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