1 /* Copyright (c) 2002, John Edwards
\r
3 Redistribution and use in source and binary forms, with or without
\r
4 modification, are permitted provided that the following conditions
\r
7 - Redistributions of source code must retain the above copyright
\r
8 notice, this list of conditions and the following disclaimer.
\r
10 - Redistributions in binary form must reproduce the above copyright
\r
11 notice, this list of conditions and the following disclaimer in the
\r
12 documentation and/or other materials provided with the distribution.
\r
14 - Neither the name of the Xiph.org Foundation nor the names of its
\r
15 contributors may be used to endorse or promote products derived from
\r
16 this software without specific prior written permission.
\r
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
\r
19 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
\r
20 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
\r
21 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
\r
22 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
\r
23 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
\r
24 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
\r
25 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
\r
26 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
27 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
\r
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
31 #ifdef HAVE_CONFIG_H
\r
32 # include "config.h"
\r
36 /********************************************************************
\r
38 function: To provide playback of 16 bit PCM wave data in Win32
\r
39 environments from decoded compressed files.
\r
41 ********************************************************************/
\r
43 #if defined WIN32 || defined _WIN32
\r
47 #include "wave_out.h"
\r
49 #define MAXWAVESIZE 4294967040LU
\r
50 #define MAX_WAVEBLOCKS 32
\r
52 // This is modified for USE_WIN_AUDIO - ONLY 2002-02-27
\r
55 static CRITICAL_SECTION cs;
\r
56 static HWAVEOUT dev = NULL;
\r
57 static int ScheduledBlocks = 0;
\r
58 static int PlayedWaveHeadersCount = 0; // free index
\r
59 static WAVEHDR* PlayedWaveHeaders [MAX_WAVEBLOCKS];
\r
62 Box ( const char* msg )
\r
64 MessageBox ( NULL, msg, " "VERSION_STRING": Error Message . . .", MB_OK | MB_ICONEXCLAMATION );
\r
70 * This function registers already played WAVE chunks. Freeing is done by free_memory(),
\r
73 static void CALLBACK
\r
74 wave_callback ( HWAVE hWave, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
\r
76 if ( uMsg == WOM_DONE ) {
\r
77 EnterCriticalSection ( &cs );
\r
78 PlayedWaveHeaders [PlayedWaveHeadersCount++] = (WAVEHDR*) dwParam1;
\r
79 LeaveCriticalSection ( &cs );
\r
85 free_memory ( void )
\r
90 EnterCriticalSection ( &cs );
\r
91 wh = PlayedWaveHeaders [--PlayedWaveHeadersCount];
\r
92 ScheduledBlocks--; // decrease the number of USED blocks
\r
93 LeaveCriticalSection ( &cs );
\r
95 waveOutUnprepareHeader ( dev, wh, sizeof (WAVEHDR) );
\r
97 hg = GlobalHandle ( wh -> lpData ); // Deallocate the buffer memory
\r
101 hg = GlobalHandle ( wh ); // Deallocate the header memory
\r
108 Set_WIN_Params ( FILE_T dummyFile ,
\r
109 Ldouble SampleFreq,
\r
110 Uint BitsPerSample,
\r
113 WAVEFORMATEX outFormat;
\r
114 UINT deviceID = WAVE_MAPPER;
\r
118 if ( waveOutGetNumDevs () == 0 )
\r
119 return Box ( "No audio device present." );
\r
121 outFormat.wFormatTag = WAVE_FORMAT_PCM;
\r
122 outFormat.wBitsPerSample = BitsPerSample;
\r
123 outFormat.nChannels = Channels;
\r
124 outFormat.nSamplesPerSec = (unsigned long)(SampleFreq + 0.5);
\r
125 outFormat.nBlockAlign = (outFormat.wBitsPerSample + 7) / 8 * outFormat.nChannels;
\r
126 outFormat.nAvgBytesPerSec = outFormat.nSamplesPerSec * outFormat.nBlockAlign;
\r
128 switch ( waveOutOpen ( &dev, deviceID, &outFormat, (DWORD)wave_callback, 0, CALLBACK_FUNCTION ) )
\r
130 case MMSYSERR_ALLOCATED: return Box ( "Device is already open." );
\r
131 case MMSYSERR_BADDEVICEID: return Box ( "The specified device is out of range." );
\r
132 case MMSYSERR_NODRIVER: return Box ( "There is no audio driver in this system." );
\r
133 case MMSYSERR_NOMEM: return Box ( "Unable to allocate sound memory." );
\r
134 case WAVERR_BADFORMAT: return Box ( "This audio format is not supported." );
\r
135 case WAVERR_SYNC: return Box ( "The device is synchronous." );
\r
136 default: return Box ( "Unknown media error." );
\r
137 case MMSYSERR_NOERROR: break;
\r
140 waveOutReset ( dev );
\r
141 InitializeCriticalSection ( &cs );
\r
142 SetPriorityClass ( GetCurrentProcess (), HIGH_PRIORITY_CLASS );
\r
148 WIN_Play_Samples ( const void* data, size_t len )
\r
156 while ( PlayedWaveHeadersCount > 0 ) // free used blocks ...
\r
159 if ( ScheduledBlocks < sizeof(PlayedWaveHeaders)/sizeof(*PlayedWaveHeaders) ) // wait for a free block ...
\r
164 if ( (hg2 = GlobalAlloc ( GMEM_MOVEABLE, len )) == NULL ) // allocate some memory for a copy of the buffer
\r
165 return Box ( "GlobalAlloc failed." );
\r
167 allocptr = GlobalLock (hg2);
\r
168 CopyMemory ( allocptr, data, len ); // Here we can call any modification output functions we want....
\r
170 if ( (hg = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (WAVEHDR))) == NULL ) // now make a header and WRITE IT!
\r
173 wh = GlobalLock (hg);
\r
174 wh -> dwBufferLength = len;
\r
175 wh -> lpData = allocptr;
\r
177 if ( waveOutPrepareHeader ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) {
\r
183 if ( waveOutWrite ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) {
\r
189 EnterCriticalSection ( &cs );
\r
191 LeaveCriticalSection ( &cs );
\r
198 WIN_Audio_close ( void )
\r
200 if ( dev != NULL ) {
\r
202 while ( ScheduledBlocks > 0 ) {
\r
203 Sleep (ScheduledBlocks);
\r
204 while ( PlayedWaveHeadersCount > 0 ) // free used blocks ...
\r
208 waveOutReset (dev); // reset the device
\r
209 waveOutClose (dev); // close the device
\r
213 DeleteCriticalSection ( &cs );
\r
214 ScheduledBlocks = 0;
\r
220 /* end of wave_out.c */
\r