blob: 64eeb6e963d4a60bb0e35043f51d69a1683f2002 [file] [log] [blame]
Jean-Marc Valine6233122008-02-01 16:27:38 +11001/* 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
55static CRITICAL_SECTION cs;
56static HWAVEOUT dev = NULL;
57static int ScheduledBlocks = 0;
58static int PlayedWaveHeadersCount = 0; // free index
59static WAVEHDR* PlayedWaveHeaders [MAX_WAVEBLOCKS];
60
61static int
62Box ( 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
73static void CALLBACK
74wave_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
84static void
85free_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
107Int
108Set_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
147int
148WIN_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
197int
198WIN_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 */