#include #include #include #include #include "mpg123.h" #include static CRITICAL_SECTION cs; static HWAVEOUT dev = NULL; static int nBlocks = 0; #define MAX_BLOCKS 6 static int fi = -1; /* free index */ WAVEHDR *wh[MAX_BLOCKS + 1]; static _inline void wait(void) { while(nBlocks) Sleep(77); } static void CALLBACK wave_callback(HWAVE hWave, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { if(uMsg == WOM_DONE) { EnterCriticalSection( &cs ); wh[++fi] = (WAVEHDR *)dwParam1; // decrease the number of USED blocks nBlocks--; LeaveCriticalSection( &cs ); } } void free_res(void) { WAVEHDR *whfi; HGLOBAL hg; EnterCriticalSection( &cs ); whfi = wh[fi--]; LeaveCriticalSection( &cs ); waveOutUnprepareHeader(dev, whfi, sizeof (WAVEHDR)); //Deallocate the buffer memory hg = GlobalHandle(whfi->lpData); GlobalUnlock(hg); GlobalFree(hg); //Deallocate the header memory hg = GlobalHandle(whfi); GlobalUnlock(hg); GlobalFree(hg); } int audio_open(struct audio_info_struct *ai) { MMRESULT res; WAVEFORMATEX outFormatex; if(ai->rate == -1) { InitializeCriticalSection(&cs); return(0); } if(!waveOutGetNumDevs()) { MessageBox(NULL, "No audio devices present!", "Error...", MB_OK); return -1; } outFormatex.wFormatTag = WAVE_FORMAT_PCM; outFormatex.wBitsPerSample = 16; outFormatex.nChannels = 2; outFormatex.nSamplesPerSec = ai->rate; outFormatex.nAvgBytesPerSec = outFormatex.nSamplesPerSec * outFormatex.nChannels * outFormatex.wBitsPerSample/8; outFormatex.nBlockAlign = outFormatex.nChannels * outFormatex.wBitsPerSample/8; res = waveOutOpen(&dev, (UINT)ai->device, &outFormatex, (DWORD)wave_callback, 0, CALLBACK_FUNCTION); if(res != MMSYSERR_NOERROR) { switch(res) { case MMSYSERR_ALLOCATED: MessageBox(NULL, "Device Is Already Open", "Error...", MB_OK); break; case MMSYSERR_BADDEVICEID: MessageBox(NULL, "The Specified Device Is out of range", "Error...", MB_OK); break; case MMSYSERR_NODRIVER: MessageBox(NULL, "There is no audio driver in this system.", "Error...", MB_OK); break; case MMSYSERR_NOMEM: MessageBox(NULL, "Unable to allocate sound memory.", "Error...", MB_OK); break; case WAVERR_BADFORMAT: MessageBox(NULL, "This audio format is not supported.", "Error...", MB_OK); break; case WAVERR_SYNC: MessageBox(NULL, "The device is synchronous.", "Error...", MB_OK); break; default: MessageBox(NULL, "Unknown Media Error", "Error...", MB_OK); break; } return -1; } waveOutReset(dev); InitializeCriticalSection(&cs); return 0; } int audio_reset_parameters(struct audio_info_struct *ai) { return 0; } int audio_rate_best_match(struct audio_info_struct *ai) { return 0; } int audio_set_rate(struct audio_info_struct *ai) { return 0; } int audio_set_channels(struct audio_info_struct *ai) { return 0; } int audio_set_format(struct audio_info_struct *ai) { return 0; } int audio_get_formats(struct audio_info_struct *ai) { return AUDIO_FORMAT_SIGNED_16; } int audio_play_samples(struct audio_info_struct *ai,unsigned char *buf,int len) { HGLOBAL hg, hg2; LPWAVEHDR wh; MMRESULT res; void *b; /* first, free used blocks */ while (fi >= 0) { free_res(); } /////////////////////////////////////////////////////// // Wait for a few FREE blocks... /////////////////////////////////////////////////////// while(nBlocks > MAX_BLOCKS) Sleep(77); //////////////////////////////////////////////////////// // FIRST allocate some memory for a copy of the buffer! //////////////////////////////////////////////////////// hg2 = GlobalAlloc(GMEM_MOVEABLE, len); if(!hg2) { MessageBox(NULL, "GlobalAlloc failed!", "Error...", MB_OK); return(-1); } b = GlobalLock(hg2); ////////////////////////////////////////////////////////// // Here we can call any modification output functions we want.... /////////////////////////////////////////////////////////// CopyMemory(b, buf, len); /////////////////////////////////////////////////////////// // now make a header and WRITE IT! /////////////////////////////////////////////////////////// hg = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (WAVEHDR)); if(!hg) { return -1; } wh = GlobalLock(hg); wh->dwBufferLength = len; wh->lpData = b; res = waveOutPrepareHeader(dev, wh, sizeof (WAVEHDR)); if(res) { GlobalUnlock(hg); GlobalFree(hg); return -1; } res = waveOutWrite(dev, wh, sizeof (WAVEHDR)); if(res) { GlobalUnlock(hg); GlobalFree(hg); return (-1); } EnterCriticalSection( &cs ); nBlocks++; LeaveCriticalSection( &cs ); return(len); } int audio_close(struct audio_info_struct *ai) { if(dev) { wait(); waveOutReset(dev); //reset the device waveOutClose(dev); //close the device dev=NULL; } DeleteCriticalSection(&cs); nBlocks = 0; return(0); }