Mercurial > sdl-ios-xcode
comparison src/audio/windib/SDL_dibaudio.c @ 3841:3479f939987c SDL-ryan-multiple-audio-device
Moved windib (waveout) audio to 1.3 API and made other cleanups.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Sun, 08 Oct 2006 23:04:24 +0000 |
parents | c8b3d3d13ed1 |
children | 66fb40445587 |
comparison
equal
deleted
inserted
replaced
3840:be9bd1067c6c | 3841:3479f939987c |
---|---|
33 #include "SDL_dibaudio.h" | 33 #include "SDL_dibaudio.h" |
34 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) | 34 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) |
35 #include "win_ce_semaphore.h" | 35 #include "win_ce_semaphore.h" |
36 #endif | 36 #endif |
37 | 37 |
38 | 38 #if defined(_WIN32_WCE) |
39 /* Audio driver functions */ | 39 #define WINDOWS_OS_NAME "Windows CE/PocketPC" |
40 static int DIB_OpenAudio(_THIS, SDL_AudioSpec * spec); | 40 #elif defined(WIN64) |
41 static void DIB_ThreadInit(_THIS); | 41 #define WINDOWS_OS_NAME "Win64" |
42 static void DIB_WaitAudio(_THIS); | 42 #else |
43 static Uint8 *DIB_GetAudioBuf(_THIS); | 43 #define WINDOWS_OS_NAME "Win32" |
44 static void DIB_PlayAudio(_THIS); | 44 #endif |
45 static void DIB_WaitDone(_THIS); | |
46 static void DIB_CloseAudio(_THIS); | |
47 | |
48 /* Audio driver bootstrap functions */ | |
49 | 45 |
50 static int | 46 static int |
51 Audio_Available(void) | 47 WINWAVEOUT_Available(void) |
52 { | 48 { |
53 return (1); | 49 return 1; /* Always available on win32/pocketpc systems... */ |
54 } | 50 } |
55 | |
56 static void | |
57 Audio_DeleteDevice(SDL_AudioDevice * device) | |
58 { | |
59 SDL_free(device->hidden); | |
60 SDL_free(device); | |
61 } | |
62 | |
63 static SDL_AudioDevice * | |
64 Audio_CreateDevice(int devindex) | |
65 { | |
66 SDL_AudioDevice *this; | |
67 | |
68 /* Initialize all variables that we clean on shutdown */ | |
69 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); | |
70 if (this) { | |
71 SDL_memset(this, 0, (sizeof *this)); | |
72 this->hidden = (struct SDL_PrivateAudioData *) | |
73 SDL_malloc((sizeof *this->hidden)); | |
74 } | |
75 if ((this == NULL) || (this->hidden == NULL)) { | |
76 SDL_OutOfMemory(); | |
77 if (this) { | |
78 SDL_free(this); | |
79 } | |
80 return (0); | |
81 } | |
82 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); | |
83 | |
84 /* Set the function pointers */ | |
85 this->OpenAudio = DIB_OpenAudio; | |
86 this->ThreadInit = DIB_ThreadInit; | |
87 this->WaitAudio = DIB_WaitAudio; | |
88 this->PlayAudio = DIB_PlayAudio; | |
89 this->GetAudioBuf = DIB_GetAudioBuf; | |
90 this->WaitDone = DIB_WaitDone; | |
91 this->CloseAudio = DIB_CloseAudio; | |
92 | |
93 this->free = Audio_DeleteDevice; | |
94 | |
95 return this; | |
96 } | |
97 | |
98 AudioBootStrap WAVEOUT_bootstrap = { | |
99 "waveout", "Win95/98/NT/2000 WaveOut", | |
100 Audio_Available, Audio_CreateDevice, 0 | |
101 }; | |
102 | |
103 | 51 |
104 /* The Win32 callback for filling the WAVE device */ | 52 /* The Win32 callback for filling the WAVE device */ |
105 static void CALLBACK | 53 static void CALLBACK |
106 FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, | 54 FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, |
107 DWORD dwParam1, DWORD dwParam2) | 55 DWORD dwParam1, DWORD dwParam2) |
112 if (uMsg != WOM_DONE) | 60 if (uMsg != WOM_DONE) |
113 return; | 61 return; |
114 | 62 |
115 /* Signal that we are done playing a buffer */ | 63 /* Signal that we are done playing a buffer */ |
116 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) | 64 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) |
117 ReleaseSemaphoreCE(audio_sem, 1, NULL); | 65 ReleaseSemaphoreCE(this->hidden->audio_sem, 1, NULL); |
118 #else | 66 #else |
119 ReleaseSemaphore(audio_sem, 1, NULL); | 67 ReleaseSemaphore(this->hidden->audio_sem, 1, NULL); |
120 #endif | 68 #endif |
121 } | 69 } |
122 | 70 |
123 static void | 71 static void |
124 SetMMerror(char *function, MMRESULT code) | 72 SetMMerror(char *function, MMRESULT code) |
144 SDL_SetError("%s", errbuf); | 92 SDL_SetError("%s", errbuf); |
145 } | 93 } |
146 | 94 |
147 /* Set high priority for the audio thread */ | 95 /* Set high priority for the audio thread */ |
148 static void | 96 static void |
149 DIB_ThreadInit(_THIS) | 97 WINWAVEOUT_ThreadInit(_THIS) |
150 { | 98 { |
151 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); | 99 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); |
152 } | 100 } |
153 | 101 |
154 void | 102 void |
155 DIB_WaitAudio(_THIS) | 103 WINWAVEOUT_WaitDevice(_THIS) |
156 { | 104 { |
157 /* Wait for an audio chunk to finish */ | 105 /* Wait for an audio chunk to finish */ |
158 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) | 106 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) |
159 WaitForSemaphoreCE(audio_sem, INFINITE); | 107 WaitForSemaphoreCE(this->hidden->audio_sem, INFINITE); |
160 #else | 108 #else |
161 WaitForSingleObject(audio_sem, INFINITE); | 109 WaitForSingleObject(this->hidden->audio_sem, INFINITE); |
162 #endif | 110 #endif |
163 } | 111 } |
164 | 112 |
165 Uint8 * | 113 Uint8 * |
166 DIB_GetAudioBuf(_THIS) | 114 WINWAVEOUT_GetDeviceBuf(_THIS) |
167 { | 115 { |
168 Uint8 *retval; | 116 return (Uint8 *) (this->hidden->wavebuf[this->hidden->next_buffer].lpData); |
169 | |
170 retval = (Uint8 *) (wavebuf[next_buffer].lpData); | |
171 return retval; | |
172 } | 117 } |
173 | 118 |
174 void | 119 void |
175 DIB_PlayAudio(_THIS) | 120 WINWAVEOUT_PlayDevice(_THIS) |
176 { | 121 { |
177 /* Queue it up */ | 122 /* Queue it up */ |
178 waveOutWrite(sound, &wavebuf[next_buffer], sizeof(wavebuf[0])); | 123 waveOutWrite(this->hidden->sound, |
179 next_buffer = (next_buffer + 1) % NUM_BUFFERS; | 124 &this->hidden->wavebuf[this->hidden->next_buffer], |
125 sizeof (this->hidden->wavebuf[0])); | |
126 this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS; | |
180 } | 127 } |
181 | 128 |
182 void | 129 void |
183 DIB_WaitDone(_THIS) | 130 WINWAVEOUT_WaitDone(_THIS) |
184 { | 131 { |
185 int i, left; | 132 int i, left; |
186 | 133 |
187 do { | 134 do { |
188 left = NUM_BUFFERS; | 135 left = NUM_BUFFERS; |
189 for (i = 0; i < NUM_BUFFERS; ++i) { | 136 for (i = 0; i < NUM_BUFFERS; ++i) { |
190 if (wavebuf[i].dwFlags & WHDR_DONE) { | 137 if (this->hidden->wavebuf[i].dwFlags & WHDR_DONE) { |
191 --left; | 138 --left; |
192 } | 139 } |
193 } | 140 } |
194 if (left > 0) { | 141 if (left > 0) { |
195 SDL_Delay(100); | 142 SDL_Delay(100); |
197 } | 144 } |
198 while (left > 0); | 145 while (left > 0); |
199 } | 146 } |
200 | 147 |
201 void | 148 void |
202 DIB_CloseAudio(_THIS) | 149 WINWAVEOUT_CloseDevice(_THIS) |
203 { | 150 { |
151 /* Close up audio */ | |
152 if (this->hidden != NULL) { | |
153 int i; | |
154 | |
155 if (this->hidden->audio_sem) { | |
156 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) | |
157 CloseSynchHandle(this->hidden->audio_sem); | |
158 #else | |
159 CloseHandle(this->hidden->audio_sem); | |
160 #endif | |
161 this->hidden->audio_sem = 0; | |
162 } | |
163 | |
164 if (this->hidden->sound) { | |
165 waveOutClose(this->hidden->sound); | |
166 this->hidden->sound = 0; | |
167 } | |
168 | |
169 /* Clean up mixing buffers */ | |
170 for (i = 0; i < NUM_BUFFERS; ++i) { | |
171 if (this->hidden->wavebuf[i].dwUser != 0xFFFF) { | |
172 waveOutUnprepareHeader(this->hidden->sound, | |
173 &this->hidden->wavebuf[i], | |
174 sizeof (this->hidden->wavebuf[i])); | |
175 this->hidden->wavebuf[i].dwUser = 0xFFFF; | |
176 } | |
177 } | |
178 | |
179 if (this->hidden->mixbuf != NULL) { | |
180 /* Free raw mixing buffer */ | |
181 SDL_free(this->hidden->mixbuf); | |
182 this->hidden->mixbuf = NULL; | |
183 } | |
184 | |
185 SDL_free(this->hidden); | |
186 this->hidden = NULL; | |
187 } | |
188 } | |
189 | |
190 int | |
191 WINWAVEOUT_OpenDevice(_THIS, const char *devname, int iscapture) | |
192 { | |
193 SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); | |
194 int valid_datatype = 0; | |
195 MMRESULT result; | |
196 WAVEFORMATEX waveformat; | |
204 int i; | 197 int i; |
205 | 198 |
206 /* Close up audio */ | 199 /* Initialize all variables that we clean on shutdown */ |
207 if (audio_sem) { | 200 this->hidden = (struct SDL_PrivateAudioData *) |
208 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) | 201 SDL_malloc((sizeof *this->hidden)); |
209 CloseSynchHandle(audio_sem); | 202 if (this->hidden == NULL) { |
210 #else | 203 SDL_OutOfMemory(); |
211 CloseHandle(audio_sem); | 204 return 0; |
212 #endif | 205 } |
213 } | 206 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); |
214 if (sound) { | |
215 waveOutClose(sound); | |
216 } | |
217 | |
218 /* Clean up mixing buffers */ | |
219 for (i = 0; i < NUM_BUFFERS; ++i) { | |
220 if (wavebuf[i].dwUser != 0xFFFF) { | |
221 waveOutUnprepareHeader(sound, &wavebuf[i], sizeof(wavebuf[i])); | |
222 wavebuf[i].dwUser = 0xFFFF; | |
223 } | |
224 } | |
225 /* Free raw mixing buffer */ | |
226 if (mixbuf != NULL) { | |
227 SDL_free(mixbuf); | |
228 mixbuf = NULL; | |
229 } | |
230 } | |
231 | |
232 int | |
233 DIB_OpenAudio(_THIS, SDL_AudioSpec * spec) | |
234 { | |
235 MMRESULT result; | |
236 int i; | |
237 WAVEFORMATEX waveformat; | |
238 | 207 |
239 /* Initialize the wavebuf structures for closing */ | 208 /* Initialize the wavebuf structures for closing */ |
240 sound = NULL; | |
241 audio_sem = NULL; | |
242 for (i = 0; i < NUM_BUFFERS; ++i) | 209 for (i = 0; i < NUM_BUFFERS; ++i) |
243 wavebuf[i].dwUser = 0xFFFF; | 210 this->hidden->wavebuf[i].dwUser = 0xFFFF; |
244 mixbuf = NULL; | 211 |
212 while ((!valid_datatype) && (test_format)) { | |
213 valid_datatype = 1; | |
214 _this->spec.format = test_format; | |
215 switch (test_format) { | |
216 case AUDIO_U8: | |
217 case AUDIO_S16: | |
218 case AUDIO_S32: | |
219 break; /* valid. */ | |
220 | |
221 default: | |
222 valid_datatype = 0; | |
223 test_format = SDL_NextAudioFormat(); | |
224 break; | |
225 } | |
226 } | |
227 | |
228 if (!valid_datatype) { | |
229 WINWAVEOUT_CloseDevice(this); | |
230 SDL_SetError("Unsupported audio format"); | |
231 return 0; | |
232 } | |
245 | 233 |
246 /* Set basic WAVE format parameters */ | 234 /* Set basic WAVE format parameters */ |
247 SDL_memset(&waveformat, 0, sizeof(waveformat)); | 235 SDL_memset(&waveformat, '\0', sizeof (waveformat)); |
248 waveformat.wFormatTag = WAVE_FORMAT_PCM; | 236 waveformat.wFormatTag = WAVE_FORMAT_PCM; |
249 | 237 waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format); |
250 /* Determine the audio parameters from the AudioSpec */ | 238 |
251 switch (SDL_AUDIO_BITSIZE(spec->format)) { | 239 if (this->spec.channels > 2) |
252 case 8: | 240 this->spec.channels = 2; /* !!! FIXME: is this right? */ |
253 /* Unsigned 8 bit audio data */ | 241 |
254 spec->format = AUDIO_U8; | 242 waveformat.nChannels = this->spec.channels; |
255 waveformat.wBitsPerSample = 8; | 243 waveformat.nSamplesPerSec = this->spec.freq; |
256 break; | |
257 case 16: | |
258 /* Signed 16 bit audio data */ | |
259 spec->format = AUDIO_S16; | |
260 waveformat.wBitsPerSample = 16; | |
261 break; | |
262 case 32: | |
263 /* Signed 32 bit audio data */ | |
264 spec->format = AUDIO_S32; | |
265 waveformat.wBitsPerSample = 32; | |
266 break; | |
267 default: | |
268 SDL_SetError("Unsupported audio format"); | |
269 return (-1); | |
270 } | |
271 waveformat.nChannels = spec->channels; | |
272 waveformat.nSamplesPerSec = spec->freq; | |
273 waveformat.nBlockAlign = | 244 waveformat.nBlockAlign = |
274 waveformat.nChannels * (waveformat.wBitsPerSample / 8); | 245 waveformat.nChannels * (waveformat.wBitsPerSample / 8); |
275 waveformat.nAvgBytesPerSec = | 246 waveformat.nAvgBytesPerSec = |
276 waveformat.nSamplesPerSec * waveformat.nBlockAlign; | 247 waveformat.nSamplesPerSec * waveformat.nBlockAlign; |
277 | 248 |
278 /* Check the buffer size -- minimum of 1/4 second (word aligned) */ | 249 /* Check the buffer size -- minimum of 1/4 second (word aligned) */ |
279 if (spec->samples < (spec->freq / 4)) | 250 if (this->spec.samples < (this->spec.freq / 4)) |
280 spec->samples = ((spec->freq / 4) + 3) & ~3; | 251 this->spec.samples = ((this->spec.freq / 4) + 3) & ~3; |
281 | 252 |
282 /* Update the fragment size as size in bytes */ | 253 /* Update the fragment size as size in bytes */ |
283 SDL_CalculateAudioSpec(spec); | 254 SDL_CalculateAudioSpec(&this->spec); |
284 | 255 |
285 /* Open the audio device */ | 256 /* Open the audio device */ |
286 result = waveOutOpen(&sound, WAVE_MAPPER, &waveformat, | 257 result = waveOutOpen(&this->hidden->sound, WAVE_MAPPER, &waveformat, |
287 (DWORD_PTR) FillSound, (DWORD_PTR) this, | 258 (DWORD_PTR) FillSound, (DWORD_PTR) this, |
288 CALLBACK_FUNCTION); | 259 CALLBACK_FUNCTION); |
289 if (result != MMSYSERR_NOERROR) { | 260 if (result != MMSYSERR_NOERROR) { |
261 WINWAVEOUT_CloseDevice(this); | |
290 SetMMerror("waveOutOpen()", result); | 262 SetMMerror("waveOutOpen()", result); |
291 return (-1); | 263 return 0; |
292 } | 264 } |
293 #ifdef SOUND_DEBUG | 265 #ifdef SOUND_DEBUG |
294 /* Check the sound device we retrieved */ | 266 /* Check the sound device we retrieved */ |
295 { | 267 { |
296 WAVEOUTCAPS caps; | 268 WAVEOUTCAPS caps; |
297 | 269 |
298 result = waveOutGetDevCaps((UINT) sound, &caps, sizeof(caps)); | 270 result = waveOutGetDevCaps((UINT) this->hidden->sound, |
271 &caps, sizeof(caps)); | |
299 if (result != MMSYSERR_NOERROR) { | 272 if (result != MMSYSERR_NOERROR) { |
273 WINWAVEOUT_CloseDevice(this); | |
300 SetMMerror("waveOutGetDevCaps()", result); | 274 SetMMerror("waveOutGetDevCaps()", result); |
301 return (-1); | 275 return 0; |
302 } | 276 } |
303 printf("Audio device: %s\n", caps.szPname); | 277 printf("Audio device: %s\n", caps.szPname); |
304 } | 278 } |
305 #endif | 279 #endif |
306 | 280 |
307 /* Create the audio buffer semaphore */ | 281 /* Create the audio buffer semaphore */ |
308 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) | 282 this->hidden->audio_sem = |
309 audio_sem = CreateSemaphoreCE(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL); | 283 #if defined(_WIN32_WCE) && (_WIN32_WCE < 300) |
310 #else | 284 CreateSemaphoreCE(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL); |
311 audio_sem = CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL); | 285 #else |
312 #endif | 286 CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL); |
313 if (audio_sem == NULL) { | 287 #endif |
288 if (this->hidden->audio_sem == NULL) { | |
289 WINWAVEOUT_CloseDevice(this); | |
314 SDL_SetError("Couldn't create semaphore"); | 290 SDL_SetError("Couldn't create semaphore"); |
315 return (-1); | 291 return 0; |
316 } | 292 } |
317 | 293 |
318 /* Create the sound buffers */ | 294 /* Create the sound buffers */ |
319 mixbuf = (Uint8 *) SDL_malloc(NUM_BUFFERS * spec->size); | 295 this->hidden->mixbuf = (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size); |
320 if (mixbuf == NULL) { | 296 if (mixbuf == NULL) { |
321 SDL_SetError("Out of memory"); | 297 WINWAVEOUT_CloseDevice(this); |
322 return (-1); | 298 SDL_OutOfMemory(); |
299 return 0; | |
323 } | 300 } |
324 for (i = 0; i < NUM_BUFFERS; ++i) { | 301 for (i = 0; i < NUM_BUFFERS; ++i) { |
325 SDL_memset(&wavebuf[i], 0, sizeof(wavebuf[i])); | 302 SDL_memset(&this->hidden->wavebuf[i], '\0', |
326 wavebuf[i].lpData = (LPSTR) & mixbuf[i * spec->size]; | 303 sizeof (this->hidden->wavebuf[i])); |
327 wavebuf[i].dwBufferLength = spec->size; | 304 this->hidden->wavebuf[i].dwBufferLength = this->spec.size; |
328 wavebuf[i].dwFlags = WHDR_DONE; | 305 this->hidden->wavebuf[i].dwFlags = WHDR_DONE; |
329 result = waveOutPrepareHeader(sound, &wavebuf[i], sizeof(wavebuf[i])); | 306 this->hidden->wavebuf[i].lpData = |
307 (LPSTR) &this->hidden->mixbuf[i * this->spec.size]; | |
308 result = waveOutPrepareHeader(this->hidden->sound, | |
309 &this->hidden->wavebuf[i], | |
310 sizeof (this->hidden->wavebuf[i])); | |
330 if (result != MMSYSERR_NOERROR) { | 311 if (result != MMSYSERR_NOERROR) { |
312 WINWAVEOUT_CloseDevice(this); | |
331 SetMMerror("waveOutPrepareHeader()", result); | 313 SetMMerror("waveOutPrepareHeader()", result); |
332 return (-1); | 314 return 0; |
333 } | 315 } |
334 } | 316 } |
335 | 317 |
336 /* Ready to go! */ | 318 return 1; /* Ready to go! */ |
337 next_buffer = 0; | 319 } |
338 return (0); | 320 |
339 } | 321 |
322 static int | |
323 WINWAVEOUT_Init(SDL_AudioDriverImpl *impl) | |
324 { | |
325 /* Set the function pointers */ | |
326 impl->OpenDevice = WINWAVEOUT_OpenDevice; | |
327 impl->ThreadInit = WINWAVEOUT_ThreadInit; | |
328 impl->PlayDevice = WINWAVEOUT_PlayDevice; | |
329 impl->WaitDevice = WINWAVEOUT_WaitDevice; | |
330 impl->WaitDone = WINWAVEOUT_WaitDone; | |
331 impl->GetDeviceBuf = WINWAVEOUT_GetDeviceBuf; | |
332 impl->CloseDevice = WINWAVEOUT_CloseDevice; | |
333 impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: Is this true? */ | |
334 | |
335 return 1; | |
336 } | |
337 | |
338 AudioBootStrap WINWAVEOUT_bootstrap = { | |
339 "waveout", WINDOWS_OS_NAME " WaveOut", | |
340 WINWAVEOUT_Available, WINWAVEOUT_Init, 0 | |
341 }; | |
340 | 342 |
341 /* vi: set ts=4 sw=4 expandtab: */ | 343 /* vi: set ts=4 sw=4 expandtab: */ |