Home | History | Annotate | Download | only in windx5
      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 (at) 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 
    706