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