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