#include #include #include #include "mmc_buffers.h" #include "mmc_cmdlin.h" #include "mmc_memory.h" #include "mmc_wave_format.h" #include "mmc_wave_file.h" #include "mmc_wave.h" #define BUFFER_PAD 4 #define DEFAULT_NCHANNELS 1 #define DEFAULT_ENCODING WAVE_FORMAT_MULAW #define DEFAULT_SAMPLESIZE 8 #define DEFAULT_SAMPLERATE 8000 #define DIV_ROUND_UP_(n,d) ((n + d - 1) / d) #define ROUND_UP_(n,d) (DIV_ROUND_UP_(n,d) * d) enum mmov_state { MMOV_START, MMOV_PLAY, MMOV_WAITING, MMOV_CLOSE }; #define NUM_DATA 32 struct mmov_soundformat { WAVEFORMATEX wave; char extra_data[ NUM_DATA ]; }; static int Verbose; static mmcWaveFileState_t wavefilestatus = mmcWaveFileStateInitialValue; static mmcBufferList_t mmov_buffer = mmcBufferListInitialValue; static enum mmov_state play_state; static void mmov_cleanup( ) { if (mmov_buffer.b) { mmcBuffersFree (&mmov_buffer); } mmcFreeAll (); { mmcWaveInFileClose (&wavefilestatus); } return; } static void mmov_driver (HANDLE hWaveOut, UINT wMsg, DWORD dwInstance, LPARAM lParam1, LPARAM lParam2) { switch (wMsg) { case WOM_OPEN: play_state = MMOV_PLAY; break; case WOM_CLOSE: play_state = MMOV_CLOSE; break; case WOM_DONE: { int buffer_index = mmcWaveOutGotData (&mmov_buffer, lParam1); mmcBuffer_p bp = &mmov_buffer.b[buffer_index]; mmcBufferSetStatus (&mmov_buffer, buffer_index, Empty, mmov_buffer.nbytes); } break; default: mmcVerboseDisplay(Verbose, "Unknown index %d", wMsg); break; } } void play_sound_mmov( char* FileName , int verbose ) { HWAVEOUT hwaveout; MMRESULT status; int mask1; int allDone; static int uDeviceId = WAVE_MAPPER; static int AdpcmBitsPerSample = 16; static int AdpcmSamplesPerBlock = 0; static int sizeBuffers = 0; static int msBuffers = 0; static int numBuffers = 4; static struct mmov_soundformat sound_format = { { DEFAULT_ENCODING, DEFAULT_NCHANNELS, DEFAULT_SAMPLERATE, 0, 0, DEFAULT_SAMPLESIZE, NUM_DATA }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; Verbose = verbose; play_state = MMOV_START; /* Open the Wave In file */ if (mmcWaveInFileOpen (FileName, &sound_format.wave, &wavefilestatus) != 0) { mmcVerboseDisplay(Verbose,"Error opening input file"); mmov_cleanup(); return; } if ( sound_format.wave.wFormatTag == WAVE_FORMAT_PCM) mmcVerboseDisplay(Verbose,"PCM file"); else if ( sound_format.wave.wFormatTag == WAVE_FORMAT_MULAW) mmcVerboseDisplay(Verbose,"mu-law file"); else if ( sound_format.wave.wFormatTag == WAVE_FORMAT_IMA_ADPCM) mmcVerboseDisplay(Verbose,"IMA file"); else mmcVerboseDisplay(Verbose,"Unknown sound format %d", sound_format.wave.wFormatTag); mmcVerboseDisplay(Verbose,"Channels = %d ", sound_format.wave.nChannels ); mmcVerboseDisplay(Verbose,"Sample rate = %d", sound_format.wave.nSamplesPerSec); mmcVerboseDisplay(Verbose, "Sample size = %d", sound_format.wave.wBitsPerSample ); if( sound_format.wave.nChannels == 0) sound_format.wave.nChannels = DEFAULT_NCHANNELS; if( sound_format.wave.nSamplesPerSec == 0) sound_format.wave.nSamplesPerSec = DEFAULT_SAMPLERATE; if( sound_format.wave.wBitsPerSample == 0) sound_format.wave.wBitsPerSample = DEFAULT_SAMPLESIZE; if ( sound_format.wave.wFormatTag == WAVE_FORMAT_IMA_ADPCM ) { AdpcmSamplesPerBlock = *(Uint16 *)(&sound_format.extra_data[0]); } if ( ( sound_format.wave.wFormatTag == WAVE_FORMAT_PCM) || ( sound_format.wave.wFormatTag == WAVE_FORMAT_MULAW) ) { mask1 = WAVE_FORMAT_FIX_BLOCK_ALIGN | WAVE_FORMAT_FIX_AVG_BPS; mmcWaveFormatFix((LPPCMWAVEFORMAT)(&sound_format), mask1 ); } if ( sound_format.wave.wFormatTag == WAVE_FORMAT_IMA_ADPCM) { sizeBuffers = sound_format.wave.nBlockAlign; msBuffers = sizeBuffers * 1000 / (DIV_ROUND_UP_(AdpcmBitsPerSample,8) * sound_format.wave.nSamplesPerSec * sound_format.wave.nChannels); } else { if (!msBuffers && !sizeBuffers) msBuffers = 1000/numBuffers; if (msBuffers) sizeBuffers = ROUND_UP_(DIV_ROUND_UP_(msBuffers * DIV_ROUND_UP_( sound_format.wave.wBitsPerSample, 8) * sound_format.wave.nSamplesPerSec * sound_format.wave.nChannels,1000), BUFFER_PAD); else { sizeBuffers = ROUND_UP_(sizeBuffers, BUFFER_PAD); msBuffers = sizeBuffers * 1000 / (DIV_ROUND_UP_( sound_format.wave.wBitsPerSample,8) * sound_format.wave.nSamplesPerSec * sound_format.wave.nChannels); } } mmcVerboseDisplay(Verbose, "Buffer size = %d bytes or %d milliseconds", sizeBuffers, msBuffers); hwaveout = NULL; status = mmcWaveOutOpen(&sound_format.wave, uDeviceId, &mmov_driver , WAVE_OPEN_SHAREABLE, &hwaveout); if (status != MMSYSERR_NOERROR) { mmov_cleanup(); return; } if (mmcBuffersCreate (&mmov_buffer, numBuffers, sizeBuffers, BUFFER_PAD) != MMSYSERR_NOERROR) { mmov_cleanup(); return; } for (;;) { switch ( play_state ) { case MMOV_START: break; case MMOV_PLAY: status = mmcWaveOutQueueBufferAll (hwaveout, &mmov_buffer, Verbose, &wavefilestatus, &allDone); if (allDone) play_state = MMOV_WAITING; else { if (status != MMSYSERR_NOERROR) { mmov_cleanup(); return; } } break; case MMOV_WAITING: if ((mmcBufferFind(&mmov_buffer,Filling) != mmcBufferNone) || (mmcBufferFind(&mmov_buffer,Full) != mmcBufferNone) || (mmcBufferFind(&mmov_buffer,Playing) != mmcBufferNone)) break; play_state = MMOV_CLOSE; case MMOV_CLOSE: status = mmcWaveOutClose (hwaveout, &mmov_buffer); if (status != MMSYSERR_NOERROR) { mmov_cleanup(); return; } mmov_cleanup(); return; default: mmcVerboseDisplay(Verbose,"Unknown play_state %d", play_state); mmov_cleanup(); return; } mmeWaitForCallbacks (); /* block so we don't hog 100% of the CPU */ mmeProcessCallbacks (); } }