1 
2 /*
3 #    Sfront, a SAOL to C translator
4 #    This file: Win32 DirectSound audio driver for sfront
5 #
6 # Copyright (c) 1999-2006, Regents of the University of California
7 # All rights reserved.
8 #
9 # Redistribution and use in source and binary forms, with or without
10 # modification, are permitted provided that the following conditions are
11 # met:
12 #
13 #  Redistributions of source code must retain the above copyright
14 #  notice, this list of conditions and the following disclaimer.
15 #
16 #  Redistributions in binary form must reproduce the above copyright
17 #  notice, this list of conditions and the following disclaimer in the
18 #  documentation and/or other materials provided with the distribution.
19 #
20 #  Neither the name of the University of California, Berkeley nor the
21 #  names of its contributors may be used to endorse or promote products
22 #  derived from this software without specific prior written permission.
23 #
24 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #
36 #    Author: Professor John Wawrzynek, UCB CS Division
37 #    Maintainance Email To: John Lazzaro, lazzaro@cs.berkeley.edu
38 */
39 
40 //////////////////////////
41 // dsound output
42 // by Vincent Siliakus & Thomas Jongepier
43 // november 1999
44 //////////////////////////
45 #include <windows.h>
46 #include <windowsx.h>
47 #include <mmsystem.h>
48 #include <dsound.h>
49 #include <objbase.h>
50 #include <initguid.h>
51 
52 #include <stdio.h>
53 
54 #define ASYS_SUCCESS ASYS_DONE
55 
56 #if defined(ASYS_HASOUTPUT)
57 
58 
59 /* Global variables for audio output.
60  */
61 
62 
63 char asyso_playing = 0;
64 int asyso_wrtCursor = 0;
65 int asyso_bufsize;                                /* buffer size in
66 bytes        */
67 int asyso_blksize;                                /* size preferred by
68 sfront    */
69 
70 double asyso_speriod;
71 LPDIRECTSOUND 		lpDirectSound;
72 LPDIRECTSOUNDBUFFER lpDsb;
73 LPDIRECTSOUNDBUFFER lpPrDsb;
74 LPDIRECTSOUNDNOTIFY lpDsNotify;
75 HANDLE				*hBuffPos;
76 DSBPOSITIONNOTIFY   *PositionNotify;
77 PCMWAVEFORMAT		pcmwfp;
78 PCMWAVEFORMAT		pcmwf;
79 DSBUFFERDESC		dsprbdescp;
80 DSBUFFERDESC		dsbdesc;
81 DSCAPS				dscaps;
82 DSBCAPS				pr,sec;
83 HRESULT       		hr;
84 unsigned int		ds_numofsubbuff;
85 unsigned int		ds_subbuffercounter=0;
86 unsigned int		ds_writeposition=0;
87 unsigned int		ds_counter=0;
88 unsigned int		ds_resetwritecrspoint=0;
89 unsigned int		SECBUFFBYTESIZE;
90 unsigned int		SUBBUFFBYTESIZE;
91 unsigned int		SUBBUFFSAMPLESIZE;
92 unsigned int		WRITEPOSITIONOFFSET;
93 unsigned int		TIMES;
94 unsigned int		EXCEPTIONTIMES;
95 
96 
97 void DevCaps(DSCAPS *);
98 void PrBuffCaps(DSBCAPS *);
99 void SecBuffCaps(DSBCAPS *);
100 void WaitForNotification();
101 void Close();
102 void Play();
103 void Stop();
104 int InitOutput(unsigned int);
105 
DevCaps(DSCAPS * DSCaps)106 void DevCaps(DSCAPS *DSCaps)
107 {
108 	DSCaps->dwSize = sizeof(DSCAPS);
109 	IDirectSound_GetCaps(lpDirectSound,DSCaps);
110 }
111 
PrBuffCaps(DSBCAPS * PrBCaps)112 void PrBuffCaps(DSBCAPS *PrBCaps)
113 {
114 	PrBCaps->dwSize = sizeof(DSBCAPS);
115 	IDirectSoundBuffer_GetCaps(lpPrDsb,PrBCaps);
116 }
117 
SecBuffCaps(DSBCAPS * SecBCaps)118 void SecBuffCaps(DSBCAPS *SecBCaps)
119 {
120 	SecBCaps->dwSize = sizeof(DSBCAPS);
121 	IDirectSoundBuffer_GetCaps(lpDsb,SecBCaps);
122 }
123 
WaitForNotification()124 void WaitForNotification()
125 {
126 	DWORD EventNumber = (WaitForMultipleObjects
127 		(ds_numofsubbuff, hBuffPos, FALSE, INFINITE));
128 	//ResetEvent(hBuffPos[EventNumber]); //for manual ResetEvent.
129 }
130 
Close()131 void Close()
132 {
133 	for(ds_counter=0;ds_counter<ds_numofsubbuff;ds_counter++)
134 		CloseHandle(hBuffPos[ds_counter]);
135 	IDirectSoundBuffer_Release(lpDsb);
136 	IDirectSound_Release(lpDirectSound);
137 }
138 
Play()139 void Play()
140 {
141 	IDirectSoundBuffer_Play(lpDsb,0,0,DSBPLAY_LOOPING );
142 }
143 
Stop()144 void Stop()
145 {
146 	IDirectSoundBuffer_Stop(lpDsb);
147 }
148 
149 
InitOutput(unsigned int sys_osize,unsigned int samplerate,unsigned int numchannels)150 int InitOutput(unsigned int sys_osize,
151 			   unsigned int samplerate,
152 			   unsigned int numchannels)
153 {
154 	HWND hwnd = GetForegroundWindow();
155 	if(hwnd==NULL)hwnd = GetDesktopWindow();
156 	SECBUFFBYTESIZE	 =	sys_osize*16;//use 16 or 32
157 	SUBBUFFBYTESIZE	 =	sys_osize;
158 	SUBBUFFSAMPLESIZE=	sys_osize/2;
159   	WRITEPOSITIONOFFSET = SUBBUFFBYTESIZE;
160 	TIMES=SECBUFFBYTESIZE/SUBBUFFBYTESIZE;
161 	EXCEPTIONTIMES = (WRITEPOSITIONOFFSET/SUBBUFFBYTESIZE);
162 	ds_resetwritecrspoint =
163 		SECBUFFBYTESIZE-(EXCEPTIONTIMES*SUBBUFFBYTESIZE);
164 	ds_numofsubbuff=SECBUFFBYTESIZE/SUBBUFFBYTESIZE;
165 	////////////////////////////////
166 	//dsound init
167 	////////////////////////////////
168 	//Create DirectSound Object
169 	if FAILED(DirectSoundCreate(NULL, &lpDirectSound, NULL))
170 		return ASYS_ERROR;
171 	//
172 	//Set Cooperative level of DirectSound Object
173 	if FAILED(IDirectSound_SetCooperativeLevel(lpDirectSound,hwnd,
174 			DSSCL_PRIORITY))return ASYS_ERROR;
175 	//
176 	////////////////////////////////
177    // Set up wave format structure.
178    memset(&pcmwfp, 0, sizeof(PCMWAVEFORMAT));
179     pcmwfp.wf.wFormatTag = WAVE_FORMAT_PCM;
180     pcmwfp.wf.nChannels = numchannels;
181     pcmwfp.wf.nSamplesPerSec = samplerate;
182     pcmwfp.wf.nBlockAlign = 2*numchannels;
183     pcmwfp.wf.nAvgBytesPerSec =
184 		pcmwfp.wf.nSamplesPerSec * pcmwfp.wf.nBlockAlign;
185     pcmwfp.wBitsPerSample = 16;
186 	//
187 	////////////////////////////////
188     // Set up DSBUFFERDESC structure.
189     memset(&dsprbdescp, 0, sizeof(DSBUFFERDESC)); // Zero it out.
190     dsprbdescp.dwSize = sizeof(DSBUFFERDESC);
191     dsprbdescp.dwFlags = DSBCAPS_PRIMARYBUFFER;
192     dsprbdescp.dwBufferBytes = 0;
193     dsprbdescp.lpwfxFormat = NULL;
194 	//
195 	////////////////////////////////
196 	// Create Primary buffer.
197     if FAILED(IDirectSound_CreateSoundBuffer(lpDirectSound,&dsprbdescp,
198 	&lpPrDsb, NULL))return ASYS_ERROR;
199 	// Set primary buffer to desired format.
200     if FAILED(IDirectSoundBuffer_SetFormat(lpPrDsb,
201 		(LPWAVEFORMATEX)&pcmwfp))return ASYS_ERROR;
202 	//start playing (no sound yet)
203     IDirectSoundBuffer_Play(lpPrDsb,0,0,DSBPLAY_LOOPING);
204 	//
205     // Set up wave format structure.
206     memset(&pcmwf, 0, sizeof(PCMWAVEFORMAT));
207     pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM;
208     pcmwf.wf.nChannels = numchannels;
209     pcmwf.wf.nSamplesPerSec = samplerate;
210     pcmwf.wf.nBlockAlign = 2*numchannels;
211     pcmwf.wf.nAvgBytesPerSec =
212 		pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign;
213     pcmwf.wBitsPerSample = 16;
214 	//
215     // Set up DSBUFFERDESC structure.
216     memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); // Zero it out.
217     dsbdesc.dwSize = sizeof(DSBUFFERDESC);
218     // Need default controls (pan, volume, frequency).
219     dsbdesc.dwFlags =
220 					 DSBCAPS_GLOBALFOCUS
221 					|DSBCAPS_GETCURRENTPOSITION2
222 					|DSBCAPS_CTRLPOSITIONNOTIFY ;
223     dsbdesc.dwBufferBytes = SECBUFFBYTESIZE;
224     dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf;
225 	//
226 	////////////////////////////////
227 	if FAILED(IDirectSound_CreateSoundBuffer(lpDirectSound,&dsbdesc,
228 		&lpDsb, NULL))return ASYS_ERROR;
229     //
230 	PositionNotify=(DSBPOSITIONNOTIFY*)malloc(ds_numofsubbuff*
231 		(sizeof(DSBPOSITIONNOTIFY)));
232 	hBuffPos=(HANDLE*)malloc(ds_numofsubbuff*sizeof(HANDLE));
233 	//
234 	for(ds_counter=0;ds_counter<ds_numofsubbuff;ds_counter++){
235 		hBuffPos[ds_counter]=CreateEvent(NULL,FALSE,FALSE,NULL);
236 		PositionNotify[ds_counter].dwOffset = SUBBUFFBYTESIZE*ds_counter;
237 		PositionNotify[ds_counter].hEventNotify=hBuffPos[ds_counter];
238 	}
239 	//
240 	if FAILED(IDirectSoundBuffer_QueryInterface(lpDsb,
241 		&IID_IDirectSoundNotify,(LPVOID *)&lpDsNotify))return ASYS_ERROR;
242 	//
243 	IDirectSoundNotify_SetNotificationPositions(lpDsNotify,ds_numofsubbuff,
244 		PositionNotify);
245 	//\\\\\\\\\\\\\\\
246 	//
247 	Play();
248 	return ASYS_SUCCESS;
249 }
250 
251 
252 #endif
253 
254 #if (defined(ASYS_HASOUTPUT) && !defined(ASYS_HASINPUT))
255 
256 /* Opens waveform output for a given srate/channels.
257  */
258 
asys_osetup(int srate,int ochannels,int osample,char * oname,int toption)259 int asys_osetup(int srate, int ochannels, int osample,
260                 char * oname, int toption)
261 {
262 
263   int osize = ASYS_OCHAN*ACYCLE;
264 
265   InitOutput(osize,srate,ochannels);
266   return ASYS_SUCCESS;
267 }
268 
269 #endif
270 
271 #if defined(ASYS_HASOUTPUT)
272 
273 /*
274  * Shuts down audio system.
275  */
276 
asys_oshutdown(void)277 void asys_oshutdown(void)
278 
279 {
280   Stop();
281   Close();
282 }
283 
284 #endif
285 
286 #if defined(ASYS_HASOUTPUT)
287 
asys_putbuf(short ** buffer,int * osize)288 int asys_putbuf(short **buffer, int * osize)
289 
290 {
291 	DWORD dwBytes;
292 	*osize=SUBBUFFSAMPLESIZE;
293 	ds_writeposition=ds_subbuffercounter*SUBBUFFBYTESIZE;
294 	WaitForNotification();
295 	if(ds_writeposition>ds_resetwritecrspoint)
296 	{
297 		ds_subbuffercounter=0;
298 		ds_writeposition=0;
299 	}
300 	hr = IDirectSoundBuffer_Unlock(lpDsb,*buffer,
301 		SUBBUFFBYTESIZE, NULL,NULL);
302     hr = IDirectSoundBuffer_Lock(lpDsb,ds_writeposition,
303 		SUBBUFFBYTESIZE, (LPVOID*)buffer,&dwBytes, NULL, 0, NULL);
304 	ds_subbuffercounter++;
305 	return ASYS_DONE;
306 }
307 
308 /****************************************************************/
309 /*        creates buffer, and generates starting silence        */
310 /****************************************************************/
311 
asys_preamble(ASYS_OTYPE * asys_obuf[],int * osize)312 int asys_preamble(ASYS_OTYPE * asys_obuf[], int * osize)
313 
314 {
315   int i;
316 
317   /* emulates old interface, since I don't understand asys_putbuf */
318   /* well enough to make direct modifications  */
319 
320   /* set up first call, which allocates buffer */
321 
322   *asys_obuf = NULL;
323   *osize = 0;
324 
325   if (asys_putbuf(asys_obuf, osize) == ASYS_ERROR)
326     return ASYS_ERROR;
327 
328   /* clear allocated buffer */
329 
330   for (i = 0; i < (*osize); i++)
331     (*asys_obuf)[i] = 0;
332 
333   /* send the 4 silence putbuf's of old API */
334 
335   for(i = 0; i < 4; i++)
336     if (asys_putbuf(asys_obuf, osize) == ASYS_ERROR)
337       return ASYS_ERROR;
338 
339   return ASYS_DONE;
340 }
341 
342 
343 #endif
344 
345 
346 /* Currently not supported audio input.  All routines are dummies.
347  */
348 
349 #if (!defined(ASYS_HASOUTPUT) && defined(ASYS_HASINPUT))
350 
351 /* Initializes audio input.
352  */
asys_isetup(int srate,int ichannels,int isample,char * iname,int toption)353 int asys_isetup(int srate, int ichannels, int isample,
354                 char * iname, int toption)
355 
356 {
357   return ASYS_ERROR;
358 }
359 
360 #endif
361 
362 #if (defined(ASYS_HASOUTPUT) && defined(ASYS_HASINPUT))
363 
364 /* Initialized bidirectional audio flows. */
asys_iosetup(int srate,int ichannels,int ochannels,int isample,int osample,char * iname,char * oname,int toption)365 int asys_iosetup(int srate, int ichannels, int ochannels,
366                  int isample, int osample,
367                  char * iname, char * oname, int toption)
368 
369 {
370   return ASYS_ERROR;
371 }
372 
373 #endif
374 
375 #if defined(ASYS_HASINPUT)
376 
377 /* Shuts down audio input device.
378  */
379 
asys_ishutdown(void)380 void asys_ishutdown(void)
381 
382 {
383 }
384 
385 #endif
386 
387 #if defined(ASYS_HASINPUT)
388 
389 /* Gets one frame of audio from input.
390  */
391 
asys_getbuf(ASYS_ITYPE * asys_ibuf[],int * isize)392 int asys_getbuf(ASYS_ITYPE * asys_ibuf[], int * isize)
393 {
394   return ASYS_ERROR;
395 }
396 
397 #endif
398 
399 
400 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
401 /*  ksync() and ksyncinit() for -playback and -timesync modes  */
402 /*_____________________________________________________________*/
403 
404 #if defined(ASYS_KSYNC)
405 
406 #if (ASYS_TIMEOPTION != ASYS_TIMESYNC)
407 
408 #include <windows.h>
409 #include <windowsx.h>
410 #include <winbase.h>
411 #include <mmsystem.h>
412 
413 #define SYNC_MAXCOUNT 4294967296L
414 #define SYNC_KMTIME EV(KUTIME)/1000
415 
416 DWORD sync_last, sync_this, sync_delay;
417 TIMECAPS sync_tc;
418 BOOL sync_waitFlag;
419 
420 /***********************************************************/
421 /*         support routines                                */
422 /***********************************************************/
423 
sync_callBack(UINT uID,UINT uMsg,DWORD dwUser,DWORD dw1,DWORD dw2)424 void CALLBACK sync_callBack(UINT uID, UINT uMsg,
425                             DWORD dwUser, DWORD dw1, DWORD dw2)
426 {
427   sync_waitFlag = TRUE;
428 }
429 
sync_sleep(UINT ms)430 BOOL sync_sleep(UINT ms)
431 {
432   sync_waitFlag = FALSE;
433   if FAILED(timeSetEvent(ms, (UINT) 1, &sync_callBack, 0L, TIME_ONESHOT))
434     {
435       fprintf(stderr, "timeSetEvent error.\n");
436       exit(-1);
437     }
438   // spin wait
439   while (!sync_waitFlag) {}
440   return TRUE;
441 }
442 
443 /***********************************************************/
444 /*         synchronizes on k-rate boundaries               */
445 /***********************************************************/
446 
ksync()447 float ksync()
448 
449 {
450   float ret;
451 
452   sync_this = timeGetTime();
453 
454   if (sync_this<sync_last)   // timer wrap around
455     sync_last = (DWORD) (sync_last - SYNC_MAXCOUNT) + SYNC_KMTIME;
456   else
457     sync_last += SYNC_KMTIME;
458 
459   sync_delay = sync_last - sync_this;
460   if (sync_delay>0)
461     {
462       /* sync_sleep(sync_delay); */   /* can this be safely commented out? */
463       ret = (SYNC_KMTIME - sync_delay)/SYNC_KMTIME;
464     }
465   else
466     ret = 1.0F;
467 
468   return ret;
469 }
470 
471 /***********************************************************/
472 /*         initializes k-rate boundaries sync              */
473 /***********************************************************/
474 
ksyncinit()475 void ksyncinit()
476 
477 {
478   // Set 1ms time resolution
479   if FAILED(timeGetDevCaps(&sync_tc, sizeof(TIMECAPS)))
480     {
481       fprintf(stderr, "TimeGetDevCaps error.\n");
482       exit(-1);
483     }
484   sync_last = timeGetTime();
485 }
486 
487 #endif
488 
489 
490 #if (ASYS_TIMEOPTION == ASYS_TIMESYNC)
491 
492 #include <windows.h>
493 #include <windowsx.h>
494 #include <winbase.h>
495 #include <mmsystem.h>
496 
497 #define SYNC_MAXCOUNT 4294967296L
498 #define SYNC_KMTIME EV(KUTIME)/1000
499 
500 DWORD sync_last, sync_this, sync_delay;
501 TIMECAPS sync_tc;
502 BOOL sync_waitFlag;
503 
504 /***********************************************************/
505 /*         support routines                                */
506 /***********************************************************/
507 
sync_callBack(UINT uID,UINT uMsg,DWORD dwUser,DWORD dw1,DWORD dw2)508 void CALLBACK sync_callBack(UINT uID, UINT uMsg,
509                             DWORD dwUser, DWORD dw1, DWORD dw2)
510 {
511   sync_waitFlag = TRUE;
512 }
513 
sync_sleep(UINT ms)514 BOOL sync_sleep(UINT ms)
515 {
516   sync_waitFlag = FALSE;
517   if FAILED(timeSetEvent(ms, (UINT) 1, &sync_callBack, 0L, TIME_ONESHOT))
518     {
519       fprintf(stderr, "timeSetEvent error.\n");
520       exit(-1);
521     }
522   // spin wait
523   while (!sync_waitFlag) {}
524   return TRUE;
525 }
526 
527 /***********************************************************/
528 /*         synchronizes on k-rate boundaries               */
529 /***********************************************************/
530 
ksync()531 float ksync()
532 
533 {
534   float ret;
535 
536   sync_this = timeGetTime();
537 
538   if (sync_this<sync_last)   // timer wrap around
539     sync_last = (DWORD) (sync_last - SYNC_MAXCOUNT) + SYNC_KMTIME;
540   else
541     sync_last += SYNC_KMTIME;
542 
543   sync_delay = sync_last - sync_this;
544   if (sync_delay>0)
545     {
546       sync_sleep(sync_delay);
547       ret = (SYNC_KMTIME - sync_delay)/SYNC_KMTIME;
548     }
549   else
550     ret = 1.0F;
551 
552   return ret;
553 }
554 
555 /***********************************************************/
556 /*         initializes k-rate boundaries sync              */
557 /***********************************************************/
558 
ksyncinit()559 void ksyncinit()
560 
561 {
562   // Set 1ms time resolution
563   if FAILED(timeGetDevCaps(&sync_tc, sizeof(TIMECAPS)))
564     {
565       fprintf(stderr, "TimeGetDevCaps error.\n");
566       exit(-1);
567     }
568   sync_last = timeGetTime();
569 }
570 
571 #endif
572 
573 #endif  /* ASYS_KSYNC */
574