1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2006 Sam Lantinga 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 19 Sam Lantinga 20 slouken (at) libsdl.org 21 */ 22 #include "SDL_config.h" 23 24 /* Allow access to a raw mixing buffer */ 25 26 #include "SDL_timer.h" 27 #include "SDL_audio.h" 28 #include "../SDL_audio_c.h" 29 #include "SDL_dx5audio.h" 30 31 /* Define this if you want to use DirectX 6 DirectSoundNotify interface */ 32 //#define USE_POSITION_NOTIFY 33 34 /* 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 Audio_Available(void) 52 { 53 HINSTANCE DSoundDLL; 54 int dsound_ok; 55 56 /* Version check DSOUND.DLL (Is DirectX okay?) */ 57 dsound_ok = 0; 58 DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL")); 59 if ( DSoundDLL != NULL ) { 60 /* We just use basic DirectSound, we're okay */ 61 /* Yay! */ 62 /* Unfortunately, the sound drivers on NT have 63 higher latencies than the audio buffers used 64 by many SDL applications, so there are gaps 65 in the audio - it sounds terrible. Punt for now. 66 */ 67 OSVERSIONINFO ver; 68 ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); 69 GetVersionEx(&ver); 70 switch (ver.dwPlatformId) { 71 case VER_PLATFORM_WIN32_NT: 72 if ( ver.dwMajorVersion > 4 ) { 73 /* Win2K */ 74 dsound_ok = 1; 75 } else { 76 /* WinNT */ 77 dsound_ok = 0; 78 } 79 break; 80 default: 81 /* Win95 or Win98 */ 82 dsound_ok = 1; 83 break; 84 } 85 /* Now check for DirectX 5 or better - otherwise 86 * we will fail later in DX5_OpenAudio without a chance 87 * to fall back to the DIB driver. */ 88 if (dsound_ok) { 89 /* DirectSoundCaptureCreate was added in DX5 */ 90 if (!GetProcAddress(DSoundDLL, TEXT("DirectSoundCaptureCreate"))) 91 dsound_ok = 0; 92 93 } 94 /* Clean up.. */ 95 FreeLibrary(DSoundDLL); 96 } 97 return(dsound_ok); 98 } 99 100 /* Functions for loading the DirectX functions dynamically */ 101 static HINSTANCE DSoundDLL = NULL; 102 103 static void DX5_Unload(void) 104 { 105 if ( DSoundDLL != NULL ) { 106 FreeLibrary(DSoundDLL); 107 DSoundCreate = NULL; 108 DSoundDLL = NULL; 109 } 110 } 111 static int DX5_Load(void) 112 { 113 int status; 114 115 DX5_Unload(); 116 DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL")); 117 if ( DSoundDLL != NULL ) { 118 DSoundCreate = (void *)GetProcAddress(DSoundDLL, 119 TEXT("DirectSoundCreate")); 120 } 121 if ( DSoundDLL && DSoundCreate ) { 122 status = 0; 123 } else { 124 DX5_Unload(); 125 status = -1; 126 } 127 return status; 128 } 129 130 static void Audio_DeleteDevice(SDL_AudioDevice *device) 131 { 132 DX5_Unload(); 133 SDL_free(device->hidden); 134 SDL_free(device); 135 } 136 137 static SDL_AudioDevice *Audio_CreateDevice(int devindex) 138 { 139 SDL_AudioDevice *this; 140 141 /* Load DirectX */ 142 if ( DX5_Load() < 0 ) { 143 return(NULL); 144 } 145 146 /* Initialize all variables that we clean on shutdown */ 147 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice)); 148 if ( this ) { 149 SDL_memset(this, 0, (sizeof *this)); 150 this->hidden = (struct SDL_PrivateAudioData *) 151 SDL_malloc((sizeof *this->hidden)); 152 } 153 if ( (this == NULL) || (this->hidden == NULL) ) { 154 SDL_OutOfMemory(); 155 if ( this ) { 156 SDL_free(this); 157 } 158 return(0); 159 } 160 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); 161 162 /* Set the function pointers */ 163 this->OpenAudio = DX5_OpenAudio; 164 this->ThreadInit = DX5_ThreadInit; 165 this->WaitAudio = DX5_WaitAudio_BusyWait; 166 this->PlayAudio = DX5_PlayAudio; 167 this->GetAudioBuf = DX5_GetAudioBuf; 168 this->WaitDone = DX5_WaitDone; 169 this->CloseAudio = DX5_CloseAudio; 170 171 this->free = Audio_DeleteDevice; 172 173 return this; 174 } 175 176 AudioBootStrap DSOUND_bootstrap = { 177 "dsound", "Win95/98/2000 DirectSound", 178 Audio_Available, Audio_CreateDevice 179 }; 180 181 static void SetDSerror(const char *function, int code) 182 { 183 static const char *error; 184 static char errbuf[1024]; 185 186 errbuf[0] = 0; 187 switch (code) { 188 case E_NOINTERFACE: 189 error = 190 "Unsupported interface\n-- Is DirectX 5.0 or later installed?"; 191 break; 192 case DSERR_ALLOCATED: 193 error = "Audio device in use"; 194 break; 195 case DSERR_BADFORMAT: 196 error = "Unsupported audio format"; 197 break; 198 case DSERR_BUFFERLOST: 199 error = "Mixing buffer was lost"; 200 break; 201 case DSERR_CONTROLUNAVAIL: 202 error = "Control requested is not available"; 203 break; 204 case DSERR_INVALIDCALL: 205 error = "Invalid call for the current state"; 206 break; 207 case DSERR_INVALIDPARAM: 208 error = "Invalid parameter"; 209 break; 210 case DSERR_NODRIVER: 211 error = "No audio device found"; 212 break; 213 case DSERR_OUTOFMEMORY: 214 error = "Out of memory"; 215 break; 216 case DSERR_PRIOLEVELNEEDED: 217 error = "Caller doesn't have priority"; 218 break; 219 case DSERR_UNSUPPORTED: 220 error = "Function not supported"; 221 break; 222 default: 223 SDL_snprintf(errbuf, SDL_arraysize(errbuf), 224 "%s: Unknown DirectSound error: 0x%x", 225 function, code); 226 break; 227 } 228 if ( ! errbuf[0] ) { 229 SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function, error); 230 } 231 SDL_SetError("%s", errbuf); 232 return; 233 } 234 235 /* DirectSound needs to be associated with a window */ 236 static HWND mainwin = NULL; 237 /* */ 238 void DX5_SoundFocus(HWND hwnd) 239 { 240 mainwin = hwnd; 241 } 242 243 static void DX5_ThreadInit(_THIS) 244 { 245 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); 246 } 247 248 static void DX5_WaitAudio_BusyWait(_THIS) 249 { 250 DWORD status; 251 DWORD cursor, junk; 252 HRESULT result; 253 254 /* Semi-busy wait, since we have no way of getting play notification 255 on a primary mixing buffer located in hardware (DirectX 5.0) 256 */ 257 result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor); 258 if ( result != DS_OK ) { 259 if ( result == DSERR_BUFFERLOST ) { 260 IDirectSoundBuffer_Restore(mixbuf); 261 } 262 #ifdef DEBUG_SOUND 263 SetDSerror("DirectSound GetCurrentPosition", result); 264 #endif 265 return; 266 } 267 268 while ( (cursor/mixlen) == lastchunk ) { 269 /* FIXME: find out how much time is left and sleep that long */ 270 SDL_Delay(1); 271 272 /* Try to restore a lost sound buffer */ 273 IDirectSoundBuffer_GetStatus(mixbuf, &status); 274 if ( (status&DSBSTATUS_BUFFERLOST) ) { 275 IDirectSoundBuffer_Restore(mixbuf); 276 IDirectSoundBuffer_GetStatus(mixbuf, &status); 277 if ( (status&DSBSTATUS_BUFFERLOST) ) { 278 break; 279 } 280 } 281 if ( ! (status&DSBSTATUS_PLAYING) ) { 282 result = IDirectSoundBuffer_Play(mixbuf, 0, 0, DSBPLAY_LOOPING); 283 if ( result == DS_OK ) { 284 continue; 285 } 286 #ifdef DEBUG_SOUND 287 SetDSerror("DirectSound Play", result); 288 #endif 289 return; 290 } 291 292 /* Find out where we are playing */ 293 result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, 294 &junk, &cursor); 295 if ( result != DS_OK ) { 296 SetDSerror("DirectSound GetCurrentPosition", result); 297 return; 298 } 299 } 300 } 301 302 #ifdef USE_POSITION_NOTIFY 303 static void DX6_WaitAudio_EventWait(_THIS) 304 { 305 DWORD status; 306 HRESULT result; 307 308 /* Try to restore a lost sound buffer */ 309 IDirectSoundBuffer_GetStatus(mixbuf, &status); 310 if ( (status&DSBSTATUS_BUFFERLOST) ) { 311 IDirectSoundBuffer_Restore(mixbuf); 312 IDirectSoundBuffer_GetStatus(mixbuf, &status); 313 if ( (status&DSBSTATUS_BUFFERLOST) ) { 314 return; 315 } 316 } 317 if ( ! (status&DSBSTATUS_PLAYING) ) { 318 result = IDirectSoundBuffer_Play(mixbuf, 0, 0, DSBPLAY_LOOPING); 319 if ( result != DS_OK ) { 320 #ifdef DEBUG_SOUND 321 SetDSerror("DirectSound Play", result); 322 #endif 323 return; 324 } 325 } 326 WaitForSingleObject(audio_event, INFINITE); 327 } 328 #endif /* USE_POSITION_NOTIFY */ 329 330 static void DX5_PlayAudio(_THIS) 331 { 332 /* Unlock the buffer, allowing it to play */ 333 if ( locked_buf ) { 334 IDirectSoundBuffer_Unlock(mixbuf, locked_buf, mixlen, NULL, 0); 335 } 336 337 } 338 339 static Uint8 *DX5_GetAudioBuf(_THIS) 340 { 341 DWORD cursor, junk; 342 HRESULT result; 343 DWORD rawlen; 344 345 /* Figure out which blocks to fill next */ 346 locked_buf = NULL; 347 result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor); 348 if ( result == DSERR_BUFFERLOST ) { 349 IDirectSoundBuffer_Restore(mixbuf); 350 result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, 351 &junk, &cursor); 352 } 353 if ( result != DS_OK ) { 354 SetDSerror("DirectSound GetCurrentPosition", result); 355 return(NULL); 356 } 357 cursor /= mixlen; 358 #ifdef DEBUG_SOUND 359 /* Detect audio dropouts */ 360 { DWORD spot = cursor; 361 if ( spot < lastchunk ) { 362 spot += NUM_BUFFERS; 363 } 364 if ( spot > lastchunk+1 ) { 365 fprintf(stderr, "Audio dropout, missed %d fragments\n", 366 (spot - (lastchunk+1))); 367 } 368 } 369 #endif 370 lastchunk = cursor; 371 cursor = (cursor+1)%NUM_BUFFERS; 372 cursor *= mixlen; 373 374 /* Lock the audio buffer */ 375 result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen, 376 (LPVOID *)&locked_buf, &rawlen, NULL, &junk, 0); 377 if ( result == DSERR_BUFFERLOST ) { 378 IDirectSoundBuffer_Restore(mixbuf); 379 result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen, 380 (LPVOID *)&locked_buf, &rawlen, NULL, &junk, 0); 381 } 382 if ( result != DS_OK ) { 383 SetDSerror("DirectSound Lock", result); 384 return(NULL); 385 } 386 return(locked_buf); 387 } 388 389 static void DX5_WaitDone(_THIS) 390 { 391 Uint8 *stream; 392 393 /* Wait for the playing chunk to finish */ 394 stream = this->GetAudioBuf(this); 395 if ( stream != NULL ) { 396 SDL_memset(stream, silence, mixlen); 397 this->PlayAudio(this); 398 } 399 this->WaitAudio(this); 400 401 /* Stop the looping sound buffer */ 402 IDirectSoundBuffer_Stop(mixbuf); 403 } 404 405 static void DX5_CloseAudio(_THIS) 406 { 407 if ( sound != NULL ) { 408 if ( mixbuf != NULL ) { 409 /* Clean up the audio buffer */ 410 IDirectSoundBuffer_Release(mixbuf); 411 mixbuf = NULL; 412 } 413 if ( audio_event != NULL ) { 414 CloseHandle(audio_event); 415 audio_event = NULL; 416 } 417 IDirectSound_Release(sound); 418 sound = NULL; 419 } 420 } 421 422 #ifdef USE_PRIMARY_BUFFER 423 /* This function tries to create a primary audio buffer, and returns the 424 number of audio chunks available in the created buffer. 425 */ 426 static int CreatePrimary(LPDIRECTSOUND sndObj, HWND focus, 427 LPDIRECTSOUNDBUFFER *sndbuf, WAVEFORMATEX *wavefmt, Uint32 chunksize) 428 { 429 HRESULT result; 430 DSBUFFERDESC format; 431 DSBCAPS caps; 432 int numchunks; 433 434 /* Try to set primary mixing privileges */ 435 result = IDirectSound_SetCooperativeLevel(sndObj, focus, 436 DSSCL_WRITEPRIMARY); 437 if ( result != DS_OK ) { 438 #ifdef DEBUG_SOUND 439 SetDSerror("DirectSound SetCooperativeLevel", result); 440 #endif 441 return(-1); 442 } 443 444 /* Try to create the primary buffer */ 445 SDL_memset(&format, 0, sizeof(format)); 446 format.dwSize = sizeof(format); 447 format.dwFlags=(DSBCAPS_PRIMARYBUFFER|DSBCAPS_GETCURRENTPOSITION2); 448 format.dwFlags |= DSBCAPS_STICKYFOCUS; 449 #ifdef USE_POSITION_NOTIFY 450 format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY; 451 #endif 452 result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL); 453 if ( result != DS_OK ) { 454 #ifdef DEBUG_SOUND 455 SetDSerror("DirectSound CreateSoundBuffer", result); 456 #endif 457 return(-1); 458 } 459 460 /* Check the size of the fragment buffer */ 461 SDL_memset(&caps, 0, sizeof(caps)); 462 caps.dwSize = sizeof(caps); 463 result = IDirectSoundBuffer_GetCaps(*sndbuf, &caps); 464 if ( result != DS_OK ) { 465 #ifdef DEBUG_SOUND 466 SetDSerror("DirectSound GetCaps", result); 467 #endif 468 IDirectSoundBuffer_Release(*sndbuf); 469 return(-1); 470 } 471 if ( (chunksize > caps.dwBufferBytes) || 472 ((caps.dwBufferBytes%chunksize) != 0) ) { 473 /* The primary buffer size is not a multiple of 'chunksize' 474 -- this hopefully doesn't happen when 'chunksize' is a 475 power of 2. 476 */ 477 IDirectSoundBuffer_Release(*sndbuf); 478 SDL_SetError( 479 "Primary buffer size is: %d, cannot break it into chunks of %d bytes\n", 480 caps.dwBufferBytes, chunksize); 481 return(-1); 482 } 483 numchunks = (caps.dwBufferBytes/chunksize); 484 485 /* Set the primary audio format */ 486 result = IDirectSoundBuffer_SetFormat(*sndbuf, wavefmt); 487 if ( result != DS_OK ) { 488 #ifdef DEBUG_SOUND 489 SetDSerror("DirectSound SetFormat", result); 490 #endif 491 IDirectSoundBuffer_Release(*sndbuf); 492 return(-1); 493 } 494 return(numchunks); 495 } 496 #endif /* USE_PRIMARY_BUFFER */ 497 498 /* This function tries to create a secondary audio buffer, and returns the 499 number of audio chunks available in the created buffer. 500 */ 501 static int CreateSecondary(LPDIRECTSOUND sndObj, HWND focus, 502 LPDIRECTSOUNDBUFFER *sndbuf, WAVEFORMATEX *wavefmt, Uint32 chunksize) 503 { 504 const int numchunks = 8; 505 HRESULT result; 506 DSBUFFERDESC format; 507 LPVOID pvAudioPtr1, pvAudioPtr2; 508 DWORD dwAudioBytes1, dwAudioBytes2; 509 510 /* Try to set primary mixing privileges */ 511 if ( focus ) { 512 result = IDirectSound_SetCooperativeLevel(sndObj, 513 focus, DSSCL_PRIORITY); 514 } else { 515 result = IDirectSound_SetCooperativeLevel(sndObj, 516 GetDesktopWindow(), DSSCL_NORMAL); 517 } 518 if ( result != DS_OK ) { 519 #ifdef DEBUG_SOUND 520 SetDSerror("DirectSound SetCooperativeLevel", result); 521 #endif 522 return(-1); 523 } 524 525 /* Try to create the secondary buffer */ 526 SDL_memset(&format, 0, sizeof(format)); 527 format.dwSize = sizeof(format); 528 format.dwFlags = DSBCAPS_GETCURRENTPOSITION2; 529 #ifdef USE_POSITION_NOTIFY 530 format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY; 531 #endif 532 if ( ! focus ) { 533 format.dwFlags |= DSBCAPS_GLOBALFOCUS; 534 } else { 535 format.dwFlags |= DSBCAPS_STICKYFOCUS; 536 } 537 format.dwBufferBytes = numchunks*chunksize; 538 if ( (format.dwBufferBytes < DSBSIZE_MIN) || 539 (format.dwBufferBytes > DSBSIZE_MAX) ) { 540 SDL_SetError("Sound buffer size must be between %d and %d", 541 DSBSIZE_MIN/numchunks, DSBSIZE_MAX/numchunks); 542 return(-1); 543 } 544 format.dwReserved = 0; 545 format.lpwfxFormat = wavefmt; 546 result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL); 547 if ( result != DS_OK ) { 548 SetDSerror("DirectSound CreateSoundBuffer", result); 549 return(-1); 550 } 551 IDirectSoundBuffer_SetFormat(*sndbuf, wavefmt); 552 553 /* Silence the initial audio buffer */ 554 result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes, 555 (LPVOID *)&pvAudioPtr1, &dwAudioBytes1, 556 (LPVOID *)&pvAudioPtr2, &dwAudioBytes2, 557 DSBLOCK_ENTIREBUFFER); 558 if ( result == DS_OK ) { 559 if ( wavefmt->wBitsPerSample == 8 ) { 560 SDL_memset(pvAudioPtr1, 0x80, dwAudioBytes1); 561 } else { 562 SDL_memset(pvAudioPtr1, 0x00, dwAudioBytes1); 563 } 564 IDirectSoundBuffer_Unlock(*sndbuf, 565 (LPVOID)pvAudioPtr1, dwAudioBytes1, 566 (LPVOID)pvAudioPtr2, dwAudioBytes2); 567 } 568 569 /* We're ready to go */ 570 return(numchunks); 571 } 572 573 /* This function tries to set position notify events on the mixing buffer */ 574 #ifdef USE_POSITION_NOTIFY 575 static int CreateAudioEvent(_THIS) 576 { 577 LPDIRECTSOUNDNOTIFY notify; 578 DSBPOSITIONNOTIFY *notify_positions; 579 int i, retval; 580 HRESULT result; 581 582 /* Default to fail on exit */ 583 retval = -1; 584 notify = NULL; 585 586 /* Query for the interface */ 587 result = IDirectSoundBuffer_QueryInterface(mixbuf, 588 &IID_IDirectSoundNotify, (void *)¬ify); 589 if ( result != DS_OK ) { 590 goto done; 591 } 592 593 /* Allocate the notify structures */ 594 notify_positions = (DSBPOSITIONNOTIFY *)SDL_malloc(NUM_BUFFERS* 595 sizeof(*notify_positions)); 596 if ( notify_positions == NULL ) { 597 goto done; 598 } 599 600 /* Create the notify event */ 601 audio_event = CreateEvent(NULL, FALSE, FALSE, NULL); 602 if ( audio_event == NULL ) { 603 goto done; 604 } 605 606 /* Set up the notify structures */ 607 for ( i=0; i<NUM_BUFFERS; ++i ) { 608 notify_positions[i].dwOffset = i*mixlen; 609 notify_positions[i].hEventNotify = audio_event; 610 } 611 result = IDirectSoundNotify_SetNotificationPositions(notify, 612 NUM_BUFFERS, notify_positions); 613 if ( result == DS_OK ) { 614 retval = 0; 615 } 616 done: 617 if ( notify != NULL ) { 618 IDirectSoundNotify_Release(notify); 619 } 620 return(retval); 621 } 622 #endif /* USE_POSITION_NOTIFY */ 623 624 static int DX5_OpenAudio(_THIS, SDL_AudioSpec *spec) 625 { 626 HRESULT result; 627 WAVEFORMATEX waveformat; 628 629 /* Set basic WAVE format parameters */ 630 SDL_memset(&waveformat, 0, sizeof(waveformat)); 631 waveformat.wFormatTag = WAVE_FORMAT_PCM; 632 633 /* Determine the audio parameters from the AudioSpec */ 634 switch ( spec->format & 0xFF ) { 635 case 8: 636 /* Unsigned 8 bit audio data */ 637 spec->format = AUDIO_U8; 638 silence = 0x80; 639 waveformat.wBitsPerSample = 8; 640 break; 641 case 16: 642 /* Signed 16 bit audio data */ 643 spec->format = AUDIO_S16; 644 silence = 0x00; 645 waveformat.wBitsPerSample = 16; 646 break; 647 default: 648 SDL_SetError("Unsupported audio format"); 649 return(-1); 650 } 651 waveformat.nChannels = spec->channels; 652 waveformat.nSamplesPerSec = spec->freq; 653 waveformat.nBlockAlign = 654 waveformat.nChannels * (waveformat.wBitsPerSample/8); 655 waveformat.nAvgBytesPerSec = 656 waveformat.nSamplesPerSec * waveformat.nBlockAlign; 657 658 /* Update the fragment size as size in bytes */ 659 SDL_CalculateAudioSpec(spec); 660 661 /* Open the audio device */ 662 result = DSoundCreate(NULL, &sound, NULL); 663 if ( result != DS_OK ) { 664 SetDSerror("DirectSoundCreate", result); 665 return(-1); 666 } 667 668 /* Create the audio buffer to which we write */ 669 NUM_BUFFERS = -1; 670 #ifdef USE_PRIMARY_BUFFER 671 if ( mainwin ) { 672 NUM_BUFFERS = CreatePrimary(sound, mainwin, &mixbuf, 673 &waveformat, spec->size); 674 } 675 #endif /* USE_PRIMARY_BUFFER */ 676 if ( NUM_BUFFERS < 0 ) { 677 NUM_BUFFERS = CreateSecondary(sound, mainwin, &mixbuf, 678 &waveformat, spec->size); 679 if ( NUM_BUFFERS < 0 ) { 680 return(-1); 681 } 682 #ifdef DEBUG_SOUND 683 fprintf(stderr, "Using secondary audio buffer\n"); 684 #endif 685 } 686 #ifdef DEBUG_SOUND 687 else 688 fprintf(stderr, "Using primary audio buffer\n"); 689 #endif 690 691 /* The buffer will auto-start playing in DX5_WaitAudio() */ 692 lastchunk = 0; 693 mixlen = spec->size; 694 695 #ifdef USE_POSITION_NOTIFY 696 /* See if we can use DirectX 6 event notification */ 697 if ( CreateAudioEvent(this) == 0 ) { 698 this->WaitAudio = DX6_WaitAudio_EventWait; 699 } else { 700 this->WaitAudio = DX5_WaitAudio_BusyWait; 701 } 702 #endif 703 return(0); 704 } 705 706