SDL-1.2.14
[sdl_omap.git] / src / audio / windx5 / SDL_dx5audio.c
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2009 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 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 *)&notify);
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