comparison src/audio/windx5/SDL_dx5audio.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 4ad1e863d100
children bbc89e09503f
comparison
equal deleted inserted replaced
2048:6067c7f9a672 2049:5f6550e5184f
26 #include "SDL_timer.h" 26 #include "SDL_timer.h"
27 #include "SDL_audio.h" 27 #include "SDL_audio.h"
28 #include "../SDL_audio_c.h" 28 #include "../SDL_audio_c.h"
29 #include "SDL_dx5audio.h" 29 #include "SDL_dx5audio.h"
30 30
31 /* Define this if you want to use DirectX 6 DirectSoundNotify interface */ 31 /* !!! FIXME: move this somewhere that other drivers can use it... */
32 //#define USE_POSITION_NOTIFY 32 #if defined(_WIN32_WCE)
33 #define WINDOWS_OS_NAME "Windows CE/PocketPC"
34 #elif defined(WIN64)
35 #define WINDOWS_OS_NAME "Win64"
36 #else
37 #define WINDOWS_OS_NAME "Win32"
38 #endif
33 39
34 /* DirectX function pointers for audio */ 40 /* DirectX function pointers for audio */
35 HRESULT(WINAPI * DSoundCreate) (LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
36
37 /* Audio driver functions */
38 static int DX5_OpenAudio(_THIS, SDL_AudioSpec * spec);
39 static void DX5_ThreadInit(_THIS);
40 static void DX5_WaitAudio_BusyWait(_THIS);
41 #ifdef USE_POSITION_NOTIFY
42 static void DX6_WaitAudio_EventWait(_THIS);
43 #endif
44 static void DX5_PlayAudio(_THIS);
45 static Uint8 *DX5_GetAudioBuf(_THIS);
46 static void DX5_WaitDone(_THIS);
47 static void DX5_CloseAudio(_THIS);
48
49 /* Audio driver bootstrap functions */
50
51 static int
52 Audio_Available(void)
53 {
54 HINSTANCE DSoundDLL;
55 int dsound_ok;
56
57 /* Version check DSOUND.DLL (Is DirectX okay?) */
58 dsound_ok = 0;
59 DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL"));
60 if (DSoundDLL != NULL) {
61 /* We just use basic DirectSound, we're okay */
62 /* Yay! */
63 /* Unfortunately, the sound drivers on NT have
64 higher latencies than the audio buffers used
65 by many SDL applications, so there are gaps
66 in the audio - it sounds terrible. Punt for now.
67 */
68 OSVERSIONINFO ver;
69 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
70 GetVersionEx(&ver);
71 switch (ver.dwPlatformId) {
72 case VER_PLATFORM_WIN32_NT:
73 if (ver.dwMajorVersion > 4) {
74 /* Win2K */
75 dsound_ok = 1;
76 } else {
77 /* WinNT */
78 dsound_ok = 0;
79 }
80 break;
81 default:
82 /* Win95 or Win98 */
83 dsound_ok = 1;
84 break;
85 }
86 /* Now check for DirectX 5 or better - otherwise
87 * we will fail later in DX5_OpenAudio without a chance
88 * to fall back to the DIB driver. */
89 if (dsound_ok) {
90 /* DirectSoundCaptureCreate was added in DX5 */
91 if (!GetProcAddress(DSoundDLL, TEXT("DirectSoundCaptureCreate")))
92 dsound_ok = 0;
93
94 }
95 /* Clean up.. */
96 FreeLibrary(DSoundDLL);
97 }
98 return (dsound_ok);
99 }
100
101 /* Functions for loading the DirectX functions dynamically */
102 static HINSTANCE DSoundDLL = NULL; 41 static HINSTANCE DSoundDLL = NULL;
103 42 static HRESULT (WINAPI *DSoundCreate)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN) = NULL;
104 static void 43
105 DX5_Unload(void) 44 static void
45 DSOUND_Unload(void)
106 { 46 {
107 if (DSoundDLL != NULL) { 47 if (DSoundDLL != NULL) {
108 FreeLibrary(DSoundDLL); 48 FreeLibrary(DSoundDLL);
109 DSoundCreate = NULL; 49 }
110 DSoundDLL = NULL; 50
111 } 51 DSoundCreate = NULL;
112 } 52 DSoundDLL = NULL;
53 }
54
55
113 static int 56 static int
114 DX5_Load(void) 57 DSOUND_Load(void)
115 { 58 {
116 int status; 59 int loaded = 0;
117 60
118 DX5_Unload(); 61 DSOUND_Unload();
62
119 DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL")); 63 DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL"));
120 if (DSoundDLL != NULL) { 64 if (DSoundDLL == NULL) {
121 DSoundCreate = (void *) GetProcAddress(DSoundDLL, 65 SDL_SetError("DirectSound: failed to load DSOUND.DLL");
66 } else {
67 /* Now make sure we have DirectX 5 or better... */
68 /* (DirectSoundCaptureCreate was added in DX5) */
69 if (!GetProcAddress(DSoundDLL, TEXT("DirectSoundCaptureCreate"))) {
70 SDL_SetError("DirectSound: System doesn't appear to have DX5.");
71 } else {
72 DSoundCreate = (void *) GetProcAddress(DSoundDLL,
122 TEXT("DirectSoundCreate")); 73 TEXT("DirectSoundCreate"));
123 } 74 }
124 if (DSoundDLL && DSoundCreate) { 75
125 status = 0; 76 if (!DSoundCreate) {
126 } else { 77 SDL_SetError("DirectSound: Failed to find DirectSoundCreate");
127 DX5_Unload(); 78 } else {
128 status = -1; 79 loaded = 1;
129 } 80 }
130 return status; 81 }
131 } 82
132 83 if (!loaded) {
133 static void 84 DSOUND_Unload();
134 Audio_DeleteDevice(SDL_AudioDevice * device) 85 }
135 { 86
136 DX5_Unload(); 87 return loaded;
137 SDL_free(device->hidden); 88 }
138 SDL_free(device); 89
139 }
140
141 static SDL_AudioDevice *
142 Audio_CreateDevice(int devindex)
143 {
144 SDL_AudioDevice *this;
145
146 /* Load DirectX */
147 if (DX5_Load() < 0) {
148 return (NULL);
149 }
150
151 /* Initialize all variables that we clean on shutdown */
152 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
153 if (this) {
154 SDL_memset(this, 0, (sizeof *this));
155 this->hidden = (struct SDL_PrivateAudioData *)
156 SDL_malloc((sizeof *this->hidden));
157 }
158 if ((this == NULL) || (this->hidden == NULL)) {
159 SDL_OutOfMemory();
160 if (this) {
161 SDL_free(this);
162 }
163 return (0);
164 }
165 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
166
167 /* Set the function pointers */
168 this->OpenAudio = DX5_OpenAudio;
169 this->ThreadInit = DX5_ThreadInit;
170 this->WaitAudio = DX5_WaitAudio_BusyWait;
171 this->PlayAudio = DX5_PlayAudio;
172 this->GetAudioBuf = DX5_GetAudioBuf;
173 this->WaitDone = DX5_WaitDone;
174 this->CloseAudio = DX5_CloseAudio;
175
176 this->free = Audio_DeleteDevice;
177
178 return this;
179 }
180
181 AudioBootStrap DSOUND_bootstrap = {
182 "dsound", "Win95/98/2000 DirectSound",
183 Audio_Available, Audio_CreateDevice
184 };
185 90
186 static void 91 static void
187 SetDSerror(const char *function, int code) 92 SetDSerror(const char *function, int code)
188 { 93 {
189 static const char *error; 94 static const char *error;
190 static char errbuf[1024]; 95 static char errbuf[1024];
191 96
192 errbuf[0] = 0; 97 errbuf[0] = 0;
193 switch (code) { 98 switch (code) {
194 case E_NOINTERFACE: 99 case E_NOINTERFACE:
195 error = 100 error = "Unsupported interface -- Is DirectX 5.0 or later installed?";
196 "Unsupported interface\n-- Is DirectX 5.0 or later installed?";
197 break; 101 break;
198 case DSERR_ALLOCATED: 102 case DSERR_ALLOCATED:
199 error = "Audio device in use"; 103 error = "Audio device in use";
200 break; 104 break;
201 case DSERR_BADFORMAT: 105 case DSERR_BADFORMAT:
239 } 143 }
240 144
241 /* DirectSound needs to be associated with a window */ 145 /* DirectSound needs to be associated with a window */
242 static HWND mainwin = NULL; 146 static HWND mainwin = NULL;
243 /* */ 147 /* */
148
244 void 149 void
245 DX5_SoundFocus(HWND hwnd) 150 DSOUND_SoundFocus(HWND hwnd)
246 { 151 {
152 /* !!! FIXME: probably broken with multi-window support in SDL 1.3 ... */
247 mainwin = hwnd; 153 mainwin = hwnd;
248 } 154 }
249 155
250 static void 156 static void
251 DX5_ThreadInit(_THIS) 157 DSOUND_ThreadInit(_THIS)
252 { 158 {
253 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); 159 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
254 } 160 }
255 161
256 static void 162 static void
257 DX5_WaitAudio_BusyWait(_THIS) 163 DSOUND_WaitDevice(_THIS)
258 { 164 {
259 DWORD status; 165 DWORD status = 0;
260 DWORD cursor, junk; 166 DWORD cursor = 0;
261 HRESULT result; 167 DWORD junk = 0;
168 HRESULT result = DS_OK;
262 169
263 /* Semi-busy wait, since we have no way of getting play notification 170 /* Semi-busy wait, since we have no way of getting play notification
264 on a primary mixing buffer located in hardware (DirectX 5.0) 171 on a primary mixing buffer located in hardware (DirectX 5.0)
265 */ 172 */
266 result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor); 173 result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
174 &junk, &cursor);
267 if (result != DS_OK) { 175 if (result != DS_OK) {
268 if (result == DSERR_BUFFERLOST) { 176 if (result == DSERR_BUFFERLOST) {
269 IDirectSoundBuffer_Restore(mixbuf); 177 IDirectSoundBuffer_Restore(this->hidden->mixbuf);
270 } 178 }
271 #ifdef DEBUG_SOUND 179 #ifdef DEBUG_SOUND
272 SetDSerror("DirectSound GetCurrentPosition", result); 180 SetDSerror("DirectSound GetCurrentPosition", result);
273 #endif 181 #endif
274 return; 182 return;
275 } 183 }
276 184
277 while ((cursor / mixlen) == lastchunk) { 185 while ((cursor / this->hidden->mixlen) == this->hidden->lastchunk) {
278 /* FIXME: find out how much time is left and sleep that long */ 186 /* FIXME: find out how much time is left and sleep that long */
279 SDL_Delay(1); 187 SDL_Delay(1);
280 188
281 /* Try to restore a lost sound buffer */ 189 /* Try to restore a lost sound buffer */
282 IDirectSoundBuffer_GetStatus(mixbuf, &status); 190 IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
283 if ((status & DSBSTATUS_BUFFERLOST)) { 191 if ((status & DSBSTATUS_BUFFERLOST)) {
284 IDirectSoundBuffer_Restore(mixbuf); 192 IDirectSoundBuffer_Restore(this->hidden->mixbuf);
285 IDirectSoundBuffer_GetStatus(mixbuf, &status); 193 IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
286 if ((status & DSBSTATUS_BUFFERLOST)) { 194 if ((status & DSBSTATUS_BUFFERLOST)) {
287 break; 195 break;
288 } 196 }
289 } 197 }
290 if (!(status & DSBSTATUS_PLAYING)) { 198 if (!(status & DSBSTATUS_PLAYING)) {
291 result = IDirectSoundBuffer_Play(mixbuf, 0, 0, DSBPLAY_LOOPING); 199 result = IDirectSoundBuffer_Play(this->hidden->mixbuf, 0, 0,
200 DSBPLAY_LOOPING);
292 if (result == DS_OK) { 201 if (result == DS_OK) {
293 continue; 202 continue;
294 } 203 }
295 #ifdef DEBUG_SOUND 204 #ifdef DEBUG_SOUND
296 SetDSerror("DirectSound Play", result); 205 SetDSerror("DirectSound Play", result);
297 #endif 206 #endif
298 return; 207 return;
299 } 208 }
300 209
301 /* Find out where we are playing */ 210 /* Find out where we are playing */
302 result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, 211 result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
303 &junk, &cursor); 212 &junk, &cursor);
304 if (result != DS_OK) { 213 if (result != DS_OK) {
305 SetDSerror("DirectSound GetCurrentPosition", result); 214 SetDSerror("DirectSound GetCurrentPosition", result);
306 return; 215 return;
307 } 216 }
308 } 217 }
309 } 218 }
310 219
311 #ifdef USE_POSITION_NOTIFY 220 static void
312 static void 221 DSOUND_PlayDevice(_THIS)
313 DX6_WaitAudio_EventWait(_THIS)
314 {
315 DWORD status;
316 HRESULT result;
317
318 /* Try to restore a lost sound buffer */
319 IDirectSoundBuffer_GetStatus(mixbuf, &status);
320 if ((status & DSBSTATUS_BUFFERLOST)) {
321 IDirectSoundBuffer_Restore(mixbuf);
322 IDirectSoundBuffer_GetStatus(mixbuf, &status);
323 if ((status & DSBSTATUS_BUFFERLOST)) {
324 return;
325 }
326 }
327 if (!(status & DSBSTATUS_PLAYING)) {
328 result = IDirectSoundBuffer_Play(mixbuf, 0, 0, DSBPLAY_LOOPING);
329 if (result != DS_OK) {
330 #ifdef DEBUG_SOUND
331 SetDSerror("DirectSound Play", result);
332 #endif
333 return;
334 }
335 }
336 WaitForSingleObject(audio_event, INFINITE);
337 }
338 #endif /* USE_POSITION_NOTIFY */
339
340 static void
341 DX5_PlayAudio(_THIS)
342 { 222 {
343 /* Unlock the buffer, allowing it to play */ 223 /* Unlock the buffer, allowing it to play */
344 if (locked_buf) { 224 if (this->hidden->locked_buf) {
345 IDirectSoundBuffer_Unlock(mixbuf, locked_buf, mixlen, NULL, 0); 225 IDirectSoundBuffer_Unlock(this->hidden->mixbuf,
226 this->hidden->locked_buf,
227 this->hidden->mixlen, NULL, 0);
346 } 228 }
347 229
348 } 230 }
349 231
350 static Uint8 * 232 static Uint8 *
351 DX5_GetAudioBuf(_THIS) 233 DSOUND_GetDeviceBuf(_THIS)
352 { 234 {
353 DWORD cursor, junk; 235 DWORD cursor = 0;
354 HRESULT result; 236 DWORD junk = 0;
355 DWORD rawlen; 237 HRESULT result = DS_OK;
238 DWORD rawlen = 0;
356 239
357 /* Figure out which blocks to fill next */ 240 /* Figure out which blocks to fill next */
358 locked_buf = NULL; 241 this->hidden->locked_buf = NULL;
359 result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor); 242 result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
243 &junk, &cursor);
360 if (result == DSERR_BUFFERLOST) { 244 if (result == DSERR_BUFFERLOST) {
361 IDirectSoundBuffer_Restore(mixbuf); 245 IDirectSoundBuffer_Restore(this->hidden->mixbuf);
362 result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, 246 result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
363 &junk, &cursor); 247 &junk, &cursor);
364 } 248 }
365 if (result != DS_OK) { 249 if (result != DS_OK) {
366 SetDSerror("DirectSound GetCurrentPosition", result); 250 SetDSerror("DirectSound GetCurrentPosition", result);
367 return (NULL); 251 return (NULL);
368 } 252 }
369 cursor /= mixlen; 253 cursor /= this->hidden->mixlen;
370 #ifdef DEBUG_SOUND 254 #ifdef DEBUG_SOUND
371 /* Detect audio dropouts */ 255 /* Detect audio dropouts */
372 { 256 {
373 DWORD spot = cursor; 257 DWORD spot = cursor;
374 if (spot < lastchunk) { 258 if (spot < this->hidden->lastchunk) {
375 spot += NUM_BUFFERS; 259 spot += this->hidden->num_buffers;
376 } 260 }
377 if (spot > lastchunk + 1) { 261 if (spot > this->hidden->lastchunk + 1) {
378 fprintf(stderr, "Audio dropout, missed %d fragments\n", 262 fprintf(stderr, "Audio dropout, missed %d fragments\n",
379 (spot - (lastchunk + 1))); 263 (spot - (this->hidden->lastchunk + 1)));
380 } 264 }
381 } 265 }
382 #endif 266 #endif
383 lastchunk = cursor; 267 this->hidden->lastchunk = cursor;
384 cursor = (cursor + 1) % NUM_BUFFERS; 268 cursor = (cursor + 1) % this->hidden->num_buffers;
385 cursor *= mixlen; 269 cursor *= this->hidden->mixlen;
386 270
387 /* Lock the audio buffer */ 271 /* Lock the audio buffer */
388 result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen, 272 result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
389 (LPVOID *) & locked_buf, &rawlen, NULL, 273 this->hidden->mixlen,
390 &junk, 0); 274 (LPVOID *) &this->hidden->locked_buf,
275 &rawlen, NULL, &junk, 0);
391 if (result == DSERR_BUFFERLOST) { 276 if (result == DSERR_BUFFERLOST) {
392 IDirectSoundBuffer_Restore(mixbuf); 277 IDirectSoundBuffer_Restore(this->hidden->mixbuf);
393 result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen, 278 result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
394 (LPVOID *) & locked_buf, &rawlen, 279 this->hidden->mixlen,
395 NULL, &junk, 0); 280 (LPVOID *) &this->hidden->locked_buf,
281 &rawlen, NULL, &junk, 0);
396 } 282 }
397 if (result != DS_OK) { 283 if (result != DS_OK) {
398 SetDSerror("DirectSound Lock", result); 284 SetDSerror("DirectSound Lock", result);
399 return (NULL); 285 return (NULL);
400 } 286 }
401 return (locked_buf); 287 return (this->hidden->locked_buf);
402 } 288 }
403 289
404 static void 290 static void
405 DX5_WaitDone(_THIS) 291 DSOUND_WaitDone(_THIS)
406 { 292 {
407 Uint8 *stream; 293 Uint8 *stream = DSOUND_GetDeviceBuf(this);
408 294
409 /* Wait for the playing chunk to finish */ 295 /* Wait for the playing chunk to finish */
410 stream = this->GetAudioBuf(this);
411 if (stream != NULL) { 296 if (stream != NULL) {
412 SDL_memset(stream, silence, mixlen); 297 SDL_memset(stream, this->spec.silence, this->hidden->mixlen);
413 this->PlayAudio(this); 298 DSOUND_PlayDevice(this);
414 } 299 }
415 this->WaitAudio(this); 300 DSOUND_WaitDevice(this);
416 301
417 /* Stop the looping sound buffer */ 302 /* Stop the looping sound buffer */
418 IDirectSoundBuffer_Stop(mixbuf); 303 IDirectSoundBuffer_Stop(this->hidden->mixbuf);
419 } 304 }
420 305
421 static void 306 static void
422 DX5_CloseAudio(_THIS) 307 DSOUND_CloseDevice(_THIS)
423 { 308 {
424 if (sound != NULL) { 309 if (this->hidden != NULL) {
425 if (mixbuf != NULL) { 310 if (this->hidden->sound != NULL) {
426 /* Clean up the audio buffer */ 311 if (this->hidden->mixbuf != NULL) {
427 IDirectSoundBuffer_Release(mixbuf); 312 /* Clean up the audio buffer */
428 mixbuf = NULL; 313 IDirectSoundBuffer_Release(this->hidden->mixbuf);
429 } 314 this->hidden->mixbuf = NULL;
430 if (audio_event != NULL) { 315 }
431 CloseHandle(audio_event); 316 IDirectSound_Release(this->hidden->sound);
432 audio_event = NULL; 317 this->hidden->sound = NULL;
433 } 318 }
434 IDirectSound_Release(sound); 319
435 sound = NULL; 320 SDL_free(this->hidden);
436 } 321 this->hidden = NULL;
437 } 322 }
438 323 }
439 #ifdef USE_PRIMARY_BUFFER
440 /* This function tries to create a primary audio buffer, and returns the
441 number of audio chunks available in the created buffer.
442 */
443 static int
444 CreatePrimary(LPDIRECTSOUND sndObj, HWND focus,
445 LPDIRECTSOUNDBUFFER * sndbuf, WAVEFORMATEX * wavefmt,
446 Uint32 chunksize)
447 {
448 HRESULT result;
449 DSBUFFERDESC format;
450 DSBCAPS caps;
451 int numchunks;
452
453 /* Try to set primary mixing privileges */
454 result = IDirectSound_SetCooperativeLevel(sndObj, focus,
455 DSSCL_WRITEPRIMARY);
456 if (result != DS_OK) {
457 #ifdef DEBUG_SOUND
458 SetDSerror("DirectSound SetCooperativeLevel", result);
459 #endif
460 return (-1);
461 }
462
463 /* Try to create the primary buffer */
464 SDL_memset(&format, 0, sizeof(format));
465 format.dwSize = sizeof(format);
466 format.dwFlags = (DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2);
467 format.dwFlags |= DSBCAPS_STICKYFOCUS;
468 #ifdef USE_POSITION_NOTIFY
469 format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
470 #endif
471 result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
472 if (result != DS_OK) {
473 #ifdef DEBUG_SOUND
474 SetDSerror("DirectSound CreateSoundBuffer", result);
475 #endif
476 return (-1);
477 }
478
479 /* Check the size of the fragment buffer */
480 SDL_memset(&caps, 0, sizeof(caps));
481 caps.dwSize = sizeof(caps);
482 result = IDirectSoundBuffer_GetCaps(*sndbuf, &caps);
483 if (result != DS_OK) {
484 #ifdef DEBUG_SOUND
485 SetDSerror("DirectSound GetCaps", result);
486 #endif
487 IDirectSoundBuffer_Release(*sndbuf);
488 return (-1);
489 }
490 if ((chunksize > caps.dwBufferBytes) ||
491 ((caps.dwBufferBytes % chunksize) != 0)) {
492 /* The primary buffer size is not a multiple of 'chunksize'
493 -- this hopefully doesn't happen when 'chunksize' is a
494 power of 2.
495 */
496 IDirectSoundBuffer_Release(*sndbuf);
497 SDL_SetError
498 ("Primary buffer size is: %d, cannot break it into chunks of %d bytes\n",
499 caps.dwBufferBytes, chunksize);
500 return (-1);
501 }
502 numchunks = (caps.dwBufferBytes / chunksize);
503
504 /* Set the primary audio format */
505 result = IDirectSoundBuffer_SetFormat(*sndbuf, wavefmt);
506 if (result != DS_OK) {
507 #ifdef DEBUG_SOUND
508 SetDSerror("DirectSound SetFormat", result);
509 #endif
510 IDirectSoundBuffer_Release(*sndbuf);
511 return (-1);
512 }
513 return (numchunks);
514 }
515 #endif /* USE_PRIMARY_BUFFER */
516 324
517 /* This function tries to create a secondary audio buffer, and returns the 325 /* This function tries to create a secondary audio buffer, and returns the
518 number of audio chunks available in the created buffer. 326 number of audio chunks available in the created buffer.
519 */ 327 */
520 static int 328 static int
521 CreateSecondary(LPDIRECTSOUND sndObj, HWND focus, 329 CreateSecondary(_THIS, HWND focus, WAVEFORMATEX *wavefmt)
522 LPDIRECTSOUNDBUFFER * sndbuf, WAVEFORMATEX * wavefmt, 330 {
523 Uint32 chunksize) 331 LPDIRECTSOUND sndObj = this->hidden->sound;
524 { 332 LPDIRECTSOUNDBUFFER *sndbuf = this->hidden->mixbuf;
333 Uint32 chunksize = this->spec.size;
525 const int numchunks = 8; 334 const int numchunks = 8;
526 HRESULT result; 335 HRESULT result = DS_OK;
527 DSBUFFERDESC format; 336 DSBUFFERDESC format;
528 LPVOID pvAudioPtr1, pvAudioPtr2; 337 LPVOID pvAudioPtr1, pvAudioPtr2;
529 DWORD dwAudioBytes1, dwAudioBytes2; 338 DWORD dwAudioBytes1, dwAudioBytes2;
530 339
531 /* Try to set primary mixing privileges */ 340 /* Try to set primary mixing privileges */
536 result = IDirectSound_SetCooperativeLevel(sndObj, 345 result = IDirectSound_SetCooperativeLevel(sndObj,
537 GetDesktopWindow(), 346 GetDesktopWindow(),
538 DSSCL_NORMAL); 347 DSSCL_NORMAL);
539 } 348 }
540 if (result != DS_OK) { 349 if (result != DS_OK) {
541 #ifdef DEBUG_SOUND
542 SetDSerror("DirectSound SetCooperativeLevel", result); 350 SetDSerror("DirectSound SetCooperativeLevel", result);
543 #endif
544 return (-1); 351 return (-1);
545 } 352 }
546 353
547 /* Try to create the secondary buffer */ 354 /* Try to create the secondary buffer */
548 SDL_memset(&format, 0, sizeof(format)); 355 SDL_memset(&format, 0, sizeof(format));
549 format.dwSize = sizeof(format); 356 format.dwSize = sizeof(format);
550 format.dwFlags = DSBCAPS_GETCURRENTPOSITION2; 357 format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
551 #ifdef USE_POSITION_NOTIFY
552 format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
553 #endif
554 if (!focus) { 358 if (!focus) {
555 format.dwFlags |= DSBCAPS_GLOBALFOCUS; 359 format.dwFlags |= DSBCAPS_GLOBALFOCUS;
556 } else { 360 } else {
557 format.dwFlags |= DSBCAPS_STICKYFOCUS; 361 format.dwFlags |= DSBCAPS_STICKYFOCUS;
558 } 362 }
576 result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes, 380 result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
577 (LPVOID *) & pvAudioPtr1, &dwAudioBytes1, 381 (LPVOID *) & pvAudioPtr1, &dwAudioBytes1,
578 (LPVOID *) & pvAudioPtr2, &dwAudioBytes2, 382 (LPVOID *) & pvAudioPtr2, &dwAudioBytes2,
579 DSBLOCK_ENTIREBUFFER); 383 DSBLOCK_ENTIREBUFFER);
580 if (result == DS_OK) { 384 if (result == DS_OK) {
581 if (wavefmt->wBitsPerSample == 8) { 385 SDL_memset(pvAudioPtr1, this->spec.silence, dwAudioBytes1);
582 SDL_memset(pvAudioPtr1, 0x80, dwAudioBytes1);
583 } else {
584 SDL_memset(pvAudioPtr1, 0x00, dwAudioBytes1);
585 }
586 IDirectSoundBuffer_Unlock(*sndbuf, 386 IDirectSoundBuffer_Unlock(*sndbuf,
587 (LPVOID) pvAudioPtr1, dwAudioBytes1, 387 (LPVOID) pvAudioPtr1, dwAudioBytes1,
588 (LPVOID) pvAudioPtr2, dwAudioBytes2); 388 (LPVOID) pvAudioPtr2, dwAudioBytes2);
589 } 389 }
590 390
591 /* We're ready to go */ 391 /* We're ready to go */
592 return (numchunks); 392 return (numchunks);
593 } 393 }
594 394
595 /* This function tries to set position notify events on the mixing buffer */
596 #ifdef USE_POSITION_NOTIFY
597 static int 395 static int
598 CreateAudioEvent(_THIS) 396 DSOUND_OpenDevice(_THIS, const char *devname, int iscapture)
599 {
600 LPDIRECTSOUNDNOTIFY notify;
601 DSBPOSITIONNOTIFY *notify_positions;
602 int i, retval;
603 HRESULT result;
604
605 /* Default to fail on exit */
606 retval = -1;
607 notify = NULL;
608
609 /* Query for the interface */
610 result = IDirectSoundBuffer_QueryInterface(mixbuf,
611 &IID_IDirectSoundNotify,
612 (void *) &notify);
613 if (result != DS_OK) {
614 goto done;
615 }
616
617 /* Allocate the notify structures */
618 notify_positions = (DSBPOSITIONNOTIFY *) SDL_malloc(NUM_BUFFERS *
619 sizeof
620 (*notify_positions));
621 if (notify_positions == NULL) {
622 goto done;
623 }
624
625 /* Create the notify event */
626 audio_event = CreateEvent(NULL, FALSE, FALSE, NULL);
627 if (audio_event == NULL) {
628 goto done;
629 }
630
631 /* Set up the notify structures */
632 for (i = 0; i < NUM_BUFFERS; ++i) {
633 notify_positions[i].dwOffset = i * mixlen;
634 notify_positions[i].hEventNotify = audio_event;
635 }
636 result = IDirectSoundNotify_SetNotificationPositions(notify,
637 NUM_BUFFERS,
638 notify_positions);
639 if (result == DS_OK) {
640 retval = 0;
641 }
642 done:
643 if (notify != NULL) {
644 IDirectSoundNotify_Release(notify);
645 }
646 return (retval);
647 }
648 #endif /* USE_POSITION_NOTIFY */
649
650 static int
651 DX5_OpenAudio(_THIS, SDL_AudioSpec * spec)
652 { 397 {
653 HRESULT result; 398 HRESULT result;
654 WAVEFORMATEX waveformat; 399 WAVEFORMATEX waveformat;
655 400 int valid_format = 0;
656 /* Set basic WAVE format parameters */ 401 SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
402
403 /* !!! FIXME: handle devname */
404 /* !!! FIXME: handle iscapture */
405
406 /* Initialize all variables that we clean on shutdown */
407 this->hidden = (struct SDL_PrivateAudioData *)
408 SDL_malloc((sizeof *this->hidden));
409 if (this->hidden == NULL) {
410 SDL_OutOfMemory();
411 return 0;
412 }
413 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
414
415 while ((!valid_format) && (test_format)) {
416 switch (test_format) {
417 case AUDIO_U8:
418 case AUDIO_S16:
419 case AUDIO_S32:
420 this->spec.format = test_format;
421 valid_format = 1;
422 break;
423 }
424 test_format = SDL_NextAudioFormat();
425 }
426
427 if (!valid_format) {
428 DSOUND_CloseDevice(this);
429 SDL_SetError("DirectSound: Unsupported audio format");
430 return 0;
431 }
432
657 SDL_memset(&waveformat, 0, sizeof(waveformat)); 433 SDL_memset(&waveformat, 0, sizeof(waveformat));
658 waveformat.wFormatTag = WAVE_FORMAT_PCM; 434 waveformat.wFormatTag = WAVE_FORMAT_PCM;
659 435 waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
660 /* Determine the audio parameters from the AudioSpec */ 436 waveformat.nChannels = this->spec.channels;
661 switch (SDL_AUDIO_BITSIZE(spec->format)) { 437 waveformat.nSamplesPerSec = this->spec.freq;
662 case 8:
663 /* Unsigned 8 bit audio data */
664 spec->format = AUDIO_U8;
665 silence = 0x80;
666 waveformat.wBitsPerSample = 8;
667 break;
668 case 16:
669 /* Signed 16 bit audio data */
670 spec->format = AUDIO_S16;
671 silence = 0x00;
672 waveformat.wBitsPerSample = 16;
673 break;
674 case 32:
675 /* Signed 32 bit audio data */
676 spec->format = AUDIO_S32;
677 silence = 0x00;
678 waveformat.wBitsPerSample = 32;
679 break;
680 default:
681 SDL_SetError("Unsupported audio format");
682 return (-1);
683 }
684 waveformat.nChannels = spec->channels;
685 waveformat.nSamplesPerSec = spec->freq;
686 waveformat.nBlockAlign = 438 waveformat.nBlockAlign =
687 waveformat.nChannels * (waveformat.wBitsPerSample / 8); 439 waveformat.nChannels * (waveformat.wBitsPerSample / 8);
688 waveformat.nAvgBytesPerSec = 440 waveformat.nAvgBytesPerSec =
689 waveformat.nSamplesPerSec * waveformat.nBlockAlign; 441 waveformat.nSamplesPerSec * waveformat.nBlockAlign;
690 442
691 /* Update the fragment size as size in bytes */ 443 /* Update the fragment size as size in bytes */
692 SDL_CalculateAudioSpec(spec); 444 SDL_CalculateAudioSpec(&this->spec);
693 445
694 /* Open the audio device */ 446 /* Open the audio device */
695 result = DSoundCreate(NULL, &sound, NULL); 447 result = DSoundCreate(NULL, &this->hidden->sound, NULL);
696 if (result != DS_OK) { 448 if (result != DS_OK) {
449 DSOUND_CloseDevice(this);
697 SetDSerror("DirectSoundCreate", result); 450 SetDSerror("DirectSoundCreate", result);
698 return (-1); 451 return 0;
699 } 452 }
700 453
701 /* Create the audio buffer to which we write */ 454 /* Create the audio buffer to which we write */
702 NUM_BUFFERS = -1; 455 this->hidden->num_buffers = CreateSecondary(this, mainwin, &waveformat);
703 #ifdef USE_PRIMARY_BUFFER 456 if (this->hidden->num_buffers < 0) {
704 if (mainwin) { 457 DSOUND_CloseDevice(this);
705 NUM_BUFFERS = CreatePrimary(sound, mainwin, &mixbuf, 458 return 0;
706 &waveformat, spec->size); 459 }
707 } 460
708 #endif /* USE_PRIMARY_BUFFER */ 461 /* The buffer will auto-start playing in DSOUND_WaitDevice() */
709 if (NUM_BUFFERS < 0) { 462 this->hidden->mixlen = this->spec.size;
710 NUM_BUFFERS = CreateSecondary(sound, mainwin, &mixbuf, 463
711 &waveformat, spec->size); 464 return 1; /* good to go. */
712 if (NUM_BUFFERS < 0) { 465 }
713 return (-1); 466
714 } 467
715 #ifdef DEBUG_SOUND 468 static void
716 fprintf(stderr, "Using secondary audio buffer\n"); 469 DSOUND_Deinitialize(void)
717 #endif 470 {
718 } 471 DSOUND_Unload();
719 #ifdef DEBUG_SOUND 472 }
720 else 473
721 fprintf(stderr, "Using primary audio buffer\n"); 474
722 #endif 475 static int
723 476 DSOUND_Init(SDL_AudioDriverImpl *impl)
724 /* The buffer will auto-start playing in DX5_WaitAudio() */ 477 {
725 lastchunk = 0; 478 OSVERSIONINFO ver;
726 mixlen = spec->size; 479
727 480 /*
728 #ifdef USE_POSITION_NOTIFY 481 * Unfortunately, the sound drivers on NT have higher latencies than the
729 /* See if we can use DirectX 6 event notification */ 482 * audio buffers used by many SDL applications, so there are gaps in the
730 if (CreateAudioEvent(this) == 0) { 483 * audio - it sounds terrible. Punt for now.
731 this->WaitAudio = DX6_WaitAudio_EventWait; 484 */
732 } else { 485 SDL_memset(&ver, '\0', sizeof (OSVERSIONINFO));
733 this->WaitAudio = DX5_WaitAudio_BusyWait; 486 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
734 } 487 GetVersionEx(&ver);
735 #endif 488 if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT)
736 return (0); 489 if (ver.dwMajorVersion <= 4) {
737 } 490 return 0; /* NT4.0 or earlier. Disable dsound support. */
491 }
492 }
493
494 if (!DSOUND_Load()) {
495 return 0;
496 }
497
498 /* Set the function pointers */
499 impl->OpenDevice = DSOUND_OpenDevice;
500 impl->PlayDevice = DSOUND_PlayDevice;
501 impl->WaitDevice = DSOUND_WaitDevice;
502 impl->WaitDone = DSOUND_WaitDone;
503 impl->ThreadInit = DSOUND_ThreadInit;
504 impl->GetDeviceBuf = DSOUND_GetDeviceBuf;
505 impl->CloseDevice = DSOUND_CloseDevice;
506 impl->Deinitialize = DSOUND_Deinitialize;
507 impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME */
508
509 return 1;
510 }
511
512 AudioBootStrap DSOUND_bootstrap = {
513 "dsound", WINDOWS_OS_NAME "DirectSound", DSOUND_Init, 0
514 };
738 515
739 /* vi: set ts=4 sw=4 expandtab: */ 516 /* vi: set ts=4 sw=4 expandtab: */