comparison src/audio/windx5/SDL_dx5audio.c @ 3842:6b04ca2f1016 SDL-ryan-multiple-audio-device

Moved DirectSound audio target to SDL 1.3 API and did some house cleaning.
author Ryan C. Gordon <icculus@icculus.org>
date Tue, 17 Oct 2006 06:37:42 +0000
parents c8b3d3d13ed1
children 66fb40445587
comparison
equal deleted inserted replaced
3841:3479f939987c 3842:6b04ca2f1016
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 } 90
140 91
141 static SDL_AudioDevice * 92
142 Audio_CreateDevice(int devindex) 93 static int
143 { 94 DSOUND_Available(void)
144 SDL_AudioDevice *this; 95 {
145 96 int dsound_ok = 1;
146 /* Load DirectX */ 97 OSVERSIONINFO ver;
147 if (DX5_Load() < 0) { 98
148 return (NULL); 99 /*
149 } 100 * Unfortunately, the sound drivers on NT have higher latencies than the
150 101 * audio buffers used by many SDL applications, so there are gaps in the
151 /* Initialize all variables that we clean on shutdown */ 102 * audio - it sounds terrible. Punt for now.
152 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); 103 */
153 if (this) { 104 SDL_memset(&ver, '\0', sizeof (OSVERSIONINFO));
154 SDL_memset(this, 0, (sizeof *this)); 105 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
155 this->hidden = (struct SDL_PrivateAudioData *) 106 GetVersionEx(&ver);
156 SDL_malloc((sizeof *this->hidden)); 107 if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT)
157 } 108 if (ver.dwMajorVersion <= 4) {
158 if ((this == NULL) || (this->hidden == NULL)) { 109 dsound_ok = 0; /* NT4.0 or earlier. Disable dsound support. */
159 SDL_OutOfMemory(); 110 }
160 if (this) { 111 }
161 SDL_free(this); 112
162 } 113 if (dsound_ok) {
163 return (0); 114 dsound_ok = DSOUND_Load(); /* make sure we really have DX5. */
164 } 115 DSOUND_Unload();
165 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); 116 }
166 117
167 /* Set the function pointers */ 118 return (dsound_ok);
168 this->OpenAudio = DX5_OpenAudio; 119 }
169 this->ThreadInit = DX5_ThreadInit; 120
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, 0
184 };
185 121
186 static void 122 static void
187 SetDSerror(const char *function, int code) 123 SetDSerror(const char *function, int code)
188 { 124 {
189 static const char *error; 125 static const char *error;
190 static char errbuf[1024]; 126 static char errbuf[1024];
191 127
192 errbuf[0] = 0; 128 errbuf[0] = 0;
193 switch (code) { 129 switch (code) {
194 case E_NOINTERFACE: 130 case E_NOINTERFACE:
195 error = 131 error = "Unsupported interface -- Is DirectX 5.0 or later installed?";
196 "Unsupported interface\n-- Is DirectX 5.0 or later installed?";
197 break; 132 break;
198 case DSERR_ALLOCATED: 133 case DSERR_ALLOCATED:
199 error = "Audio device in use"; 134 error = "Audio device in use";
200 break; 135 break;
201 case DSERR_BADFORMAT: 136 case DSERR_BADFORMAT:
239 } 174 }
240 175
241 /* DirectSound needs to be associated with a window */ 176 /* DirectSound needs to be associated with a window */
242 static HWND mainwin = NULL; 177 static HWND mainwin = NULL;
243 /* */ 178 /* */
179
244 void 180 void
245 DX5_SoundFocus(HWND hwnd) 181 DSOUND_SoundFocus(HWND hwnd)
246 { 182 {
183 /* !!! FIXME: probably broken with multi-window support in SDL 1.3 ... */
247 mainwin = hwnd; 184 mainwin = hwnd;
248 } 185 }
249 186
250 static void 187 static void
251 DX5_ThreadInit(_THIS) 188 DSOUND_ThreadInit(_THIS)
252 { 189 {
253 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); 190 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
254 } 191 }
255 192
256 static void 193 static void
257 DX5_WaitAudio_BusyWait(_THIS) 194 DSOUND_WaitDevice(_THIS)
258 { 195 {
259 DWORD status; 196 DWORD status = 0;
260 DWORD cursor, junk; 197 DWORD cursor = 0;
261 HRESULT result; 198 DWORD junk = 0;
199 HRESULT result = DS_OK;
262 200
263 /* Semi-busy wait, since we have no way of getting play notification 201 /* Semi-busy wait, since we have no way of getting play notification
264 on a primary mixing buffer located in hardware (DirectX 5.0) 202 on a primary mixing buffer located in hardware (DirectX 5.0)
265 */ 203 */
266 result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor); 204 result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
205 &junk, &cursor);
267 if (result != DS_OK) { 206 if (result != DS_OK) {
268 if (result == DSERR_BUFFERLOST) { 207 if (result == DSERR_BUFFERLOST) {
269 IDirectSoundBuffer_Restore(mixbuf); 208 IDirectSoundBuffer_Restore(this->hidden->mixbuf);
270 } 209 }
271 #ifdef DEBUG_SOUND 210 #ifdef DEBUG_SOUND
272 SetDSerror("DirectSound GetCurrentPosition", result); 211 SetDSerror("DirectSound GetCurrentPosition", result);
273 #endif 212 #endif
274 return; 213 return;
275 } 214 }
276 215
277 while ((cursor / mixlen) == lastchunk) { 216 while ((cursor / this->hidden->mixlen) == this->hidden->lastchunk) {
278 /* FIXME: find out how much time is left and sleep that long */ 217 /* FIXME: find out how much time is left and sleep that long */
279 SDL_Delay(1); 218 SDL_Delay(1);
280 219
281 /* Try to restore a lost sound buffer */ 220 /* Try to restore a lost sound buffer */
282 IDirectSoundBuffer_GetStatus(mixbuf, &status); 221 IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
283 if ((status & DSBSTATUS_BUFFERLOST)) { 222 if ((status & DSBSTATUS_BUFFERLOST)) {
284 IDirectSoundBuffer_Restore(mixbuf); 223 IDirectSoundBuffer_Restore(this->hidden->mixbuf);
285 IDirectSoundBuffer_GetStatus(mixbuf, &status); 224 IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
286 if ((status & DSBSTATUS_BUFFERLOST)) { 225 if ((status & DSBSTATUS_BUFFERLOST)) {
287 break; 226 break;
288 } 227 }
289 } 228 }
290 if (!(status & DSBSTATUS_PLAYING)) { 229 if (!(status & DSBSTATUS_PLAYING)) {
291 result = IDirectSoundBuffer_Play(mixbuf, 0, 0, DSBPLAY_LOOPING); 230 result = IDirectSoundBuffer_Play(this->hidden->mixbuf, 0, 0,
231 DSBPLAY_LOOPING);
292 if (result == DS_OK) { 232 if (result == DS_OK) {
293 continue; 233 continue;
294 } 234 }
295 #ifdef DEBUG_SOUND 235 #ifdef DEBUG_SOUND
296 SetDSerror("DirectSound Play", result); 236 SetDSerror("DirectSound Play", result);
297 #endif 237 #endif
298 return; 238 return;
299 } 239 }
300 240
301 /* Find out where we are playing */ 241 /* Find out where we are playing */
302 result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, 242 result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
303 &junk, &cursor); 243 &junk, &cursor);
304 if (result != DS_OK) { 244 if (result != DS_OK) {
305 SetDSerror("DirectSound GetCurrentPosition", result); 245 SetDSerror("DirectSound GetCurrentPosition", result);
306 return; 246 return;
307 } 247 }
308 } 248 }
309 } 249 }
310 250
311 #ifdef USE_POSITION_NOTIFY 251 static void
312 static void 252 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 { 253 {
343 /* Unlock the buffer, allowing it to play */ 254 /* Unlock the buffer, allowing it to play */
344 if (locked_buf) { 255 if (this->hidden->locked_buf) {
345 IDirectSoundBuffer_Unlock(mixbuf, locked_buf, mixlen, NULL, 0); 256 IDirectSoundBuffer_Unlock(this->hidden->mixbuf,
257 this->hidden->locked_buf,
258 this->hidden->mixlen, NULL, 0);
346 } 259 }
347 260
348 } 261 }
349 262
350 static Uint8 * 263 static Uint8 *
351 DX5_GetAudioBuf(_THIS) 264 DSOUND_GetDeviceBuf(_THIS)
352 { 265 {
353 DWORD cursor, junk; 266 DWORD cursor = 0;
354 HRESULT result; 267 DWORD junk = 0;
355 DWORD rawlen; 268 HRESULT result = DS_OK;
269 DWORD rawlen = 0;
356 270
357 /* Figure out which blocks to fill next */ 271 /* Figure out which blocks to fill next */
358 locked_buf = NULL; 272 this->hidden->locked_buf = NULL;
359 result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor); 273 result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
274 &junk, &cursor);
360 if (result == DSERR_BUFFERLOST) { 275 if (result == DSERR_BUFFERLOST) {
361 IDirectSoundBuffer_Restore(mixbuf); 276 IDirectSoundBuffer_Restore(this->hidden->mixbuf);
362 result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, 277 result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
363 &junk, &cursor); 278 &junk, &cursor);
364 } 279 }
365 if (result != DS_OK) { 280 if (result != DS_OK) {
366 SetDSerror("DirectSound GetCurrentPosition", result); 281 SetDSerror("DirectSound GetCurrentPosition", result);
367 return (NULL); 282 return (NULL);
368 } 283 }
369 cursor /= mixlen; 284 cursor /= this->hidden->mixlen;
370 #ifdef DEBUG_SOUND 285 #ifdef DEBUG_SOUND
371 /* Detect audio dropouts */ 286 /* Detect audio dropouts */
372 { 287 {
373 DWORD spot = cursor; 288 DWORD spot = cursor;
374 if (spot < lastchunk) { 289 if (spot < this->hidden->lastchunk) {
375 spot += NUM_BUFFERS; 290 spot += this->hidden->num_buffers;
376 } 291 }
377 if (spot > lastchunk + 1) { 292 if (spot > this->hidden->lastchunk + 1) {
378 fprintf(stderr, "Audio dropout, missed %d fragments\n", 293 fprintf(stderr, "Audio dropout, missed %d fragments\n",
379 (spot - (lastchunk + 1))); 294 (spot - (this->hidden->lastchunk + 1)));
380 } 295 }
381 } 296 }
382 #endif 297 #endif
383 lastchunk = cursor; 298 this->hidden->lastchunk = cursor;
384 cursor = (cursor + 1) % NUM_BUFFERS; 299 cursor = (cursor + 1) % this->hidden->num_buffers;
385 cursor *= mixlen; 300 cursor *= this->hidden->mixlen;
386 301
387 /* Lock the audio buffer */ 302 /* Lock the audio buffer */
388 result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen, 303 result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
389 (LPVOID *) & locked_buf, &rawlen, NULL, 304 this->hidden->mixlen,
390 &junk, 0); 305 (LPVOID *) &this->hidden->locked_buf,
306 &rawlen, NULL, &junk, 0);
391 if (result == DSERR_BUFFERLOST) { 307 if (result == DSERR_BUFFERLOST) {
392 IDirectSoundBuffer_Restore(mixbuf); 308 IDirectSoundBuffer_Restore(this->hidden->mixbuf);
393 result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen, 309 result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
394 (LPVOID *) & locked_buf, &rawlen, 310 this->hidden->mixlen,
395 NULL, &junk, 0); 311 (LPVOID *) &this->hidden->locked_buf,
312 &rawlen, NULL, &junk, 0);
396 } 313 }
397 if (result != DS_OK) { 314 if (result != DS_OK) {
398 SetDSerror("DirectSound Lock", result); 315 SetDSerror("DirectSound Lock", result);
399 return (NULL); 316 return (NULL);
400 } 317 }
401 return (locked_buf); 318 return (this->hidden->locked_buf);
402 } 319 }
403 320
404 static void 321 static void
405 DX5_WaitDone(_THIS) 322 DSOUND_WaitDone(_THIS)
406 { 323 {
407 Uint8 *stream; 324 Uint8 *stream = DSOUND_GetDeviceBuf(this);
408 325
409 /* Wait for the playing chunk to finish */ 326 /* Wait for the playing chunk to finish */
410 stream = this->GetAudioBuf(this);
411 if (stream != NULL) { 327 if (stream != NULL) {
412 SDL_memset(stream, silence, mixlen); 328 SDL_memset(stream, this->spec.silence, this->hidden->mixlen);
413 this->PlayAudio(this); 329 DSOUND_PlayDevice(this);
414 } 330 }
415 this->WaitAudio(this); 331 DSOUND_WaitDevice(this);
416 332
417 /* Stop the looping sound buffer */ 333 /* Stop the looping sound buffer */
418 IDirectSoundBuffer_Stop(mixbuf); 334 IDirectSoundBuffer_Stop(this->hidden->mixbuf);
419 } 335 }
420 336
421 static void 337 static void
422 DX5_CloseAudio(_THIS) 338 DSOUND_CloseDevice(_THIS)
423 { 339 {
424 if (sound != NULL) { 340 if (this->hidden != NULL) {
425 if (mixbuf != NULL) { 341 if (this->hidden->sound != NULL) {
426 /* Clean up the audio buffer */ 342 if (this->hidden->mixbuf != NULL) {
427 IDirectSoundBuffer_Release(mixbuf); 343 /* Clean up the audio buffer */
428 mixbuf = NULL; 344 IDirectSoundBuffer_Release(this->hidden->mixbuf);
429 } 345 this->hidden->mixbuf = NULL;
430 if (audio_event != NULL) { 346 }
431 CloseHandle(audio_event); 347 IDirectSound_Release(this->hidden->sound);
432 audio_event = NULL; 348 this->hidden->sound = NULL;
433 } 349 }
434 IDirectSound_Release(sound); 350
435 sound = NULL; 351 SDL_free(this->hidden);
436 } 352 this->hidden = NULL;
437 } 353 }
438 354 }
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 355
517 /* This function tries to create a secondary audio buffer, and returns the 356 /* This function tries to create a secondary audio buffer, and returns the
518 number of audio chunks available in the created buffer. 357 number of audio chunks available in the created buffer.
519 */ 358 */
520 static int 359 static int
521 CreateSecondary(LPDIRECTSOUND sndObj, HWND focus, 360 CreateSecondary(_THIS, HWND focus, WAVEFORMATEX *wavefmt)
522 LPDIRECTSOUNDBUFFER * sndbuf, WAVEFORMATEX * wavefmt, 361 {
523 Uint32 chunksize) 362 LPDIRECTSOUND sndObj = this->hidden->sound;
524 { 363 LPDIRECTSOUNDBUFFER *sndbuf = this->hidden->mixbuf;
364 Uint32 chunksize = this->spec.size;
525 const int numchunks = 8; 365 const int numchunks = 8;
526 HRESULT result; 366 HRESULT result = DS_OK;
527 DSBUFFERDESC format; 367 DSBUFFERDESC format;
528 LPVOID pvAudioPtr1, pvAudioPtr2; 368 LPVOID pvAudioPtr1, pvAudioPtr2;
529 DWORD dwAudioBytes1, dwAudioBytes2; 369 DWORD dwAudioBytes1, dwAudioBytes2;
530 370
531 /* Try to set primary mixing privileges */ 371 /* Try to set primary mixing privileges */
536 result = IDirectSound_SetCooperativeLevel(sndObj, 376 result = IDirectSound_SetCooperativeLevel(sndObj,
537 GetDesktopWindow(), 377 GetDesktopWindow(),
538 DSSCL_NORMAL); 378 DSSCL_NORMAL);
539 } 379 }
540 if (result != DS_OK) { 380 if (result != DS_OK) {
541 #ifdef DEBUG_SOUND
542 SetDSerror("DirectSound SetCooperativeLevel", result); 381 SetDSerror("DirectSound SetCooperativeLevel", result);
543 #endif
544 return (-1); 382 return (-1);
545 } 383 }
546 384
547 /* Try to create the secondary buffer */ 385 /* Try to create the secondary buffer */
548 SDL_memset(&format, 0, sizeof(format)); 386 SDL_memset(&format, 0, sizeof(format));
549 format.dwSize = sizeof(format); 387 format.dwSize = sizeof(format);
550 format.dwFlags = DSBCAPS_GETCURRENTPOSITION2; 388 format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
551 #ifdef USE_POSITION_NOTIFY
552 format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
553 #endif
554 if (!focus) { 389 if (!focus) {
555 format.dwFlags |= DSBCAPS_GLOBALFOCUS; 390 format.dwFlags |= DSBCAPS_GLOBALFOCUS;
556 } else { 391 } else {
557 format.dwFlags |= DSBCAPS_STICKYFOCUS; 392 format.dwFlags |= DSBCAPS_STICKYFOCUS;
558 } 393 }
576 result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes, 411 result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
577 (LPVOID *) & pvAudioPtr1, &dwAudioBytes1, 412 (LPVOID *) & pvAudioPtr1, &dwAudioBytes1,
578 (LPVOID *) & pvAudioPtr2, &dwAudioBytes2, 413 (LPVOID *) & pvAudioPtr2, &dwAudioBytes2,
579 DSBLOCK_ENTIREBUFFER); 414 DSBLOCK_ENTIREBUFFER);
580 if (result == DS_OK) { 415 if (result == DS_OK) {
581 if (wavefmt->wBitsPerSample == 8) { 416 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, 417 IDirectSoundBuffer_Unlock(*sndbuf,
587 (LPVOID) pvAudioPtr1, dwAudioBytes1, 418 (LPVOID) pvAudioPtr1, dwAudioBytes1,
588 (LPVOID) pvAudioPtr2, dwAudioBytes2); 419 (LPVOID) pvAudioPtr2, dwAudioBytes2);
589 } 420 }
590 421
591 /* We're ready to go */ 422 /* We're ready to go */
592 return (numchunks); 423 return (numchunks);
593 } 424 }
594 425
595 /* This function tries to set position notify events on the mixing buffer */
596 #ifdef USE_POSITION_NOTIFY
597 static int 426 static int
598 CreateAudioEvent(_THIS) 427 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 { 428 {
653 HRESULT result; 429 HRESULT result;
654 WAVEFORMATEX waveformat; 430 WAVEFORMATEX waveformat;
655 431 int valid_format = 0;
656 /* Set basic WAVE format parameters */ 432 SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
433
434 /* !!! FIXME: handle devname */
435 /* !!! FIXME: handle iscapture */
436
437 /* Initialize all variables that we clean on shutdown */
438 this->hidden = (struct SDL_PrivateAudioData *)
439 SDL_malloc((sizeof *this->hidden));
440 if (this->hidden == NULL) {
441 SDL_OutOfMemory();
442 return 0;
443 }
444 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
445
446 while ((!valid_format) && (test_format)) {
447 switch (test_format) {
448 case AUDIO_U8:
449 case AUDIO_S16:
450 case AUDIO_S32:
451 this->spec.format = test_format;
452 valid_format = 1;
453 break;
454 }
455 test_format = SDL_NextAudioFormat();
456 }
457
458 if (!valid_format) {
459 DSOUND_CloseDevice(this);
460 SDL_SetError("DirectSound: Unsupported audio format");
461 return 0;
462 }
463
657 SDL_memset(&waveformat, 0, sizeof(waveformat)); 464 SDL_memset(&waveformat, 0, sizeof(waveformat));
658 waveformat.wFormatTag = WAVE_FORMAT_PCM; 465 waveformat.wFormatTag = WAVE_FORMAT_PCM;
659 466 waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
660 /* Determine the audio parameters from the AudioSpec */ 467 waveformat.nChannels = this->spec.channels;
661 switch (SDL_AUDIO_BITSIZE(spec->format)) { 468 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 = 469 waveformat.nBlockAlign =
687 waveformat.nChannels * (waveformat.wBitsPerSample / 8); 470 waveformat.nChannels * (waveformat.wBitsPerSample / 8);
688 waveformat.nAvgBytesPerSec = 471 waveformat.nAvgBytesPerSec =
689 waveformat.nSamplesPerSec * waveformat.nBlockAlign; 472 waveformat.nSamplesPerSec * waveformat.nBlockAlign;
690 473
691 /* Update the fragment size as size in bytes */ 474 /* Update the fragment size as size in bytes */
692 SDL_CalculateAudioSpec(spec); 475 SDL_CalculateAudioSpec(&this->spec);
693 476
694 /* Open the audio device */ 477 /* Open the audio device */
695 result = DSoundCreate(NULL, &sound, NULL); 478 result = DSoundCreate(NULL, &this->hidden->sound, NULL);
696 if (result != DS_OK) { 479 if (result != DS_OK) {
480 DSOUND_CloseDevice(this);
697 SetDSerror("DirectSoundCreate", result); 481 SetDSerror("DirectSoundCreate", result);
698 return (-1); 482 return 0;
699 } 483 }
700 484
701 /* Create the audio buffer to which we write */ 485 /* Create the audio buffer to which we write */
702 NUM_BUFFERS = -1; 486 this->hidden->num_buffers = CreateSecondary(this, mainwin, &waveformat);
703 #ifdef USE_PRIMARY_BUFFER 487 if (this->hidden->num_buffers < 0) {
704 if (mainwin) { 488 DSOUND_CloseDevice(this);
705 NUM_BUFFERS = CreatePrimary(sound, mainwin, &mixbuf, 489 return 0;
706 &waveformat, spec->size); 490 }
707 } 491
708 #endif /* USE_PRIMARY_BUFFER */ 492 /* The buffer will auto-start playing in DSOUND_WaitDevice() */
709 if (NUM_BUFFERS < 0) { 493 this->hidden->mixlen = this->spec.size;
710 NUM_BUFFERS = CreateSecondary(sound, mainwin, &mixbuf, 494
711 &waveformat, spec->size); 495 return 1; /* good to go. */
712 if (NUM_BUFFERS < 0) { 496 }
713 return (-1); 497
714 } 498
715 #ifdef DEBUG_SOUND 499 static void
716 fprintf(stderr, "Using secondary audio buffer\n"); 500 DSOUND_Deinitialize(void)
717 #endif 501 {
718 } 502 DSOUND_Unload();
719 #ifdef DEBUG_SOUND 503 }
720 else 504
721 fprintf(stderr, "Using primary audio buffer\n"); 505
722 #endif 506 static int
723 507 DSOUND_Init(SDL_AudioDriverImpl *impl)
724 /* The buffer will auto-start playing in DX5_WaitAudio() */ 508 {
725 lastchunk = 0; 509 /* Load DirectX */
726 mixlen = spec->size; 510 if (DSOUND_Load() < 0) {
727 511 return 0;
728 #ifdef USE_POSITION_NOTIFY 512 }
729 /* See if we can use DirectX 6 event notification */ 513
730 if (CreateAudioEvent(this) == 0) { 514 /* Set the function pointers */
731 this->WaitAudio = DX6_WaitAudio_EventWait; 515 impl->OpenDevice = DSOUND_OpenDevice;
732 } else { 516 impl->PlayDevice = DSOUND_PlayDevice;
733 this->WaitAudio = DX5_WaitAudio_BusyWait; 517 impl->WaitDevice = DSOUND_WaitDevice;
734 } 518 impl->WaitDone = DSOUND_WaitDone;
735 #endif 519 impl->ThreadInit = DSOUND_ThreadInit;
736 return (0); 520 impl->GetDeviceBuf = DSOUND_GetDeviceBuf;
737 } 521 impl->CloseDevice = DSOUND_CloseDevice;
522 impl->Deinitialize = DSOUND_Deinitialize;
523 impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME */
524
525 return 1;
526 }
527
528 AudioBootStrap DSOUND_bootstrap = {
529 "dsound", WINDOWS_OS_NAME "DirectSound",
530 DSOUND_Available, DSOUND_Init, 0
531 };
738 532
739 /* vi: set ts=4 sw=4 expandtab: */ 533 /* vi: set ts=4 sw=4 expandtab: */