|
|
#include "tones.h"
//////////////////////////////////////////////////////////////////////////////
//
// Helper function used to read a wave file's data into an in-memory buffer.
//
HRESULT ReadWaveFile(char * szFileName, DWORD dwFileSize, BYTE * pbData) { const int WAVE_HEADER_SIZE = 44; FILE * fp; size_t result;
//
// Check arguments.
//
// Assumption: we are reading at least WAVE_HEADER_SIZE bytes from the file.
// Note: this is data in addition to the header.
//
// _ASSERTE( ! IsBadWritePtr( pbData, dwFileSize ) );
// _ASSERTE( ! IsBadStringPtr( szFileName, (UINT) -1 ) );
if ( dwFileSize < WAVE_HEADER_SIZE ) { return E_INVALIDARG; }
//
// Open the file for reading.
//
fp = fopen(szFileName, "rb");
if ( fp == NULL ) { return E_FAIL; }
//
// Skip the wave header.
//
result = fread(pbData, sizeof(BYTE), WAVE_HEADER_SIZE, fp);
if ( result != WAVE_HEADER_SIZE ) { fclose(fp);
return E_FAIL; }
//
// Read the waveform from the file and close the file.
//
result = fread(pbData, sizeof(BYTE), dwFileSize, fp);
fclose(fp);
if ( result != dwFileSize ) { return E_FAIL; }
return S_OK; }
//////////////////////////////////////////////////////////////////////////////
//
CTonePlayer::CTonePlayer() { m_hWaveOut = NULL; m_fInitialized = FALSE; m_fDialtonePlaying = FALSE; }
//////////////////////////////////////////////////////////////////////////////
//
CTonePlayer::~CTonePlayer() { //
// We should have closed the wave device by now.
//
if ( m_fInitialized == TRUE ) { ASSERT( m_hWaveOut == NULL ); } }
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CTonePlayer::Initialize(void) { int i;
//
// It's wasteful to initialize twice, but it won't break anything.
//
ASSERT( m_fInitialized == FALSE );
//
// Read all the files.
//
HRESULT hr = ReadWaveFile( "dialtone.wav", WAVE_FILE_SIZE, (BYTE * ) & m_abDialtoneWaveform );
if ( FAILED(hr) ) { return hr; }
//
// For each digit
//
for ( i = 0; i < NUM_DIGITS; i ++ ) { //
// Construct the filename for this digit.
//
char szFilename[20];
if ( i < 10 ) { sprintf(szFilename,"dtmf%d.wav", i); } else if ( i == 10 ) { sprintf(szFilename,"dtmfstar.wav", i); } else if ( i == 11 ) { sprintf(szFilename,"dtmfpound.wav", i); } else { ASSERT( FALSE ); }
//
// Read the wave file for this digit.
//
HRESULT hr = ReadWaveFile( szFilename, WAVE_FILE_SIZE, (BYTE * ) ( & m_abDigitWaveforms ) + ( i * WAVE_FILE_SIZE ) );
if ( FAILED(hr) ) { return hr; } }
//
// We can now go ahead with the other methods.
//
m_fInitialized = TRUE;
return S_OK; }
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CTonePlayer::StartDialtone( void ) { MMRESULT mmresult;
if ( m_fInitialized == FALSE ) { ASSERT( FALSE ); return E_UNEXPECTED; }
if ( m_hWaveOut == NULL ) { ASSERT( FALSE ); return E_UNEXPECTED; }
//
// Reset the wave device to flush out any pending buffers.
//
waveOutReset( m_hWaveOut );
//
// Construct a wave header structure that will indicate what to play
// in waveOutWrite, and read in the data from the file. This can also
// be done ahead of time.
//
ZeroMemory( & m_WaveHeader, sizeof( m_WaveHeader ) );
m_WaveHeader.lpData = (LPSTR) & m_abDialtoneWaveform; m_WaveHeader.dwBufferLength = WAVE_FILE_SIZE; m_WaveHeader.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP; m_WaveHeader.dwLoops = (DWORD) -1;
//
// Submit the data to the wave device. The wave header indicated that
// we want to loop. Need to prepare the header first, but it can
// only be prepared after the device has been opened.
//
mmresult = waveOutPrepareHeader(m_hWaveOut, & m_WaveHeader, sizeof(WAVEHDR) );
if ( mmresult != MMSYSERR_NOERROR ) { return E_FAIL; }
mmresult = waveOutWrite(m_hWaveOut, & m_WaveHeader, sizeof(WAVEHDR) );
if ( mmresult != MMSYSERR_NOERROR ) { return E_FAIL; }
m_fDialtonePlaying = TRUE;
return S_OK; }
//////////////////////////////////////////////////////////////////////////////
//
// Reset the device to stop playing.
//
HRESULT CTonePlayer::StopDialtone( void ) { if ( m_fInitialized == FALSE ) { ASSERT( FALSE ); return E_UNEXPECTED; }
if ( m_hWaveOut == NULL ) { ASSERT( FALSE ); return E_UNEXPECTED; }
waveOutReset( m_hWaveOut );
m_fDialtonePlaying = FALSE;
return S_OK; }
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CTonePlayer::GenerateDTMF( long lDigit ) { MMRESULT mmresult;
if ( lDigit < 0 ) { ASSERT( FALSE ); return E_UNEXPECTED; }
if ( lDigit > NUM_DIGITS ) { ASSERT( FALSE ); return E_UNEXPECTED; }
if ( m_fInitialized == FALSE ) { ASSERT( FALSE ); return E_UNEXPECTED; }
if ( m_hWaveOut == NULL ) { ASSERT( FALSE ); return E_UNEXPECTED; } //
// Reset the wave device to flush out any pending buffers.
//
waveOutReset( m_hWaveOut );
m_fDialtonePlaying = FALSE;
//
// Construct a wave header structure that will indicate what to play
// in waveOutWrite, and read in the data from the file. This can also
// be done ahead of time.
//
ZeroMemory( & m_WaveHeader, sizeof( m_WaveHeader ) );
m_WaveHeader.lpData = (LPSTR) & m_abDigitWaveforms + lDigit * WAVE_FILE_SIZE; m_WaveHeader.dwBufferLength = WAVE_FILE_SIZE; m_WaveHeader.dwFlags = 0; m_WaveHeader.dwLoops = (DWORD) 0;
//
// Submit the data to the wave device. The wave header indicated that
// we want to loop. Need to prepare the header first, but it can
// only be prepared after the device has been opened.
//
mmresult = waveOutPrepareHeader(m_hWaveOut, & m_WaveHeader, sizeof(WAVEHDR) );
if ( mmresult != MMSYSERR_NOERROR ) { return E_FAIL; }
mmresult = waveOutWrite(m_hWaveOut, & m_WaveHeader, sizeof(WAVEHDR) );
if ( mmresult != MMSYSERR_NOERROR ) { return E_FAIL; }
return S_OK; }
//////////////////////////////////////////////////////////////////////////////
//
HRESULT CTonePlayer::OpenWaveDevice( long lWaveID ) { MMRESULT mmresult;
if ( m_fInitialized == FALSE ) { ASSERT( FALSE ); return E_UNEXPECTED; }
//
// We expect that the wave device will not be opened twice. This is
// dependent on the calling code.
//
ASSERT( m_hWaveOut == NULL );
//
// Open the wave device. Here we specify a hard-coded audio format.
//
WAVEFORMATEX waveFormat;
waveFormat.wFormatTag = WAVE_FORMAT_PCM; // linear PCM
waveFormat.nChannels = 1; // mono
waveFormat.nSamplesPerSec = 8000; // 8 KHz
waveFormat.wBitsPerSample = 16; // 16-bit samples
waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8; waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; waveFormat.cbSize = 0; // no extra format info
mmresult = waveOutOpen(& m_hWaveOut, // returned handle
lWaveID, // which device to use
&waveFormat, // wave format to use
0, // callback function pointer
0, // callback instance data
WAVE_FORMAT_DIRECT // we don't want ACM
);
if ( mmresult != MMSYSERR_NOERROR ) { return E_FAIL; }
return S_OK; }
//////////////////////////////////////////////////////////////////////////////
//
void CTonePlayer::CloseWaveDevice(void) { if ( m_fInitialized == FALSE ) { ASSERT( FALSE ); }
ASSERT( m_hWaveOut != NULL );
if ( m_hWaveOut != NULL ) { waveOutClose( m_hWaveOut );
m_hWaveOut = NULL; } }
|