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