Jean-Marc Valin | e623312 | 2008-02-01 16:27:38 +1100 | [diff] [blame] | 1 | /* Copyright (c) 2002, John Edwards
|
| 2 |
|
| 3 | Redistribution and use in source and binary forms, with or without
|
| 4 | modification, are permitted provided that the following conditions
|
| 5 | are met:
|
| 6 |
|
| 7 | - Redistributions of source code must retain the above copyright
|
| 8 | notice, this list of conditions and the following disclaimer.
|
| 9 |
|
| 10 | - Redistributions in binary form must reproduce the above copyright
|
| 11 | notice, this list of conditions and the following disclaimer in the
|
| 12 | documentation and/or other materials provided with the distribution.
|
| 13 |
|
| 14 | - Neither the name of the Xiph.org Foundation nor the names of its
|
| 15 | contributors may be used to endorse or promote products derived from
|
| 16 | this software without specific prior written permission.
|
| 17 |
|
| 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| 19 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
| 22 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
| 23 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
| 24 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
| 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
| 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
| 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
| 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 29 | */
|
| 30 |
|
| 31 | #ifdef HAVE_CONFIG_H
|
| 32 | # include "config.h"
|
| 33 | #endif
|
| 34 |
|
| 35 | /* Set TABS = 4 */
|
| 36 | /********************************************************************
|
| 37 |
|
| 38 | function: To provide playback of 16 bit PCM wave data in Win32
|
| 39 | environments from decoded compressed files.
|
| 40 |
|
| 41 | ********************************************************************/
|
| 42 |
|
| 43 | #if defined WIN32 || defined _WIN32
|
| 44 |
|
| 45 | #include <string.h>
|
| 46 | #include <errno.h>
|
| 47 | #include "wave_out.h"
|
| 48 |
|
| 49 | #define MAXWAVESIZE 4294967040LU
|
| 50 | #define MAX_WAVEBLOCKS 32
|
| 51 |
|
| 52 | // This is modified for USE_WIN_AUDIO - ONLY 2002-02-27
|
| 53 |
|
| 54 |
|
| 55 | static CRITICAL_SECTION cs;
|
| 56 | static HWAVEOUT dev = NULL;
|
| 57 | static int ScheduledBlocks = 0;
|
| 58 | static int PlayedWaveHeadersCount = 0; // free index
|
| 59 | static WAVEHDR* PlayedWaveHeaders [MAX_WAVEBLOCKS];
|
| 60 |
|
| 61 | static int
|
| 62 | Box ( const char* msg )
|
| 63 | {
|
| 64 | MessageBox ( NULL, msg, " "VERSION_STRING": Error Message . . .", MB_OK | MB_ICONEXCLAMATION );
|
| 65 | return -1;
|
| 66 | }
|
| 67 |
|
| 68 |
|
| 69 | /*
|
| 70 | * This function registers already played WAVE chunks. Freeing is done by free_memory(),
|
| 71 | */
|
| 72 |
|
| 73 | static void CALLBACK
|
| 74 | wave_callback ( HWAVE hWave, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
|
| 75 | {
|
| 76 | if ( uMsg == WOM_DONE ) {
|
| 77 | EnterCriticalSection ( &cs );
|
| 78 | PlayedWaveHeaders [PlayedWaveHeadersCount++] = (WAVEHDR*) dwParam1;
|
| 79 | LeaveCriticalSection ( &cs );
|
| 80 | }
|
| 81 | }
|
| 82 |
|
| 83 |
|
| 84 | static void
|
| 85 | free_memory ( void )
|
| 86 | {
|
| 87 | WAVEHDR* wh;
|
| 88 | HGLOBAL hg;
|
| 89 |
|
| 90 | EnterCriticalSection ( &cs );
|
| 91 | wh = PlayedWaveHeaders [--PlayedWaveHeadersCount];
|
| 92 | ScheduledBlocks--; // decrease the number of USED blocks
|
| 93 | LeaveCriticalSection ( &cs );
|
| 94 |
|
| 95 | waveOutUnprepareHeader ( dev, wh, sizeof (WAVEHDR) );
|
| 96 |
|
| 97 | hg = GlobalHandle ( wh -> lpData ); // Deallocate the buffer memory
|
| 98 | GlobalUnlock (hg);
|
| 99 | GlobalFree (hg);
|
| 100 |
|
| 101 | hg = GlobalHandle ( wh ); // Deallocate the header memory
|
| 102 | GlobalUnlock (hg);
|
| 103 | GlobalFree (hg);
|
| 104 | }
|
| 105 |
|
| 106 |
|
| 107 | Int
|
| 108 | Set_WIN_Params ( FILE_T dummyFile ,
|
| 109 | Ldouble SampleFreq,
|
| 110 | Uint BitsPerSample,
|
| 111 | Uint Channels )
|
| 112 | {
|
| 113 | WAVEFORMATEX outFormat;
|
| 114 | UINT deviceID = WAVE_MAPPER;
|
| 115 |
|
| 116 | (void) dummyFile;
|
| 117 |
|
| 118 | if ( waveOutGetNumDevs () == 0 )
|
| 119 | return Box ( "No audio device present." );
|
| 120 |
|
| 121 | outFormat.wFormatTag = WAVE_FORMAT_PCM;
|
| 122 | outFormat.wBitsPerSample = BitsPerSample;
|
| 123 | outFormat.nChannels = Channels;
|
| 124 | outFormat.nSamplesPerSec = (unsigned long)(SampleFreq + 0.5);
|
| 125 | outFormat.nBlockAlign = (outFormat.wBitsPerSample + 7) / 8 * outFormat.nChannels;
|
| 126 | outFormat.nAvgBytesPerSec = outFormat.nSamplesPerSec * outFormat.nBlockAlign;
|
| 127 |
|
| 128 | switch ( waveOutOpen ( &dev, deviceID, &outFormat, (DWORD)wave_callback, 0, CALLBACK_FUNCTION ) )
|
| 129 | {
|
| 130 | case MMSYSERR_ALLOCATED: return Box ( "Device is already open." );
|
| 131 | case MMSYSERR_BADDEVICEID: return Box ( "The specified device is out of range." );
|
| 132 | case MMSYSERR_NODRIVER: return Box ( "There is no audio driver in this system." );
|
| 133 | case MMSYSERR_NOMEM: return Box ( "Unable to allocate sound memory." );
|
| 134 | case WAVERR_BADFORMAT: return Box ( "This audio format is not supported." );
|
| 135 | case WAVERR_SYNC: return Box ( "The device is synchronous." );
|
| 136 | default: return Box ( "Unknown media error." );
|
| 137 | case MMSYSERR_NOERROR: break;
|
| 138 | }
|
| 139 |
|
| 140 | waveOutReset ( dev );
|
| 141 | InitializeCriticalSection ( &cs );
|
| 142 | SetPriorityClass ( GetCurrentProcess (), HIGH_PRIORITY_CLASS );
|
| 143 | return 0;
|
| 144 | }
|
| 145 |
|
| 146 |
|
| 147 | int
|
| 148 | WIN_Play_Samples ( const void* data, size_t len )
|
| 149 | {
|
| 150 | HGLOBAL hg;
|
| 151 | HGLOBAL hg2;
|
| 152 | LPWAVEHDR wh;
|
| 153 | void* allocptr;
|
| 154 |
|
| 155 | do {
|
| 156 | while ( PlayedWaveHeadersCount > 0 ) // free used blocks ...
|
| 157 | free_memory ();
|
| 158 |
|
| 159 | if ( ScheduledBlocks < sizeof(PlayedWaveHeaders)/sizeof(*PlayedWaveHeaders) ) // wait for a free block ...
|
| 160 | break;
|
| 161 | Sleep (26);
|
| 162 | } while (1);
|
| 163 |
|
| 164 | if ( (hg2 = GlobalAlloc ( GMEM_MOVEABLE, len )) == NULL ) // allocate some memory for a copy of the buffer
|
| 165 | return Box ( "GlobalAlloc failed." );
|
| 166 |
|
| 167 | allocptr = GlobalLock (hg2);
|
| 168 | CopyMemory ( allocptr, data, len ); // Here we can call any modification output functions we want....
|
| 169 |
|
| 170 | if ( (hg = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (WAVEHDR))) == NULL ) // now make a header and WRITE IT!
|
| 171 | return -1;
|
| 172 |
|
| 173 | wh = GlobalLock (hg);
|
| 174 | wh -> dwBufferLength = len;
|
| 175 | wh -> lpData = allocptr;
|
| 176 |
|
| 177 | if ( waveOutPrepareHeader ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) {
|
| 178 | GlobalUnlock (hg);
|
| 179 | GlobalFree (hg);
|
| 180 | return -1;
|
| 181 | }
|
| 182 |
|
| 183 | if ( waveOutWrite ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) {
|
| 184 | GlobalUnlock (hg);
|
| 185 | GlobalFree (hg);
|
| 186 | return -1;
|
| 187 | }
|
| 188 |
|
| 189 | EnterCriticalSection ( &cs );
|
| 190 | ScheduledBlocks++;
|
| 191 | LeaveCriticalSection ( &cs );
|
| 192 |
|
| 193 | return len;
|
| 194 | }
|
| 195 |
|
| 196 |
|
| 197 | int
|
| 198 | WIN_Audio_close ( void )
|
| 199 | {
|
| 200 | if ( dev != NULL ) {
|
| 201 |
|
| 202 | while ( ScheduledBlocks > 0 ) {
|
| 203 | Sleep (ScheduledBlocks);
|
| 204 | while ( PlayedWaveHeadersCount > 0 ) // free used blocks ...
|
| 205 | free_memory ();
|
| 206 | }
|
| 207 |
|
| 208 | waveOutReset (dev); // reset the device
|
| 209 | waveOutClose (dev); // close the device
|
| 210 | dev = NULL;
|
| 211 | }
|
| 212 |
|
| 213 | DeleteCriticalSection ( &cs );
|
| 214 | ScheduledBlocks = 0;
|
| 215 | return 0;
|
| 216 | }
|
| 217 |
|
| 218 | #endif
|
| 219 |
|
| 220 | /* end of wave_out.c */
|