src/audio/windx5/SDL_dx5audio.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 23 Jun 2006 08:48:24 +0000
branchSDL-1.3
changeset 1701 442248d4e738
parent 1668 4da1ee79c9af
permissions -rw-r--r--
Merged DirectSound dropout fix from SDL 1.2
     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@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
    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;
   103 
   104 static void
   105 DX5_Unload(void)
   106 {
   107     if (DSoundDLL != NULL) {
   108         FreeLibrary(DSoundDLL);
   109         DSoundCreate = NULL;
   110         DSoundDLL = NULL;
   111     }
   112 }
   113 static int
   114 DX5_Load(void)
   115 {
   116     int status;
   117 
   118     DX5_Unload();
   119     DSoundDLL = LoadLibrary(TEXT("DSOUND.DLL"));
   120     if (DSoundDLL != NULL) {
   121         DSoundCreate = (void *) GetProcAddress(DSoundDLL,
   122                                                TEXT("DirectSoundCreate"));
   123     }
   124     if (DSoundDLL && DSoundCreate) {
   125         status = 0;
   126     } else {
   127         DX5_Unload();
   128         status = -1;
   129     }
   130     return status;
   131 }
   132 
   133 static void
   134 Audio_DeleteDevice(SDL_AudioDevice * device)
   135 {
   136     DX5_Unload();
   137     SDL_free(device->hidden);
   138     SDL_free(device);
   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 
   186 static void
   187 SetDSerror(const char *function, int code)
   188 {
   189     static const char *error;
   190     static char errbuf[1024];
   191 
   192     errbuf[0] = 0;
   193     switch (code) {
   194     case E_NOINTERFACE:
   195         error =
   196             "Unsupported interface\n-- Is DirectX 5.0 or later installed?";
   197         break;
   198     case DSERR_ALLOCATED:
   199         error = "Audio device in use";
   200         break;
   201     case DSERR_BADFORMAT:
   202         error = "Unsupported audio format";
   203         break;
   204     case DSERR_BUFFERLOST:
   205         error = "Mixing buffer was lost";
   206         break;
   207     case DSERR_CONTROLUNAVAIL:
   208         error = "Control requested is not available";
   209         break;
   210     case DSERR_INVALIDCALL:
   211         error = "Invalid call for the current state";
   212         break;
   213     case DSERR_INVALIDPARAM:
   214         error = "Invalid parameter";
   215         break;
   216     case DSERR_NODRIVER:
   217         error = "No audio device found";
   218         break;
   219     case DSERR_OUTOFMEMORY:
   220         error = "Out of memory";
   221         break;
   222     case DSERR_PRIOLEVELNEEDED:
   223         error = "Caller doesn't have priority";
   224         break;
   225     case DSERR_UNSUPPORTED:
   226         error = "Function not supported";
   227         break;
   228     default:
   229         SDL_snprintf(errbuf, SDL_arraysize(errbuf),
   230                      "%s: Unknown DirectSound error: 0x%x", function, code);
   231         break;
   232     }
   233     if (!errbuf[0]) {
   234         SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
   235                      error);
   236     }
   237     SDL_SetError("%s", errbuf);
   238     return;
   239 }
   240 
   241 /* DirectSound needs to be associated with a window */
   242 static HWND mainwin = NULL;
   243 /* */
   244 void
   245 DX5_SoundFocus(HWND hwnd)
   246 {
   247     mainwin = hwnd;
   248 }
   249 
   250 static void
   251 DX5_ThreadInit(_THIS)
   252 {
   253     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
   254 }
   255 
   256 static void
   257 DX5_WaitAudio_BusyWait(_THIS)
   258 {
   259     DWORD status;
   260     DWORD cursor, junk;
   261     HRESULT result;
   262 
   263     /* Semi-busy wait, since we have no way of getting play notification
   264        on a primary mixing buffer located in hardware (DirectX 5.0)
   265      */
   266     result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor);
   267     if (result != DS_OK) {
   268         if (result == DSERR_BUFFERLOST) {
   269             IDirectSoundBuffer_Restore(mixbuf);
   270         }
   271 #ifdef DEBUG_SOUND
   272         SetDSerror("DirectSound GetCurrentPosition", result);
   273 #endif
   274         return;
   275     }
   276 
   277     while ((cursor / mixlen) == lastchunk) {
   278         /* FIXME: find out how much time is left and sleep that long */
   279         SDL_Delay(1);
   280 
   281         /* Try to restore a lost sound buffer */
   282         IDirectSoundBuffer_GetStatus(mixbuf, &status);
   283         if ((status & DSBSTATUS_BUFFERLOST)) {
   284             IDirectSoundBuffer_Restore(mixbuf);
   285             IDirectSoundBuffer_GetStatus(mixbuf, &status);
   286             if ((status & DSBSTATUS_BUFFERLOST)) {
   287                 break;
   288             }
   289         }
   290         if (!(status & DSBSTATUS_PLAYING)) {
   291             result = IDirectSoundBuffer_Play(mixbuf, 0, 0, DSBPLAY_LOOPING);
   292             if (result == DS_OK) {
   293                 continue;
   294             }
   295 #ifdef DEBUG_SOUND
   296             SetDSerror("DirectSound Play", result);
   297 #endif
   298             return;
   299         }
   300 
   301         /* Find out where we are playing */
   302         result = IDirectSoundBuffer_GetCurrentPosition(mixbuf,
   303                                                        &junk, &cursor);
   304         if (result != DS_OK) {
   305             SetDSerror("DirectSound GetCurrentPosition", result);
   306             return;
   307         }
   308     }
   309 }
   310 
   311 #ifdef USE_POSITION_NOTIFY
   312 static void
   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 {
   343     /* Unlock the buffer, allowing it to play */
   344     if (locked_buf) {
   345         IDirectSoundBuffer_Unlock(mixbuf, locked_buf, mixlen, NULL, 0);
   346     }
   347 
   348 }
   349 
   350 static Uint8 *
   351 DX5_GetAudioBuf(_THIS)
   352 {
   353     DWORD cursor, junk;
   354     HRESULT result;
   355     DWORD rawlen;
   356 
   357     /* Figure out which blocks to fill next */
   358     locked_buf = NULL;
   359     result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &junk, &cursor);
   360     if (result == DSERR_BUFFERLOST) {
   361         IDirectSoundBuffer_Restore(mixbuf);
   362         result = IDirectSoundBuffer_GetCurrentPosition(mixbuf,
   363                                                        &junk, &cursor);
   364     }
   365     if (result != DS_OK) {
   366         SetDSerror("DirectSound GetCurrentPosition", result);
   367         return (NULL);
   368     }
   369     cursor /= mixlen;
   370 #ifdef DEBUG_SOUND
   371     /* Detect audio dropouts */
   372     {
   373         DWORD spot = cursor;
   374         if (spot < lastchunk) {
   375             spot += NUM_BUFFERS;
   376         }
   377         if (spot > lastchunk + 1) {
   378             fprintf(stderr, "Audio dropout, missed %d fragments\n",
   379                     (spot - (lastchunk + 1)));
   380         }
   381     }
   382 #endif
   383     lastchunk = cursor;
   384     cursor = (cursor + 1) % NUM_BUFFERS;
   385     cursor *= mixlen;
   386 
   387     /* Lock the audio buffer */
   388     result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen,
   389                                      (LPVOID *) & locked_buf, &rawlen, NULL,
   390                                      &junk, 0);
   391     if (result == DSERR_BUFFERLOST) {
   392         IDirectSoundBuffer_Restore(mixbuf);
   393         result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen,
   394                                          (LPVOID *) & locked_buf, &rawlen,
   395                                          NULL, &junk, 0);
   396     }
   397     if (result != DS_OK) {
   398         SetDSerror("DirectSound Lock", result);
   399         return (NULL);
   400     }
   401     return (locked_buf);
   402 }
   403 
   404 static void
   405 DX5_WaitDone(_THIS)
   406 {
   407     Uint8 *stream;
   408 
   409     /* Wait for the playing chunk to finish */
   410     stream = this->GetAudioBuf(this);
   411     if (stream != NULL) {
   412         SDL_memset(stream, silence, mixlen);
   413         this->PlayAudio(this);
   414     }
   415     this->WaitAudio(this);
   416 
   417     /* Stop the looping sound buffer */
   418     IDirectSoundBuffer_Stop(mixbuf);
   419 }
   420 
   421 static void
   422 DX5_CloseAudio(_THIS)
   423 {
   424     if (sound != NULL) {
   425         if (mixbuf != NULL) {
   426             /* Clean up the audio buffer */
   427             IDirectSoundBuffer_Release(mixbuf);
   428             mixbuf = NULL;
   429         }
   430         if (audio_event != NULL) {
   431             CloseHandle(audio_event);
   432             audio_event = NULL;
   433         }
   434         IDirectSound_Release(sound);
   435         sound = NULL;
   436     }
   437 }
   438 
   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 
   517 /* This function tries to create a secondary audio buffer, and returns the
   518    number of audio chunks available in the created buffer.
   519 */
   520 static int
   521 CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
   522                 LPDIRECTSOUNDBUFFER * sndbuf, WAVEFORMATEX * wavefmt,
   523                 Uint32 chunksize)
   524 {
   525     const int numchunks = 8;
   526     HRESULT result;
   527     DSBUFFERDESC format;
   528     LPVOID pvAudioPtr1, pvAudioPtr2;
   529     DWORD dwAudioBytes1, dwAudioBytes2;
   530 
   531     /* Try to set primary mixing privileges */
   532     if (focus) {
   533         result = IDirectSound_SetCooperativeLevel(sndObj,
   534                                                   focus, DSSCL_PRIORITY);
   535     } else {
   536         result = IDirectSound_SetCooperativeLevel(sndObj,
   537                                                   GetDesktopWindow(),
   538                                                   DSSCL_NORMAL);
   539     }
   540     if (result != DS_OK) {
   541 #ifdef DEBUG_SOUND
   542         SetDSerror("DirectSound SetCooperativeLevel", result);
   543 #endif
   544         return (-1);
   545     }
   546 
   547     /* Try to create the secondary buffer */
   548     SDL_memset(&format, 0, sizeof(format));
   549     format.dwSize = sizeof(format);
   550     format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
   551 #ifdef USE_POSITION_NOTIFY
   552     format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
   553 #endif
   554     if (!focus) {
   555         format.dwFlags |= DSBCAPS_GLOBALFOCUS;
   556     } else {
   557         format.dwFlags |= DSBCAPS_STICKYFOCUS;
   558     }
   559     format.dwBufferBytes = numchunks * chunksize;
   560     if ((format.dwBufferBytes < DSBSIZE_MIN) ||
   561         (format.dwBufferBytes > DSBSIZE_MAX)) {
   562         SDL_SetError("Sound buffer size must be between %d and %d",
   563                      DSBSIZE_MIN / numchunks, DSBSIZE_MAX / numchunks);
   564         return (-1);
   565     }
   566     format.dwReserved = 0;
   567     format.lpwfxFormat = wavefmt;
   568     result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
   569     if (result != DS_OK) {
   570         SetDSerror("DirectSound CreateSoundBuffer", result);
   571         return (-1);
   572     }
   573     IDirectSoundBuffer_SetFormat(*sndbuf, wavefmt);
   574 
   575     /* Silence the initial audio buffer */
   576     result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
   577                                      (LPVOID *) & pvAudioPtr1, &dwAudioBytes1,
   578                                      (LPVOID *) & pvAudioPtr2, &dwAudioBytes2,
   579                                      DSBLOCK_ENTIREBUFFER);
   580     if (result == DS_OK) {
   581         if (wavefmt->wBitsPerSample == 8) {
   582             SDL_memset(pvAudioPtr1, 0x80, dwAudioBytes1);
   583         } else {
   584             SDL_memset(pvAudioPtr1, 0x00, dwAudioBytes1);
   585         }
   586         IDirectSoundBuffer_Unlock(*sndbuf,
   587                                   (LPVOID) pvAudioPtr1, dwAudioBytes1,
   588                                   (LPVOID) pvAudioPtr2, dwAudioBytes2);
   589     }
   590 
   591     /* We're ready to go */
   592     return (numchunks);
   593 }
   594 
   595 /* This function tries to set position notify events on the mixing buffer */
   596 #ifdef USE_POSITION_NOTIFY
   597 static int
   598 CreateAudioEvent(_THIS)
   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 {
   653     HRESULT result;
   654     WAVEFORMATEX waveformat;
   655 
   656     /* Set basic WAVE format parameters */
   657     SDL_memset(&waveformat, 0, sizeof(waveformat));
   658     waveformat.wFormatTag = WAVE_FORMAT_PCM;
   659 
   660     /* Determine the audio parameters from the AudioSpec */
   661     switch (spec->format & 0xFF) {
   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     default:
   675         SDL_SetError("Unsupported audio format");
   676         return (-1);
   677     }
   678     waveformat.nChannels = spec->channels;
   679     waveformat.nSamplesPerSec = spec->freq;
   680     waveformat.nBlockAlign =
   681         waveformat.nChannels * (waveformat.wBitsPerSample / 8);
   682     waveformat.nAvgBytesPerSec =
   683         waveformat.nSamplesPerSec * waveformat.nBlockAlign;
   684 
   685     /* Update the fragment size as size in bytes */
   686     SDL_CalculateAudioSpec(spec);
   687 
   688     /* Open the audio device */
   689     result = DSoundCreate(NULL, &sound, NULL);
   690     if (result != DS_OK) {
   691         SetDSerror("DirectSoundCreate", result);
   692         return (-1);
   693     }
   694 
   695     /* Create the audio buffer to which we write */
   696     NUM_BUFFERS = -1;
   697 #ifdef USE_PRIMARY_BUFFER
   698     if (mainwin) {
   699         NUM_BUFFERS = CreatePrimary(sound, mainwin, &mixbuf,
   700                                     &waveformat, spec->size);
   701     }
   702 #endif /* USE_PRIMARY_BUFFER */
   703     if (NUM_BUFFERS < 0) {
   704         NUM_BUFFERS = CreateSecondary(sound, mainwin, &mixbuf,
   705                                       &waveformat, spec->size);
   706         if (NUM_BUFFERS < 0) {
   707             return (-1);
   708         }
   709 #ifdef DEBUG_SOUND
   710         fprintf(stderr, "Using secondary audio buffer\n");
   711 #endif
   712     }
   713 #ifdef DEBUG_SOUND
   714     else
   715         fprintf(stderr, "Using primary audio buffer\n");
   716 #endif
   717 
   718     /* The buffer will auto-start playing in DX5_WaitAudio() */
   719     lastchunk = 0;
   720     mixlen = spec->size;
   721 
   722 #ifdef USE_POSITION_NOTIFY
   723     /* See if we can use DirectX 6 event notification */
   724     if (CreateAudioEvent(this) == 0) {
   725         this->WaitAudio = DX6_WaitAudio_EventWait;
   726     } else {
   727         this->WaitAudio = DX5_WaitAudio_BusyWait;
   728     }
   729 #endif
   730     return (0);
   731 }
   732 
   733 /* vi: set ts=4 sw=4 expandtab: */