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