1 /*
2     TiMidity++ -- MIDI to WAVE converter and player
3     Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4     Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 
20     w32_a.c
21 
22     Functions to play sound on the Windows audio driver (Windows 95/98/NT).
23 
24     Modified by Masanao Izumo <mo@goice.co.jp>
25 */
26 
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif /* HAVE_CONFIG_H */
30 #ifdef __W32__
31 #include "interface.h"
32 #endif
33 #include <stdio.h>
34 #include <stdlib.h>
35 #ifndef NO_STRING_H
36 #include <string.h>
37 #else
38 #include <strings.h>
39 #endif
40 #include <windows.h>
41 
42 extern void *safe_malloc(size_t count);
43 
44 extern CRITICAL_SECTION critSect;
45 
46 static int opt_wmme_device_id = -2;
47 
48 UINT uDeviceID;
49 
50 /*****************************************************************************************************************************/
51 
52 #if defined(__CYGWIN32__) || defined(__MINGW32__)
53 #ifdef HAVE_NEW_MMSYSTEM
54 #include <mmsystem.h>
55 #else
56 /* On cygnus, there is not mmsystem.h for Multimedia API's.
57  * mmsystem.h can not distribute becase of Microsoft Lisence
58  * Then declare some of them here. **/
59 #define WOM_OPEN                0x3BB
60 #define WOM_CLOSE               0x3BC
61 #define WOM_DONE                0x3BD
62 #define WAVE_FORMAT_QUERY       0x0001
63 #define WAVE_ALLOWSYNC          0x0002
64 #define WAVE_FORMAT_PCM         1
65 #define CALLBACK_FUNCTION       0x00030000l
66 #define WAVERR_BASE             32
67 #define WAVE_MAPPER             (UINT)-1
68 
69 DECLARE_HANDLE(HWAVEOUT);
70 DECLARE_HANDLE(HWAVE);
71 typedef HWAVEOUT *LPHWAVEOUT;
72 
73 /* Define WAVEHDR, WAVEFORMAT structure */
74 
75 typedef struct wavehdr_tag
76 {
77     LPSTR       lpData;
78     DWORD       dwBufferLength;
79     DWORD       dwBytesRecorded;
80     DWORD       dwUser;
81     DWORD       dwFlags;
82     DWORD       dwLoops;
83     struct wavehdr_tag *lpNext;
84     DWORD       reserved;
85 } WAVEHDR;
86 
87 typedef struct
88 {
89     WORD    wFormatTag;
90     WORD    nChannels;
91     DWORD   nSamplesPerSec;
92     DWORD   nAvgBytesPerSec;
93     WORD    nBlockAlign;
94     WORD    wBitsPerSample;
95     WORD    cbSize;
96 } WAVEFORMAT, WAVEFORMATEX, *LPWAVEFORMATEX;
97 
98 
99 typedef struct waveoutcaps_tag
100 {
101     WORD    wMid;
102     WORD    wPid;
103     UINT    vDriverVersion;
104 #define MAXPNAMELEN      32
105     char    szPname[MAXPNAMELEN];
106     DWORD   dwFormats;
107     WORD    wChannels;
108     DWORD   dwSupport;
109 } WAVEOUTCAPS;
110 
111 typedef WAVEHDR *       LPWAVEHDR;
112 typedef WAVEFORMAT *    LPWAVEFORMAT;
113 typedef WAVEOUTCAPS *   LPWAVEOUTCAPS;
114 typedef UINT            MMRESULT;
115 
116 MMRESULT WINAPI waveOutOpen(LPHWAVEOUT, UINT, LPWAVEFORMAT, DWORD, DWORD, DWORD);
117 MMRESULT WINAPI waveOutClose(HWAVEOUT);
118 MMRESULT WINAPI waveOutPrepareHeader(HWAVEOUT, LPWAVEHDR, UINT);
119 MMRESULT WINAPI waveOutUnprepareHeader(HWAVEOUT, LPWAVEHDR, UINT);
120 MMRESULT WINAPI waveOutWrite(HWAVEOUT, LPWAVEHDR, UINT);
121 UINT     WINAPI waveOutGetNumDevs(void);
122 MMRESULT WINAPI waveOutReset(HWAVEOUT);
123 MMRESULT WINAPI waveOutGetDevCaps(UINT, LPWAVEOUTCAPS, UINT);
124 MMRESULT WINAPI waveOutGetDevCapsA(UINT, LPWAVEOUTCAPS, UINT);
125 #define waveOutGetDevCaps waveOutGetDevCapsA
126 MMRESULT WINAPI waveOutGetID(HWAVEOUT, UINT*);
127 
128 #endif
129 #endif /* __CYGWIN32__ */
130 
131 /*****************************************************************************************************************************/
132 
133 #include "timidity.h"
134 #include "output.h"
135 #include "controls.h"
136 #include "timer.h"
137 #include "instrum.h"
138 #include "playmidi.h"
139 #include "mblock.h"
140 #include "miditrace.h"
141 #include "interface.h"
142 
143 #define NOT !
144 
145 static int  open_output     (void); /* 0=success, 1=warning, -1=fatal error */
146 static void close_output    (void);
147 static int  output_data     (char * Data, int32 Size);
148 static int  acntl           (int request, void * arg);
149 
150 static void print_device_list(void);
151 
152 #if defined ( IA_W32GUI ) || defined ( IA_W32G_SYN )
153 //#if defined ( IA_W32GUI )
154 volatile int data_block_bits = DEFAULT_AUDIO_BUFFER_BITS;
155 volatile int data_block_num = 64;
156 #endif
157 
158 #define DATA_BLOCK_SIZE     (4 * AUDIO_BUFFER_SIZE)
159 #define DATA_BLOCK_NUM      (dpm.extra_param[0])
160 static int data_block_trunc_size;
161 
162 struct MMBuffer
163 {
164     int                 Number;
165     int                 Prepared;   // Non-zero if this buffer has been prepared.
166 
167     HGLOBAL             hData;
168     void *              Data;
169 
170     HGLOBAL             hHead;
171     WAVEHDR *           Head;
172 
173     struct MMBuffer *   Next;
174 };
175 
176 static struct MMBuffer *            Buffers;
177 
178 static volatile struct MMBuffer *   FreeBuffers;
179 static volatile int                 NumBuffersInUse;
180 
181 static HWAVEOUT                     hDevice;
182 static int                          BufferDelay;                    // in milliseconds
183 
184 static volatile BOOL                DriverClosing = FALSE;
185 static volatile BOOL                OutputWorking = FALSE;
186 
187 static const int                    AllowSynchronousWaveforms = 1;
188 
189 /*****************************************************************************************************************************/
190 
191 static void CALLBACK                OnPlaybackEvent (HWAVE hWave, UINT Msg, DWORD_PTR UserData, DWORD_PTR Param1, DWORD_PTR Param2);
192 static void                         BufferPoolReset (void);
193 static struct MMBuffer *            GetBuffer       ();
194 static void                         PutBuffer       (struct MMBuffer *);
195 static const char *                 MMErrorMessage  (MMRESULT Result);
196 static void                         WaitForBuffer   (int WaitForAllBuffers);
197 static void                         DebugPrint      (const char *format, ...);
198 
199 /*****************************************************************************************************************************/
200 
201 static int detect(void);
202 
203 #define dpm w32_play_mode
204 
205 PlayMode dpm =
206 {
207     DEFAULT_RATE,
208     PE_16BIT | PE_SIGNED,
209     PF_PCM_STREAM|PF_CAN_TRACE|PF_BUFF_FRAGM_OPT,
210     -1,
211     {32},
212     "Windows audio driver", 'd',
213     NULL,
214     open_output,
215     close_output,
216     output_data,
217     acntl,
218 	detect
219 };
220 
221 /*****************************************************************************************************************************/
222 
open_output(void)223 static int open_output(void)
224 {
225     int             i;
226     int             j;
227     int             IsMono;
228     WAVEFORMATEX    wf;
229     WAVEOUTCAPS     woc;
230     MMRESULT        Result;
231     UINT            DeviceID;
232 	int ret;
233 
234 	if( dpm.name != NULL)
235 		ret = sscanf(dpm.name, "%d", &opt_wmme_device_id);
236 	if ( dpm.name == NULL || ret == 0 || ret == EOF)
237 		opt_wmme_device_id = -2;
238 
239 	if (opt_wmme_device_id == -1){
240 		print_device_list();
241 		return -1;
242 	}
243 
244     if (dpm.extra_param[0] < 8)
245     {
246         ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Too small -B option: %d", dpm.extra_param[0]);
247         dpm.extra_param[0] = 8;
248     }
249 
250 /** Check if there is at least one audio device. **/
251 
252     if (waveOutGetNumDevs() == 0)
253     {
254         ctl->cmsg (CMSG_ERROR, VERB_NORMAL, "No audio devices present!");
255         return -1;
256     }
257 
258 /** They can't mean these. **/
259 
260     dpm.encoding &= ~(PE_ULAW | PE_ALAW | PE_BYTESWAP);
261 
262     if (dpm.encoding & PE_16BIT || dpm.encoding & PE_24BIT)
263         dpm.encoding |= PE_SIGNED;
264     else
265         dpm.encoding &= ~PE_SIGNED;
266 
267     IsMono  = (dpm.encoding & PE_MONO);
268 
269     memset(&wf, 0, sizeof(wf));
270 
271     wf.wFormatTag     = WAVE_FORMAT_PCM;
272     wf.nChannels      = IsMono ? 1 : 2;
273     wf.nSamplesPerSec = dpm.rate;
274 
275     i = dpm.rate;
276     j = get_encoding_sample_size(dpm.encoding);
277     i *= j;
278     data_block_trunc_size = DATA_BLOCK_SIZE - (DATA_BLOCK_SIZE % j);
279 
280     wf.nAvgBytesPerSec = i;
281     wf.nBlockAlign     = j;
282 	if (dpm.encoding & PE_24BIT) {
283 		wf.wBitsPerSample  = 24;
284 	} else if (dpm.encoding & PE_16BIT) {
285 		wf.wBitsPerSample  = 16;
286 	} else {
287 		wf.wBitsPerSample  = 8;
288 	}
289     wf.cbSize          = sizeof(WAVEFORMAT);
290 
291 /** Open the device. **/
292 
293     DebugPrint("Opening device...\n");
294 
295 		hDevice = 0;
296     DriverClosing = FALSE;
297 
298 	if (opt_wmme_device_id == -2){
299 		uDeviceID = WAVE_MAPPER;
300     }else{
301     	uDeviceID= (UINT)opt_wmme_device_id;
302 	}
303 
304     if (AllowSynchronousWaveforms)
305         Result = waveOutOpen(&hDevice, uDeviceID, (LPWAVEFORMATEX) &wf, (DWORD_PTR) OnPlaybackEvent, 0, CALLBACK_FUNCTION | WAVE_ALLOWSYNC);
306     else
307         Result = waveOutOpen(&hDevice, uDeviceID, (LPWAVEFORMATEX) &wf, (DWORD_PTR) OnPlaybackEvent, 0, CALLBACK_FUNCTION);
308 
309     if (Result)
310     {
311         ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Can't open audio device: " "encoding=<%s>, rate=<%d>, ch=<%d>: %s", output_encoding_string(dpm.encoding), dpm.rate, wf.nChannels, MMErrorMessage(Result));
312         return -1;
313     }
314     else
315         DebugPrint("Device opened.\n");
316 
317 /** Get the device ID. **/
318 
319     DeviceID = 0;
320     waveOutGetID(hDevice, &DeviceID);
321 
322 /** Get the device capabilities. **/
323 
324     memset(&woc, 0, sizeof(WAVEOUTCAPS));
325     Result = waveOutGetDevCaps(DeviceID, &woc, sizeof(WAVEOUTCAPS));
326 
327     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Device ID: %d",              DeviceID);
328     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Manufacture ID: %d",         woc.wMid);
329     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Product ID: %d",             woc.wPid);
330     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Driver version: %d",         woc.vDriverVersion);
331     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Product name: %s",           woc.szPname);
332     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Formats supported: 0x%08X",  woc.dwFormats);
333     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Max. channels: %d",          woc.wChannels);
334     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Supported features: 0x%08X", woc.dwSupport);
335 
336 /** Calculate the buffer delay. **/
337 
338     BufferDelay = AUDIO_BUFFER_SIZE * get_encoding_sample_size(dpm.encoding);
339 
340     BufferDelay = (BufferDelay * 1000) / dpm.rate;
341 
342 /** Create the buffer pool. **/
343 
344     Buffers = (struct MMBuffer *) safe_malloc(DATA_BLOCK_NUM * sizeof(struct MMBuffer));
345 
346     for (i = 0; i < DATA_BLOCK_NUM; i++)
347     {
348         struct MMBuffer *   b;
349 
350         b = &Buffers[i];
351 
352         b->hData = GlobalAlloc(GMEM_ZEROINIT, DATA_BLOCK_SIZE);
353         b->Data  = GlobalLock (b->hData);
354         b->hHead = GlobalAlloc(GMEM_ZEROINIT, sizeof(WAVEHDR));
355         b->Head  = GlobalLock (b->hHead);
356     }
357 
358     BufferPoolReset();
359 
360 /** Set the file descriptor. **/
361 
362     dpm.fd = 0;
363 
364     return 0;
365 }
366 
367 /*****************************************************************************************************************************/
368 
close_output(void)369 static void close_output(void)
370 {
371     int i;
372 
373     DriverClosing = TRUE;
374 
375     if (dpm.fd != -1)
376     {
377         WaitForBuffer(1);
378 
379         DebugPrint("Closing device...\n");
380 
381         waveOutReset(hDevice);
382         waveOutClose(hDevice);
383         hDevice = NULL;
384 
385         DebugPrint("Device closed.\n");
386 
387     /** Free all buffers. **/
388 
389         for (i = 0; i < DATA_BLOCK_NUM; i++)
390         {
391             struct MMBuffer *   block;
392 
393             block = &Buffers[i];
394 
395             GlobalUnlock(block->hHead);
396             GlobalFree  (block->hHead);
397 
398             GlobalUnlock(block->hData);
399             GlobalFree  (block->hData);
400         }
401 
402         free(Buffers);
403         Buffers = NULL;
404 
405     /** Reset the file descriptor. **/
406 
407         dpm.fd = -1;
408     }
409 }
410 
detect(void)411 static int detect(void)
412 {
413 	if (waveOutGetNumDevs() == 0) {return 0;}	/* not found */
414 	return 1;	/* found */
415 }
416 
417 
418 /*****************************************************************************************************************************/
419 
output_data(char * Data,int32 Size)420 static int output_data(char * Data, int32 Size)
421 {
422     char *  d;
423     int32   s;
424 
425     OutputWorking = TRUE;
426     d = Data;
427     s = Size;
428 
429     while (NOT DriverClosing && s > 0)
430     {
431         int32               n;
432         struct MMBuffer *   b;
433 
434         MMRESULT            Result;
435         LPWAVEHDR           wh;
436 
437         if ((b = GetBuffer()) == NULL)
438         {
439             WaitForBuffer(0);
440             continue;
441         }
442 
443         if (s <= data_block_trunc_size)
444             n = s;
445         else
446             n = data_block_trunc_size;
447 
448         CopyMemory(b->Data, d, n);
449 
450         wh = b->Head;
451 
452         wh->dwBufferLength = n;
453         wh->lpData         = b->Data;
454         wh->dwUser         = b->Number;
455 
456     /** Prepare the buffer. **/
457 
458         DebugPrint("%2d: Preparing buffer %d...\n", NumBuffersInUse, wh->dwUser);
459 
460         Result = waveOutPrepareHeader(hDevice, wh, sizeof(WAVEHDR));
461 
462         if (Result)
463         {
464             DebugPrint("%2d: Buffer preparation failed.\n", NumBuffersInUse);
465 
466             ctl->cmsg (CMSG_ERROR, VERB_NORMAL, "waveOutPrepareHeader(): %s", MMErrorMessage(Result));
467             return -1;
468         }
469         else
470             DebugPrint("%2d: Buffer %d prepared.\n", NumBuffersInUse, wh->dwUser);
471 
472         b->Prepared = 1;
473 
474     /** Queue the buffer. **/
475 
476         DebugPrint("%2d: Queueing buffer %d...\n", NumBuffersInUse, wh->dwUser);
477 
478         Result = waveOutWrite(hDevice, wh, sizeof(WAVEHDR));
479 
480         if (Result)
481         {
482             DebugPrint("%2d: Buffer queueing failed.\n", NumBuffersInUse);
483 
484             ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "waveOutWrite(): %s", MMErrorMessage(Result));
485             return -1;
486         }
487         else
488             DebugPrint("%2d: Buffer %d queued.\n", NumBuffersInUse, wh->dwUser);
489 
490         d += n;
491         s -= n;
492     }
493 
494     OutputWorking = FALSE;
495     return 0;
496 }
497 
498 /*****************************************************************************************************************************/
499 
acntl(int request,void * arg)500 static int acntl(int request, void *arg)
501 {
502   static char dummy_sounds[4*AUDIO_BUFFER_SIZE];
503 
504     switch(request)
505     {
506         case PM_REQ_GETQSIZ:
507             *(int *)arg = (DATA_BLOCK_NUM-1) * AUDIO_BUFFER_SIZE;
508             *(int *)arg *= get_encoding_sample_size(dpm.encoding);
509 
510             return 0;
511 
512         case PM_REQ_DISCARD:
513         {
514             DebugPrint("Resetting audio device.\n");
515 
516             waveOutReset(hDevice);
517 	    close_output();
518 	    open_output();
519 
520             DebugPrint("Audio device reset.\n");
521 
522             return 0;
523         }
524 
525         case PM_REQ_FLUSH:
526         {
527 	    close_output();
528 	    open_output();
529             return 0;
530         }
531 
532         case PM_REQ_PLAY_START: /* Called just before playing */
533         case PM_REQ_PLAY_END: /* Called just after playing */
534     	    return 0;
535     }
536 
537     return -1;
538 }
539 
540 /*****************************************************************************************************************************/
541 
OnPlaybackEvent(HWAVE hWave,UINT Msg,DWORD_PTR UserData,DWORD_PTR Param1,DWORD_PTR Param2)542 static void CALLBACK OnPlaybackEvent(HWAVE hWave, UINT Msg, DWORD_PTR UserData, DWORD_PTR Param1, DWORD_PTR Param2)
543 {
544     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Msg: 0x%08X, Num. buffers in use: %d", Msg, NumBuffersInUse);
545 
546     switch (Msg)
547     {
548         case WOM_OPEN:
549             DebugPrint("%2d: Device opened.\n", NumBuffersInUse);
550             break;
551 
552         case WOM_CLOSE:
553             DebugPrint("%2d: Device closed.\n", NumBuffersInUse);
554             break;
555 
556         case WOM_DONE:
557         {
558             WAVEHDR *   wh;
559 
560             EnterCriticalSection(&critSect);
561 
562             wh = (WAVEHDR *) Param1;
563 
564 /* It's not safe to do this here. Read the remarks of waveOutProc() in the SDK on which functions are safe to call.
565             if (NOT Queueing)
566             {
567                 DebugPrint("%2d: Dequeueing buffer %d...\n", NumBuffersInUse, wh->dwUser);
568 
569                 waveOutUnprepareHeader(hDevice, wh, sizeof(WAVEHDR));
570 
571                 DebugPrint("%2d: Buffer %d dequeued.\n",     NumBuffersInUse, wh->dwUser);
572             }
573             else
574                 DebugPrint("%2d: *** Buffer %d not dequeued! ***\n", NumBuffersInUse, wh->dwUser);
575  */
576             PutBuffer(&Buffers[wh->dwUser]);
577 
578             LeaveCriticalSection(&critSect);
579 
580             break;
581         }
582 
583         default:
584             DebugPrint("%2d: Unknown play back event 0x%08X.\n", NumBuffersInUse, Msg);
585     }
586 }
587 
588 /*****************************************************************************************************************************/
589 
590 #define DIM(a) sizeof(a) / sizeof(a[0])
591 
592 static const char * mmsyserr_code_string[] =
593 {
594     "no error",
595     "unspecified error",
596     "device ID out of range",
597     "driver failed enable",
598     "device already allocated",
599     "device handle is invalid",
600     "no device driver present",
601     "memory allocation error",
602     "function isn't supported",
603     "error value out of range",
604     "invalid flag passed",
605     "invalid parameter passed",
606     "handle being used",
607 };
608 
609 static const char * waverr_code_sring[] =
610 {
611     "unsupported wave format",
612     "still something playing",
613     "header not prepared",
614     "device is synchronous",
615 };
616 
MMErrorMessage(MMRESULT ErrorCode)617 static const char * MMErrorMessage(MMRESULT ErrorCode)
618 {
619     static char s[32];
620 
621     if (ErrorCode >= WAVERR_BASE)
622     {
623         ErrorCode -= WAVERR_BASE;
624 
625         if (ErrorCode > DIM(waverr_code_sring))
626         {
627             wsprintf(s, "Unknown wave error %d", ErrorCode);
628             return s;
629         }
630         else
631             return waverr_code_sring[ErrorCode];
632     }
633     else
634     if (ErrorCode > DIM(mmsyserr_code_string))
635     {
636         wsprintf(s, "Unknown multimedia error %d", ErrorCode);
637         return s;
638     }
639     else
640         return mmsyserr_code_string[ErrorCode];
641 }
642 
643 #undef DIM
644 
645 /*****************************************************************************************************************************/
646 
BufferPoolReset(void)647 static void BufferPoolReset(void)
648 {
649     int i;
650 
651     DebugPrint("Resetting buffer pool...\n");
652 
653     Buffers[0].Number   = 0;
654     Buffers[0].Prepared = 0;
655     Buffers[0].Next     = &Buffers[1];
656 
657     for (i = 1; i < DATA_BLOCK_NUM - 1; i++)
658     {
659         Buffers[i].Number   = i;
660         Buffers[i].Prepared = 0;
661         Buffers[i].Next     = &Buffers[i + 1];
662     }
663 
664     Buffers[i].Number   = i;
665     Buffers[i].Prepared = 0;
666     Buffers[i].Next     = NULL;
667 
668     FreeBuffers     = &Buffers[0];
669     NumBuffersInUse = 0;
670 
671     DebugPrint("Buffer pool reset.\n", NumBuffersInUse);
672 }
673 
674 /*****************************************************************************************************************************/
675 
GetBuffer()676 static struct MMBuffer * GetBuffer()
677 {
678     struct MMBuffer *   b;
679 
680     DebugPrint("%2d: Getting buffer...\n", NumBuffersInUse);
681 
682     EnterCriticalSection(&critSect);
683 
684     if (FreeBuffers)
685     {
686     	b           = (struct MMBuffer *)FreeBuffers;
687         FreeBuffers = FreeBuffers->Next;
688         NumBuffersInUse++;
689 
690     /** If this buffer is still prepared we can safely unprepare it because we got it from the free buffer list. **/
691 
692         if (b->Prepared)
693         {
694             waveOutUnprepareHeader(hDevice, (LPWAVEHDR) b->Head, sizeof(WAVEHDR));
695 
696             b->Prepared = 0;
697         }
698 
699         b->Next     = NULL;
700     }
701     else
702         b = NULL;
703 
704     LeaveCriticalSection(&critSect);
705 
706     DebugPrint("%2d: Got buffer.\n", NumBuffersInUse);
707 
708     return b;
709 }
710 
711 /*****************************************************************************************************************************/
712 
PutBuffer(struct MMBuffer * b)713 static void PutBuffer(struct MMBuffer * b)
714 {
715     DebugPrint("%2d: Putting buffer...\n", NumBuffersInUse);
716 
717     b->Next     = (struct MMBuffer *)FreeBuffers;
718     FreeBuffers = b;
719     NumBuffersInUse--;
720 
721     DebugPrint("%2d: Buffer put.\n", NumBuffersInUse);
722 }
723 
724 /*****************************************************************************************************************************/
725 
WaitForBuffer(int WaitForAllBuffers)726 static void WaitForBuffer(int WaitForAllBuffers)
727 {
728   int numbuf;
729 
730     if (WaitForAllBuffers)
731     {
732         DebugPrint("%2d: Waiting for all buffers to be dequeued...\n", NumBuffersInUse);
733 
734 	while (1) {
735 	  EnterCriticalSection(&critSect);
736 	  numbuf = NumBuffersInUse;
737 	  if (numbuf || OutputWorking) {
738             LeaveCriticalSection(&critSect);
739 	    Sleep(BufferDelay);
740 	    continue;
741 	  }
742 	  break;
743 	}
744 	LeaveCriticalSection(&critSect);
745 
746 
747 //        while (NumBuffersInUse)
748 //            Sleep(BufferDelay);
749 
750         DebugPrint("%2d: All buffers dequeued.\n", NumBuffersInUse);
751 
752         BufferPoolReset();
753     }
754     else
755     {
756         DebugPrint("%2d: Waiting %dms...\n", NumBuffersInUse, BufferDelay);
757 
758 		#if !defined ( IA_W32GUI ) && !defined ( IA_W32G_SYN )
759 //		#if !defined ( IA_W32GUI )
760         if(ctl->trace_playing)
761             Sleep(0);
762         else
763     #endif
764             Sleep(BufferDelay);
765 
766         DebugPrint("%2d: Wait finished.\n", NumBuffersInUse);
767     }
768 }
769 
770 /*****************************************************************************************************************************/
771 
772 #define DEVLIST_MAX 20
print_device_list(void)773 static void print_device_list(void){
774 	UINT num;
775 	int i, list_num;
776 	WAVEOUTCAPS woc;
777 	typedef struct tag_DEVICELIST{
778 		int  deviceID;
779 		char name[256];
780 	} DEVICELIST;
781 	DEVICELIST device[DEVLIST_MAX];
782 	num = waveOutGetNumDevs();
783 	list_num=0;
784 	for(i = 0 ; i < num  && i < DEVLIST_MAX ; i++){
785 		if (MMSYSERR_NOERROR == waveOutGetDevCaps((UINT)i, &woc, sizeof(woc)) ){
786 			device[list_num].deviceID=i;
787 			strcpy(device[list_num].name, woc.szPname);
788 			list_num++;
789 		}
790 	}
791 	for(i=0;i<list_num;i++){
792 		ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%2d %s", device[i].deviceID, device[i].name);
793 	}
794 }
795 
DebugPrint(const char * format,...)796 static void DebugPrint(const char *format, ...)
797 {
798 #ifdef DEBUG
799 	CHAR b[256];
800 	va_list ap;
801 
802 	va_begin(ap, format);
803 	wvsprintf(b, format, ap);
804 	va_end(ap);
805 	OutputDebugString(b);
806 #endif
807 }
808 
809