1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2012 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 
Audio_Available(void)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 
DX5_Unload(void)103 static void DX5_Unload(void)
104 {
105 	if ( DSoundDLL != NULL ) {
106 		FreeLibrary(DSoundDLL);
107 		DSoundCreate = NULL;
108 		DSoundDLL = NULL;
109 	}
110 }
DX5_Load(void)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 
Audio_DeleteDevice(SDL_AudioDevice * device)130 static void Audio_DeleteDevice(SDL_AudioDevice *device)
131 {
132 	DX5_Unload();
133 	SDL_free(device->hidden);
134 	SDL_free(device);
135 }
136 
Audio_CreateDevice(int devindex)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 
SetDSerror(const char * function,int code)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 /* */
DX5_SoundFocus(HWND hwnd)238 void DX5_SoundFocus(HWND hwnd)
239 {
240 	mainwin = hwnd;
241 }
242 
DX5_ThreadInit(_THIS)243 static void DX5_ThreadInit(_THIS)
244 {
245 	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
246 }
247 
DX5_WaitAudio_BusyWait(_THIS)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
DX6_WaitAudio_EventWait(_THIS)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 
DX5_PlayAudio(_THIS)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 
DX5_GetAudioBuf(_THIS)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 
DX5_WaitDone(_THIS)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 
DX5_CloseAudio(_THIS)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 */
CreatePrimary(LPDIRECTSOUND sndObj,HWND focus,LPDIRECTSOUNDBUFFER * sndbuf,WAVEFORMATEX * wavefmt,Uint32 chunksize)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 */
CreateSecondary(LPDIRECTSOUND sndObj,HWND focus,LPDIRECTSOUNDBUFFER * sndbuf,WAVEFORMATEX * wavefmt,Uint32 chunksize)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
CreateAudioEvent(_THIS)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 
DX5_OpenAudio(_THIS,SDL_AudioSpec * spec)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