| /* Copyright (c) 2002, John Edwards |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions |
| are met: |
| |
| - Redistributions of source code must retain the above copyright |
| notice, this list of conditions and the following disclaimer. |
| |
| - Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions and the following disclaimer in the |
| documentation and/or other materials provided with the distribution. |
| |
| - Neither the name of the Xiph.org Foundation nor the names of its |
| contributors may be used to endorse or promote products derived from |
| this software without specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR |
| CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| # include "config.h" |
| #endif |
| |
| /* Set TABS = 4 */ |
| /******************************************************************** |
| |
| function: To provide playback of 16 bit PCM wave data in Win32 |
| environments from decoded compressed files. |
| |
| ********************************************************************/ |
| |
| #if defined WIN32 || defined _WIN32 |
| |
| #include <string.h> |
| #include <errno.h> |
| #include "wave_out.h" |
| |
| #define MAXWAVESIZE 4294967040LU |
| #define MAX_WAVEBLOCKS 32 |
| |
| // This is modified for USE_WIN_AUDIO - ONLY 2002-02-27 |
| |
| |
| static CRITICAL_SECTION cs; |
| static HWAVEOUT dev = NULL; |
| static unsigned ScheduledBlocks = 0; |
| static int PlayedWaveHeadersCount = 0; // free index |
| static WAVEHDR* PlayedWaveHeaders [MAX_WAVEBLOCKS]; |
| |
| static int |
| Box ( const char* msg ) |
| { |
| MessageBox ( NULL, msg, " "PACKAGE_NAME" "PACKAGE_VERSION": Error Message . . .", MB_OK | MB_ICONEXCLAMATION ); |
| return -1; |
| } |
| |
| |
| /* |
| * This function registers already played WAVE chunks. Freeing is done by free_memory(), |
| */ |
| |
| static void CALLBACK |
| wave_callback ( HWAVE hWave, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 ) |
| { |
| (void) hWave; |
| (void) dwInstance; |
| (void) dwParam2; |
| if ( uMsg == WOM_DONE ) { |
| EnterCriticalSection ( &cs ); |
| PlayedWaveHeaders [PlayedWaveHeadersCount++] = (WAVEHDR*) dwParam1; |
| LeaveCriticalSection ( &cs ); |
| } |
| } |
| |
| |
| static void |
| free_memory ( void ) |
| { |
| WAVEHDR* wh; |
| HGLOBAL hg; |
| |
| EnterCriticalSection ( &cs ); |
| wh = PlayedWaveHeaders [--PlayedWaveHeadersCount]; |
| ScheduledBlocks--; // decrease the number of USED blocks |
| LeaveCriticalSection ( &cs ); |
| |
| waveOutUnprepareHeader ( dev, wh, sizeof (WAVEHDR) ); |
| |
| hg = GlobalHandle ( wh -> lpData ); // Deallocate the buffer memory |
| GlobalUnlock (hg); |
| GlobalFree (hg); |
| |
| hg = GlobalHandle ( wh ); // Deallocate the header memory |
| GlobalUnlock (hg); |
| GlobalFree (hg); |
| } |
| |
| |
| Int |
| Set_WIN_Params ( FILE_T dummyFile , |
| Ldouble SampleFreq, |
| Uint BitsPerSample, |
| Uint Channels ) |
| { |
| WAVEFORMATEX outFormat; |
| UINT deviceID = WAVE_MAPPER; |
| |
| (void) dummyFile; |
| |
| if ( waveOutGetNumDevs () == 0 ) |
| return Box ( "No audio device present." ); |
| |
| outFormat.wFormatTag = WAVE_FORMAT_PCM; |
| outFormat.wBitsPerSample = BitsPerSample; |
| outFormat.nChannels = Channels; |
| outFormat.nSamplesPerSec = (unsigned long)(SampleFreq + 0.5); |
| outFormat.nBlockAlign = (outFormat.wBitsPerSample + 7) / 8 * outFormat.nChannels; |
| outFormat.nAvgBytesPerSec = outFormat.nSamplesPerSec * outFormat.nBlockAlign; |
| |
| switch ( waveOutOpen ( &dev, deviceID, &outFormat, (DWORD_PTR)wave_callback, 0, CALLBACK_FUNCTION ) ) |
| { |
| case MMSYSERR_ALLOCATED: return Box ( "Device is already open." ); |
| case MMSYSERR_BADDEVICEID: return Box ( "The specified device is out of range." ); |
| case MMSYSERR_NODRIVER: return Box ( "There is no audio driver in this system." ); |
| case MMSYSERR_NOMEM: return Box ( "Unable to allocate sound memory." ); |
| case WAVERR_BADFORMAT: return Box ( "This audio format is not supported." ); |
| case WAVERR_SYNC: return Box ( "The device is synchronous." ); |
| default: return Box ( "Unknown media error." ); |
| case MMSYSERR_NOERROR: break; |
| } |
| |
| waveOutReset ( dev ); |
| InitializeCriticalSection ( &cs ); |
| SetPriorityClass ( GetCurrentProcess (), HIGH_PRIORITY_CLASS ); |
| return 0; |
| } |
| |
| |
| int |
| WIN_Play_Samples ( const void* data, size_t len ) |
| { |
| HGLOBAL hg; |
| HGLOBAL hg2; |
| LPWAVEHDR wh; |
| void* allocptr; |
| |
| do { |
| while ( PlayedWaveHeadersCount > 0 ) // free used blocks ... |
| free_memory (); |
| |
| if ( ScheduledBlocks < sizeof(PlayedWaveHeaders)/sizeof(*PlayedWaveHeaders) ) // wait for a free block ... |
| break; |
| Sleep (26); |
| } while (1); |
| |
| if ( (hg2 = GlobalAlloc ( GMEM_MOVEABLE, len )) == NULL ) // allocate some memory for a copy of the buffer |
| return Box ( "GlobalAlloc failed." ); |
| |
| allocptr = GlobalLock (hg2); |
| CopyMemory ( allocptr, data, len ); // Here we can call any modification output functions we want.... |
| |
| if ( (hg = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (WAVEHDR))) == NULL ) // now make a header and WRITE IT! |
| return -1; |
| |
| wh = GlobalLock (hg); |
| wh -> dwBufferLength = len; |
| wh -> lpData = allocptr; |
| |
| if ( waveOutPrepareHeader ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) { |
| GlobalUnlock (hg); |
| GlobalFree (hg); |
| return -1; |
| } |
| |
| if ( waveOutWrite ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) { |
| GlobalUnlock (hg); |
| GlobalFree (hg); |
| return -1; |
| } |
| |
| EnterCriticalSection ( &cs ); |
| ScheduledBlocks++; |
| LeaveCriticalSection ( &cs ); |
| |
| return len; |
| } |
| |
| |
| int |
| WIN_Audio_close ( void ) |
| { |
| if ( dev != NULL ) { |
| |
| while ( ScheduledBlocks > 0 ) { |
| Sleep (ScheduledBlocks); |
| while ( PlayedWaveHeadersCount > 0 ) // free used blocks ... |
| free_memory (); |
| } |
| |
| waveOutReset (dev); // reset the device |
| waveOutClose (dev); // close the device |
| dev = NULL; |
| } |
| |
| DeleteCriticalSection ( &cs ); |
| ScheduledBlocks = 0; |
| return 0; |
| } |
| |
| #endif |
| |
| /* end of wave_out.c */ |