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: */