src/audio/windx5/SDL_dx5audio.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 29 May 2006 04:04:35 +0000
branchSDL-1.3
changeset 1668 4da1ee79c9af
parent 1662 782fd950bd46
child 1701 442248d4e738
permissions -rw-r--r--
more tweaking indent options
     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, &cursor, &junk);
   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     cursor /= mixlen;
   277 
   278     while (cursor == playing) {
   279         /* FIXME: find out how much time is left and sleep that long */
   280         SDL_Delay(10);
   281 
   282         /* Try to restore a lost sound buffer */
   283         IDirectSoundBuffer_GetStatus(mixbuf, &status);
   284         if ((status & DSBSTATUS_BUFFERLOST)) {
   285             IDirectSoundBuffer_Restore(mixbuf);
   286             IDirectSoundBuffer_GetStatus(mixbuf, &status);
   287             if ((status & DSBSTATUS_BUFFERLOST)) {
   288                 break;
   289             }
   290         }
   291         if (!(status & DSBSTATUS_PLAYING)) {
   292             result = IDirectSoundBuffer_Play(mixbuf, 0, 0, DSBPLAY_LOOPING);
   293             if (result == DS_OK) {
   294                 continue;
   295             }
   296 #ifdef DEBUG_SOUND
   297             SetDSerror("DirectSound Play", result);
   298 #endif
   299             return;
   300         }
   301 
   302         /* Find out where we are playing */
   303         result = IDirectSoundBuffer_GetCurrentPosition(mixbuf,
   304                                                        &cursor, &junk);
   305         if (result != DS_OK) {
   306             SetDSerror("DirectSound GetCurrentPosition", result);
   307             return;
   308         }
   309         cursor /= mixlen;
   310     }
   311 }
   312 
   313 #ifdef USE_POSITION_NOTIFY
   314 static void
   315 DX6_WaitAudio_EventWait(_THIS)
   316 {
   317     DWORD status;
   318     HRESULT result;
   319 
   320     /* Try to restore a lost sound buffer */
   321     IDirectSoundBuffer_GetStatus(mixbuf, &status);
   322     if ((status & DSBSTATUS_BUFFERLOST)) {
   323         IDirectSoundBuffer_Restore(mixbuf);
   324         IDirectSoundBuffer_GetStatus(mixbuf, &status);
   325         if ((status & DSBSTATUS_BUFFERLOST)) {
   326             return;
   327         }
   328     }
   329     if (!(status & DSBSTATUS_PLAYING)) {
   330         result = IDirectSoundBuffer_Play(mixbuf, 0, 0, DSBPLAY_LOOPING);
   331         if (result != DS_OK) {
   332 #ifdef DEBUG_SOUND
   333             SetDSerror("DirectSound Play", result);
   334 #endif
   335             return;
   336         }
   337     }
   338     WaitForSingleObject(audio_event, INFINITE);
   339 }
   340 #endif /* USE_POSITION_NOTIFY */
   341 
   342 static void
   343 DX5_PlayAudio(_THIS)
   344 {
   345     /* Unlock the buffer, allowing it to play */
   346     if (locked_buf) {
   347         IDirectSoundBuffer_Unlock(mixbuf, locked_buf, mixlen, NULL, 0);
   348     }
   349 
   350 }
   351 
   352 static Uint8 *
   353 DX5_GetAudioBuf(_THIS)
   354 {
   355     DWORD cursor, junk;
   356     HRESULT result;
   357     DWORD rawlen;
   358 
   359     /* Figure out which blocks to fill next */
   360     locked_buf = NULL;
   361     result = IDirectSoundBuffer_GetCurrentPosition(mixbuf, &cursor, &junk);
   362     if (result == DSERR_BUFFERLOST) {
   363         IDirectSoundBuffer_Restore(mixbuf);
   364         result = IDirectSoundBuffer_GetCurrentPosition(mixbuf,
   365                                                        &cursor, &junk);
   366     }
   367     if (result != DS_OK) {
   368         SetDSerror("DirectSound GetCurrentPosition", result);
   369         return (NULL);
   370     }
   371     cursor /= mixlen;
   372     playing = cursor;
   373     cursor = (cursor + 1) % NUM_BUFFERS;
   374     cursor *= mixlen;
   375 
   376     /* Lock the audio buffer */
   377     result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen,
   378                                      (LPVOID *) & locked_buf, &rawlen, NULL,
   379                                      &junk, 0);
   380     if (result == DSERR_BUFFERLOST) {
   381         IDirectSoundBuffer_Restore(mixbuf);
   382         result = IDirectSoundBuffer_Lock(mixbuf, cursor, mixlen,
   383                                          (LPVOID *) & locked_buf, &rawlen,
   384                                          NULL, &junk, 0);
   385     }
   386     if (result != DS_OK) {
   387         SetDSerror("DirectSound Lock", result);
   388         return (NULL);
   389     }
   390     return (locked_buf);
   391 }
   392 
   393 static void
   394 DX5_WaitDone(_THIS)
   395 {
   396     Uint8 *stream;
   397 
   398     /* Wait for the playing chunk to finish */
   399     stream = this->GetAudioBuf(this);
   400     if (stream != NULL) {
   401         SDL_memset(stream, silence, mixlen);
   402         this->PlayAudio(this);
   403     }
   404     this->WaitAudio(this);
   405 
   406     /* Stop the looping sound buffer */
   407     IDirectSoundBuffer_Stop(mixbuf);
   408 }
   409 
   410 static void
   411 DX5_CloseAudio(_THIS)
   412 {
   413     if (sound != NULL) {
   414         if (mixbuf != NULL) {
   415             /* Clean up the audio buffer */
   416             IDirectSoundBuffer_Release(mixbuf);
   417             mixbuf = NULL;
   418         }
   419         if (audio_event != NULL) {
   420             CloseHandle(audio_event);
   421             audio_event = NULL;
   422         }
   423         IDirectSound_Release(sound);
   424         sound = NULL;
   425     }
   426 }
   427 
   428 #ifdef USE_PRIMARY_BUFFER
   429 /* This function tries to create a primary audio buffer, and returns the
   430    number of audio chunks available in the created buffer.
   431 */
   432 static int
   433 CreatePrimary(LPDIRECTSOUND sndObj, HWND focus,
   434               LPDIRECTSOUNDBUFFER * sndbuf, WAVEFORMATEX * wavefmt,
   435               Uint32 chunksize)
   436 {
   437     HRESULT result;
   438     DSBUFFERDESC format;
   439     DSBCAPS caps;
   440     int numchunks;
   441 
   442     /* Try to set primary mixing privileges */
   443     result = IDirectSound_SetCooperativeLevel(sndObj, focus,
   444                                               DSSCL_WRITEPRIMARY);
   445     if (result != DS_OK) {
   446 #ifdef DEBUG_SOUND
   447         SetDSerror("DirectSound SetCooperativeLevel", result);
   448 #endif
   449         return (-1);
   450     }
   451 
   452     /* Try to create the primary buffer */
   453     SDL_memset(&format, 0, sizeof(format));
   454     format.dwSize = sizeof(format);
   455     format.dwFlags = (DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2);
   456     format.dwFlags |= DSBCAPS_STICKYFOCUS;
   457 #ifdef USE_POSITION_NOTIFY
   458     format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
   459 #endif
   460     result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
   461     if (result != DS_OK) {
   462 #ifdef DEBUG_SOUND
   463         SetDSerror("DirectSound CreateSoundBuffer", result);
   464 #endif
   465         return (-1);
   466     }
   467 
   468     /* Check the size of the fragment buffer */
   469     SDL_memset(&caps, 0, sizeof(caps));
   470     caps.dwSize = sizeof(caps);
   471     result = IDirectSoundBuffer_GetCaps(*sndbuf, &caps);
   472     if (result != DS_OK) {
   473 #ifdef DEBUG_SOUND
   474         SetDSerror("DirectSound GetCaps", result);
   475 #endif
   476         IDirectSoundBuffer_Release(*sndbuf);
   477         return (-1);
   478     }
   479     if ((chunksize > caps.dwBufferBytes) ||
   480         ((caps.dwBufferBytes % chunksize) != 0)) {
   481         /* The primary buffer size is not a multiple of 'chunksize'
   482            -- this hopefully doesn't happen when 'chunksize' is a 
   483            power of 2.
   484          */
   485         IDirectSoundBuffer_Release(*sndbuf);
   486         SDL_SetError
   487             ("Primary buffer size is: %d, cannot break it into chunks of %d bytes\n",
   488              caps.dwBufferBytes, chunksize);
   489         return (-1);
   490     }
   491     numchunks = (caps.dwBufferBytes / chunksize);
   492 
   493     /* Set the primary audio format */
   494     result = IDirectSoundBuffer_SetFormat(*sndbuf, wavefmt);
   495     if (result != DS_OK) {
   496 #ifdef DEBUG_SOUND
   497         SetDSerror("DirectSound SetFormat", result);
   498 #endif
   499         IDirectSoundBuffer_Release(*sndbuf);
   500         return (-1);
   501     }
   502     return (numchunks);
   503 }
   504 #endif /* USE_PRIMARY_BUFFER */
   505 
   506 /* This function tries to create a secondary audio buffer, and returns the
   507    number of audio chunks available in the created buffer.
   508 */
   509 static int
   510 CreateSecondary(LPDIRECTSOUND sndObj, HWND focus,
   511                 LPDIRECTSOUNDBUFFER * sndbuf, WAVEFORMATEX * wavefmt,
   512                 Uint32 chunksize)
   513 {
   514     const int numchunks = 2;
   515     HRESULT result;
   516     DSBUFFERDESC format;
   517     LPVOID pvAudioPtr1, pvAudioPtr2;
   518     DWORD dwAudioBytes1, dwAudioBytes2;
   519 
   520     /* Try to set primary mixing privileges */
   521     if (focus) {
   522         result = IDirectSound_SetCooperativeLevel(sndObj,
   523                                                   focus, DSSCL_PRIORITY);
   524     } else {
   525         result = IDirectSound_SetCooperativeLevel(sndObj,
   526                                                   GetDesktopWindow(),
   527                                                   DSSCL_NORMAL);
   528     }
   529     if (result != DS_OK) {
   530 #ifdef DEBUG_SOUND
   531         SetDSerror("DirectSound SetCooperativeLevel", result);
   532 #endif
   533         return (-1);
   534     }
   535 
   536     /* Try to create the secondary buffer */
   537     SDL_memset(&format, 0, sizeof(format));
   538     format.dwSize = sizeof(format);
   539     format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
   540 #ifdef USE_POSITION_NOTIFY
   541     format.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
   542 #endif
   543     if (!focus) {
   544         format.dwFlags |= DSBCAPS_GLOBALFOCUS;
   545     } else {
   546         format.dwFlags |= DSBCAPS_STICKYFOCUS;
   547     }
   548     format.dwBufferBytes = numchunks * chunksize;
   549     if ((format.dwBufferBytes < DSBSIZE_MIN) ||
   550         (format.dwBufferBytes > DSBSIZE_MAX)) {
   551         SDL_SetError("Sound buffer size must be between %d and %d",
   552                      DSBSIZE_MIN / numchunks, DSBSIZE_MAX / numchunks);
   553         return (-1);
   554     }
   555     format.dwReserved = 0;
   556     format.lpwfxFormat = wavefmt;
   557     result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
   558     if (result != DS_OK) {
   559         SetDSerror("DirectSound CreateSoundBuffer", result);
   560         return (-1);
   561     }
   562     IDirectSoundBuffer_SetFormat(*sndbuf, wavefmt);
   563 
   564     /* Silence the initial audio buffer */
   565     result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
   566                                      (LPVOID *) & pvAudioPtr1,
   567                                      &dwAudioBytes1,
   568                                      (LPVOID *) & pvAudioPtr2,
   569                                      &dwAudioBytes2, DSBLOCK_ENTIREBUFFER);
   570     if (result == DS_OK) {
   571         if (wavefmt->wBitsPerSample == 8) {
   572             SDL_memset(pvAudioPtr1, 0x80, dwAudioBytes1);
   573         } else {
   574             SDL_memset(pvAudioPtr1, 0x00, dwAudioBytes1);
   575         }
   576         IDirectSoundBuffer_Unlock(*sndbuf,
   577                                   (LPVOID) pvAudioPtr1, dwAudioBytes1,
   578                                   (LPVOID) pvAudioPtr2, dwAudioBytes2);
   579     }
   580 
   581     /* We're ready to go */
   582     return (numchunks);
   583 }
   584 
   585 /* This function tries to set position notify events on the mixing buffer */
   586 #ifdef USE_POSITION_NOTIFY
   587 static int
   588 CreateAudioEvent(_THIS)
   589 {
   590     LPDIRECTSOUNDNOTIFY notify;
   591     DSBPOSITIONNOTIFY *notify_positions;
   592     int i, retval;
   593     HRESULT result;
   594 
   595     /* Default to fail on exit */
   596     retval = -1;
   597     notify = NULL;
   598 
   599     /* Query for the interface */
   600     result = IDirectSoundBuffer_QueryInterface(mixbuf,
   601                                                &IID_IDirectSoundNotify,
   602                                                (void *) &notify);
   603     if (result != DS_OK) {
   604         goto done;
   605     }
   606 
   607     /* Allocate the notify structures */
   608     notify_positions = (DSBPOSITIONNOTIFY *) SDL_malloc(NUM_BUFFERS *
   609                                                         sizeof
   610                                                         (*notify_positions));
   611     if (notify_positions == NULL) {
   612         goto done;
   613     }
   614 
   615     /* Create the notify event */
   616     audio_event = CreateEvent(NULL, FALSE, FALSE, NULL);
   617     if (audio_event == NULL) {
   618         goto done;
   619     }
   620 
   621     /* Set up the notify structures */
   622     for (i = 0; i < NUM_BUFFERS; ++i) {
   623         notify_positions[i].dwOffset = i * mixlen;
   624         notify_positions[i].hEventNotify = audio_event;
   625     }
   626     result = IDirectSoundNotify_SetNotificationPositions(notify,
   627                                                          NUM_BUFFERS,
   628                                                          notify_positions);
   629     if (result == DS_OK) {
   630         retval = 0;
   631     }
   632   done:
   633     if (notify != NULL) {
   634         IDirectSoundNotify_Release(notify);
   635     }
   636     return (retval);
   637 }
   638 #endif /* USE_POSITION_NOTIFY */
   639 
   640 static int
   641 DX5_OpenAudio(_THIS, SDL_AudioSpec * spec)
   642 {
   643     HRESULT result;
   644     WAVEFORMATEX waveformat;
   645 
   646     /* Set basic WAVE format parameters */
   647     SDL_memset(&waveformat, 0, sizeof(waveformat));
   648     waveformat.wFormatTag = WAVE_FORMAT_PCM;
   649 
   650     /* Determine the audio parameters from the AudioSpec */
   651     switch (spec->format & 0xFF) {
   652     case 8:
   653         /* Unsigned 8 bit audio data */
   654         spec->format = AUDIO_U8;
   655         silence = 0x80;
   656         waveformat.wBitsPerSample = 8;
   657         break;
   658     case 16:
   659         /* Signed 16 bit audio data */
   660         spec->format = AUDIO_S16;
   661         silence = 0x00;
   662         waveformat.wBitsPerSample = 16;
   663         break;
   664     default:
   665         SDL_SetError("Unsupported audio format");
   666         return (-1);
   667     }
   668     waveformat.nChannels = spec->channels;
   669     waveformat.nSamplesPerSec = spec->freq;
   670     waveformat.nBlockAlign =
   671         waveformat.nChannels * (waveformat.wBitsPerSample / 8);
   672     waveformat.nAvgBytesPerSec =
   673         waveformat.nSamplesPerSec * waveformat.nBlockAlign;
   674 
   675     /* Update the fragment size as size in bytes */
   676     SDL_CalculateAudioSpec(spec);
   677 
   678     /* Open the audio device */
   679     result = DSoundCreate(NULL, &sound, NULL);
   680     if (result != DS_OK) {
   681         SetDSerror("DirectSoundCreate", result);
   682         return (-1);
   683     }
   684 
   685     /* Create the audio buffer to which we write */
   686     NUM_BUFFERS = -1;
   687 #ifdef USE_PRIMARY_BUFFER
   688     if (mainwin) {
   689         NUM_BUFFERS = CreatePrimary(sound, mainwin, &mixbuf,
   690                                     &waveformat, spec->size);
   691     }
   692 #endif /* USE_PRIMARY_BUFFER */
   693     if (NUM_BUFFERS < 0) {
   694         NUM_BUFFERS = CreateSecondary(sound, mainwin, &mixbuf,
   695                                       &waveformat, spec->size);
   696         if (NUM_BUFFERS < 0) {
   697             return (-1);
   698         }
   699 #ifdef DEBUG_SOUND
   700         fprintf(stderr, "Using secondary audio buffer\n");
   701 #endif
   702     }
   703 #ifdef DEBUG_SOUND
   704     else
   705         fprintf(stderr, "Using primary audio buffer\n");
   706 #endif
   707 
   708     /* The buffer will auto-start playing in DX5_WaitAudio() */
   709     playing = 0;
   710     mixlen = spec->size;
   711 
   712 #ifdef USE_POSITION_NOTIFY
   713     /* See if we can use DirectX 6 event notification */
   714     if (CreateAudioEvent(this) == 0) {
   715         this->WaitAudio = DX6_WaitAudio_EventWait;
   716     } else {
   717         this->WaitAudio = DX5_WaitAudio_BusyWait;
   718     }
   719 #endif
   720     return (0);
   721 }
   722 
   723 /* vi: set ts=4 sw=4 expandtab: */