OSDN Git Service

Merge UnkoTim220
[timidity41/timidity41.git] / timidity / w32_a.c
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
31
32 #include "timidity.h"
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #ifndef NO_STRING_H
37 #include <string.h>
38 #else
39 #include <strings.h>
40 #endif
41 #include <windows.h>
42
43 #include "timidity.h"
44 #include "output.h"
45 #include "controls.h"
46 #include "timer.h"
47 #include "instrum.h"
48 #include "playmidi.h"
49 #include "mblock.h"
50
51 ///r
52 #include "w32_a.h"
53 #include "common.h"
54 #include "miditrace.h"
55
56 int opt_wmme_device_id = -1;
57 int opt_wave_format_ext = 1;
58 int opt_wmme_buffer_bits = DEFAULT_AUDIO_BUFFER_BITS;
59 int opt_wmme_buffer_num = 64;
60
61 /*****************************************************************************************************************************/
62
63 static int  open_output     (void); /* 0=success, 1=warning, -1=fatal error */
64 static void close_output    (void);
65 static int  output_data     (const uint8 * Data, size_t Size);
66 static int  acntl           (int request, void * arg);
67 static int  detect          (void);
68
69 /*****************************************************************************************************************************/
70
71 #define dpm w32_play_mode
72
73 PlayMode dpm =
74 {
75     DEFAULT_RATE,
76     PE_16BIT | PE_SIGNED,
77     PF_PCM_STREAM|PF_CAN_TRACE|PF_BUFF_FRAGM_OPT,
78     -1,
79     {32},
80     "Windows audio driver", 'd',
81     NULL,
82     open_output,
83     close_output,
84     output_data,
85     acntl,
86         detect
87 };
88
89 /*****************************************************************************************************************************/
90
91 ///r
92 typedef struct {
93     WAVEFORMATEX    Format;
94     union {
95         WORD wValidBitsPerSample;       /* bits of precision  */
96         WORD wSamplesPerBlock;          /* valid if wBitsPerSample==0 */
97         WORD wReserved;                 /* If neither applies, set to zero. */
98     } Samples;
99     DWORD           dwChannelMask;      /* which channels are */ /* present in stream  */
100     GUID            SubFormat;
101 } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
102
103 typedef WAVEFORMATEXTENSIBLE *PWAVEFORMATEXTENSIBLE, *LPWAVEFORMATEXTENSIBLE;
104
105 #define  WAVE_FORMAT_UNKNOWN      0x0000
106 #define  WAVE_FORMAT_PCM          0x0001
107 #define  WAVE_FORMAT_ADPCM        0x0002
108 #define  WAVE_FORMAT_IEEE_FLOAT   0x0003
109 #define  WAVE_FORMAT_ALAW         0x0006
110 #define  WAVE_FORMAT_MULAW        0x0007
111 #define  WAVE_FORMAT_EXTENSIBLE   0xFFFE
112
113 #define SPEAKER_FRONT_LEFT        0x1
114 #define SPEAKER_FRONT_RIGHT       0x2
115 #define SPEAKER_FRONT_CENTER      0x4
116 #define SPEAKER_MONO              (SPEAKER_FRONT_CENTER)
117 #define SPEAKER_STEREO            (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT)
118
119 /*****************************************************************************************************************************/
120
121 #define DIM(a) sizeof(a) / sizeof(a[0])
122
123 static const char * mmsyserr_code_string[] =
124 {
125     "no error",
126     "unspecified error",
127     "device ID out of range",
128     "driver failed enable",
129     "device already allocated",
130     "device handle is invalid",
131     "no device driver present",
132     "memory allocation error",
133     "function isn't supported",
134     "error value out of range",
135     "invalid flag passed",
136     "invalid parameter passed",
137     "handle being used",
138 };
139
140 static const char * waverr_code_sring[] =
141 {
142     "unsupported wave format",
143     "still something playing",
144     "header not prepared",
145     "device is synchronous",
146 };
147
148 static const char * MMErrorMessage(MMRESULT ErrorCode)
149 {
150     static char s[32];
151
152     if (ErrorCode >= WAVERR_BASE)
153     {
154         ErrorCode -= WAVERR_BASE;
155
156         if (ErrorCode > DIM(waverr_code_sring))
157         {
158             wsprintf(s, "Unknown wave error %d", ErrorCode);
159             return s;
160         }
161         else
162             return waverr_code_sring[ErrorCode];
163     }
164     else
165     if (ErrorCode > DIM(mmsyserr_code_string))
166     {
167         wsprintf(s, "Unknown multimedia error %d", ErrorCode);
168         return s;
169     }
170     else
171         return mmsyserr_code_string[ErrorCode];
172 }
173
174 #undef DIM
175
176 #ifdef OUTPUT_DEBUG_STR
177 static void DebugPrint(const char *format, ...);
178 #define DEBUGPRINT DebugPrint
179 #else
180 #define DEBUGPRINT (void)
181 #endif
182
183 /*****************************************************************************************************************************/
184
185 struct MMBuffer
186 {
187     int                 Number;
188     int                 Prepared;   // Non-zero if this buffer has been prepared.
189     HGLOBAL             hData;
190     void *              Data;
191     HGLOBAL             hHead;
192     WAVEHDR *           Head;
193     struct MMBuffer *   Next;
194 };
195
196 static struct MMBuffer *            Buffers;
197 static volatile struct MMBuffer *   FreeBuffers;
198 static volatile int                 NumBuffersInUse;
199 static HWAVEOUT                     hDevice;
200 static int                          BufferDelay; // in milliseconds
201 static int                          BufferBlockDelay; // in milliseconds
202 static DWORD                        CurrentTime = 0;
203 static volatile BOOL                DriverClosing = FALSE;
204 static volatile BOOL                OutputWorking = FALSE;
205 static const int                    AllowSynchronousWaveforms = 1;
206 static int data_block_size;
207 static int data_block_num = 64;
208 static int data_block_trunc_size = sizeof(int16) * 2 * (1L << DEFAULT_AUDIO_BUFFER_BITS);
209
210 /*****************************************************************************************************************************/
211
212 static void BufferPoolReset(void)
213 {
214     int i;
215
216     DEBUGPRINT("Resetting buffer pool...\n");
217     Buffers[0].Number   = 0;
218     Buffers[0].Prepared = 0;
219     Buffers[0].Next     = &Buffers[1];
220     for (i = 1; i < data_block_num - 1; i++)
221     {
222         Buffers[i].Number   = i;
223         Buffers[i].Prepared = 0;
224         Buffers[i].Next     = &Buffers[i + 1];
225     }
226     Buffers[i].Number   = i;
227     Buffers[i].Prepared = 0;
228     Buffers[i].Next     = NULL;
229     FreeBuffers     = &Buffers[0];
230     NumBuffersInUse = 0;
231     DEBUGPRINT("Buffer pool reset.\n", NumBuffersInUse);
232 }
233
234 static struct MMBuffer * GetBuffer()
235 {
236     struct MMBuffer *   b;
237
238     DEBUGPRINT("%2d: Getting buffer...\n", NumBuffersInUse);
239     EnterCriticalSection(&critSect);
240     if (FreeBuffers)
241     {
242         b           = (struct MMBuffer *)FreeBuffers;
243         FreeBuffers = FreeBuffers->Next;
244         NumBuffersInUse++;
245     /** If this buffer is still prepared we can safely unprepare it because we got it from the free buffer list. **/
246         if (b->Prepared)
247         {
248             waveOutUnprepareHeader(hDevice, (LPWAVEHDR) b->Head, sizeof(WAVEHDR));
249             b->Prepared = 0;
250         }
251         b->Next     = NULL;
252     }
253     else
254         b = NULL;
255     LeaveCriticalSection(&critSect);
256     DEBUGPRINT("%2d: Got buffer.\n", NumBuffersInUse);
257     return b;
258 }
259
260 static void PutBuffer(struct MMBuffer * b)
261 {
262     DEBUGPRINT("%2d: Putting buffer...\n", NumBuffersInUse);
263     b->Next     = (struct MMBuffer *)FreeBuffers;
264     FreeBuffers = b;
265     NumBuffersInUse--;
266     DEBUGPRINT("%2d: Buffer put.\n", NumBuffersInUse);
267 }
268
269 static void CALLBACK OnPlaybackEvent(HWAVE hWave, UINT Msg, DWORD_PTR UserData, DWORD_PTR Param1, DWORD_PTR Param2)
270 {
271     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Msg: 0x%08X, Num. buffers in use: %d", Msg, NumBuffersInUse);
272     switch (Msg)
273     {
274     case WOM_OPEN:
275         DEBUGPRINT("%2d: Device opened.\n", NumBuffersInUse);
276         break;
277     case WOM_CLOSE:
278         DEBUGPRINT("%2d: Device closed.\n", NumBuffersInUse);
279         break;
280     case WOM_DONE:
281         EnterCriticalSection(&critSect);
282         PutBuffer(&Buffers[((WAVEHDR *)Param1)->dwUser]);
283         LeaveCriticalSection(&critSect);
284         break;
285     default:
286         DEBUGPRINT("%2d: Unknown play back event 0x%08X.\n", NumBuffersInUse, Msg);
287         break;        
288     }
289 }
290
291 static void print_device_list(void)
292 {
293         UINT num;
294         int i, list_num;
295         WAVEOUTCAPS woc;
296         DEVICELIST device[DEVLIST_MAX];
297
298         num = waveOutGetNumDevs();
299         list_num=0;
300         for(i = 0 ; i < num  && i < DEVLIST_MAX ; i++){
301                 if (MMSYSERR_NOERROR == waveOutGetDevCaps((UINT)i, &woc, sizeof(woc)) ){
302                         device[list_num].deviceID=i;
303                         strcpy(device[list_num].name, woc.szPname);
304                         list_num++;
305                 }
306         }
307         for(i=0;i<list_num;i++){
308                 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%2d %s", device[i].deviceID, device[i].name);
309         }
310 }
311
312 /*****************************************************************************************************************************/
313
314 static int open_output(void)
315 {
316     int             i;
317         WAVEFORMATEXTENSIBLE wfe = {0};
318         WAVEFORMATEX    *pwf = NULL;
319     WAVEOUTCAPS     woc;
320     MMRESULT        Result;
321     UINT            uDeviceID, DeviceID;
322         int ret;
323         int tmp;
324         int format_ext;
325         GUID guid_WAVE_FORMAT = {WAVE_FORMAT_UNKNOWN,0x0000,0x0010,{0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
326
327 /** Check if there is at least one audio device. **/
328     if (waveOutGetNumDevs() == 0)
329     {
330         ctl->cmsg (CMSG_ERROR, VERB_NORMAL, "No audio devices present!");
331         return -1;
332     }
333         opt_wmme_device_id = opt_output_device_id != -3 ? opt_output_device_id : opt_wmme_device_id; 
334         if (opt_wmme_device_id == -2){
335                 print_device_list();
336         return -1;
337         }
338 /** They can't mean these. **/
339         dpm.encoding &= ~(PE_BYTESWAP);
340         if (dpm.encoding & (PE_16BIT | PE_24BIT | PE_32BIT | PE_F32BIT | PE_64BIT | PE_F64BIT)){
341         dpm.encoding |= PE_SIGNED;
342         }else // 8bit PE_ULAW PE_ALAW only unsigned
343         dpm.encoding &= ~PE_SIGNED;
344         format_ext = (dpm.encoding & (PE_ULAW | PE_ALAW)) ? 0 : opt_wave_format_ext;
345         if(format_ext){
346                 pwf = &wfe.Format;
347                 memcpy(&wfe.SubFormat, &guid_WAVE_FORMAT, sizeof(GUID));
348                 pwf->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
349                 pwf->cbSize       = (WORD)22;
350         }else{
351                 pwf = (WAVEFORMATEX *)&wfe;
352                 pwf->cbSize       = (WORD)0;
353         }
354         if(dpm.encoding & PE_16BIT){
355                 if(format_ext){                 
356                         wfe.SubFormat.Data1 = WAVE_FORMAT_PCM;
357                         wfe.Samples.wValidBitsPerSample = 16;
358                         pwf->wBitsPerSample = (WORD) 16;
359                 }else{
360                         pwf->wFormatTag = WAVE_FORMAT_PCM;
361                         pwf->wBitsPerSample = (WORD) 16;
362                 }
363         }else if(dpm.encoding & PE_24BIT){
364                 if(format_ext){
365                         wfe.SubFormat.Data1 = WAVE_FORMAT_PCM;
366                         wfe.Samples.wValidBitsPerSample = 24;
367                         pwf->wBitsPerSample = (WORD) 24;
368                 }else{
369                         pwf->wFormatTag = WAVE_FORMAT_PCM;
370                         pwf->wBitsPerSample = (WORD) 24;
371                 }
372         }else if(dpm.encoding & PE_32BIT){
373                 if(format_ext){
374                         wfe.SubFormat.Data1 = WAVE_FORMAT_PCM;
375                         wfe.Samples.wValidBitsPerSample = 32;
376                         pwf->wBitsPerSample = (WORD) 32;                        
377                 }else{
378                         pwf->wFormatTag = WAVE_FORMAT_PCM;
379                         pwf->wBitsPerSample = (WORD) 32;
380                 }
381         }else if(dpm.encoding & PE_F32BIT){
382                 if(format_ext){
383                         wfe.SubFormat.Data1 = WAVE_FORMAT_IEEE_FLOAT;
384                         wfe.Samples.wValidBitsPerSample = 32;
385                         pwf->wBitsPerSample = (WORD) 32;                        
386                 }else{
387                         pwf->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
388                         pwf->wBitsPerSample = (WORD) 32;
389                 }
390         }else if(dpm.encoding & PE_64BIT){
391                 if(format_ext){
392                         wfe.SubFormat.Data1 = WAVE_FORMAT_PCM;
393                         wfe.Samples.wValidBitsPerSample = 64;
394                         pwf->wBitsPerSample = (WORD) 64;                        
395                 }else{
396                         pwf->wFormatTag = WAVE_FORMAT_PCM;
397                         pwf->wBitsPerSample = (WORD) 64;
398                 }
399         }else if(dpm.encoding & PE_F64BIT){
400                 if(format_ext){
401                         wfe.SubFormat.Data1 = WAVE_FORMAT_IEEE_FLOAT;
402                         wfe.Samples.wValidBitsPerSample = 64;
403                         pwf->wBitsPerSample = (WORD) 64;                        
404                 }else{
405                         pwf->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
406                         pwf->wBitsPerSample = (WORD) 64;
407                 }               
408         }else if(dpm.encoding & PE_ALAW){
409                 if(format_ext){
410                         wfe.SubFormat.Data1 = WAVE_FORMAT_ALAW;
411                         wfe.Samples.wValidBitsPerSample = 8;
412                         pwf->wBitsPerSample = (WORD) 8;                 
413                 }else{
414                         pwf->wFormatTag = WAVE_FORMAT_ALAW;
415                         pwf->wBitsPerSample = (WORD) 8;
416                 }
417         }else if(dpm.encoding & PE_ULAW){
418                 if(format_ext){
419                         wfe.SubFormat.Data1 = WAVE_FORMAT_MULAW;
420                         wfe.Samples.wValidBitsPerSample = 8;
421                         pwf->wBitsPerSample = (WORD) 8;                 
422                 }else{
423                         pwf->wFormatTag = WAVE_FORMAT_MULAW;
424                         pwf->wBitsPerSample = (WORD) 8;
425                 }
426         }else{ // 8bit
427                 if(format_ext){
428                         wfe.SubFormat.Data1 = WAVE_FORMAT_PCM;
429                         wfe.Samples.wValidBitsPerSample = 8;
430                         pwf->wBitsPerSample = (WORD) 8;                 
431                 }else{
432                         pwf->wFormatTag = WAVE_FORMAT_PCM;
433                         pwf->wBitsPerSample = (WORD) 8;
434                 }
435         }
436         pwf->nChannels       = (WORD)dpm.encoding & PE_MONO ? 1 : 2;
437         pwf->nSamplesPerSec  = (DWORD)dpm.rate;
438         pwf->nBlockAlign     = (WORD)(pwf->nChannels * pwf->wBitsPerSample / 8);
439         pwf->nAvgBytesPerSec = (DWORD)pwf->nSamplesPerSec * pwf->nBlockAlign;
440         wfe.dwChannelMask = pwf->nChannels == 1 ? SPEAKER_MONO : SPEAKER_STEREO;
441     if (dpm.extra_param[0] < 2)
442     {
443         ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Too small -B option: %d,X", dpm.extra_param[0]);
444         dpm.extra_param[0] = 2;
445     }
446     if (audio_buffer_bits < 7)
447     {
448         ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Too small -B option: X,%d", audio_buffer_bits);
449         audio_buffer_bits = 7;
450     }
451 /** check buffer size **/
452         tmp = dpm.extra_param[0] * audio_buffer_size;
453         if(tmp < 4096)
454     {
455         ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Too small -B option: %d,%d", dpm.extra_param[0], audio_buffer_bits);
456                 dpm.extra_param[0] = DEFAULT_AUDIO_BUFFER_NUM;
457                 audio_buffer_bits = DEFAULT_AUDIO_BUFFER_BITS;
458     }
459         data_block_num = dpm.extra_param[0];
460         data_block_size = audio_buffer_size;
461         data_block_trunc_size = data_block_size * pwf->nBlockAlign;
462 /** Open the device. **/
463     DEBUGPRINT("Opening device...\n");
464         hDevice = 0;
465     DriverClosing = FALSE;
466         uDeviceID = opt_wmme_device_id == -1 ? WAVE_MAPPER : (UINT)opt_wmme_device_id;   
467         if (AllowSynchronousWaveforms)
468                 Result = waveOutOpen(&hDevice, uDeviceID, (WAVEFORMATEX *) &wfe, (DWORD_PTR) OnPlaybackEvent, 0, CALLBACK_FUNCTION | WAVE_ALLOWSYNC);
469         else
470                 Result = waveOutOpen(&hDevice, uDeviceID, (WAVEFORMATEX *) &wfe, (DWORD_PTR) OnPlaybackEvent, 0, CALLBACK_FUNCTION);
471     if (Result)
472     {
473         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, pwf->nChannels, MMErrorMessage(Result));
474         return -1;
475     }
476     else
477         {
478         DEBUGPRINT("Device opened.\n");
479         }
480 /** Get the device ID. **/
481     DeviceID = 0;
482     waveOutGetID(hDevice, &DeviceID);
483 /** Get the device capabilities. **/
484     memset(&woc, 0, sizeof(WAVEOUTCAPS));
485     Result = waveOutGetDevCaps(DeviceID, &woc, sizeof(WAVEOUTCAPS));
486     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Device ID: %d",              DeviceID);
487     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Manufacture ID: %d",         woc.wMid);
488     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Product ID: %d",             woc.wPid);
489     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Driver version: %d",         woc.vDriverVersion);
490     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Product name: %s",           woc.szPname);
491     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Formats supported: 0x%08X",  woc.dwFormats);
492     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Max. channels: %d",          woc.wChannels);
493     ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Supported features: 0x%08X", woc.dwSupport);
494 /** Calculate the buffer delay. **/
495     BufferDelay = data_block_size * data_block_num * 1000 / dpm.rate;
496         BufferBlockDelay = data_block_size * 1000 / dpm.rate / 4;
497 /** Create the buffer pool. **/
498     Buffers = (struct MMBuffer *) safe_malloc(data_block_num * sizeof(struct MMBuffer));        
499     for (i = 0; i < data_block_num; i++)
500     {
501         struct MMBuffer *   b;
502
503         b = &Buffers[i];
504         b->hData = GlobalAlloc(GMEM_ZEROINIT, data_block_trunc_size);
505         b->Data  = GlobalLock (b->hData);
506         b->hHead = GlobalAlloc(GMEM_ZEROINIT, sizeof(WAVEHDR));
507         b->Head  = GlobalLock (b->hHead);
508     }
509     BufferPoolReset();
510 /** Set the file descriptor. **/
511     dpm.fd = 0;
512     return 0;
513 }
514
515 static void close_output(void)
516 {
517         int i, flg;
518
519     if (dpm.fd == -1)
520                 return; 
521 /**  WaitForAllBuffers **/
522     DEBUGPRINT("%2d: Waiting for all buffers to be dequeued...\n", NumBuffersInUse);
523         for (;;) {
524                 EnterCriticalSection(&critSect);
525                 flg = (NumBuffersInUse || OutputWorking) ? 1 : 0;
526                 LeaveCriticalSection(&critSect);
527                 if(!flg) break;
528                 Sleep(BufferDelay);
529         }
530     DEBUGPRINT("%2d: All buffers dequeued.\n", NumBuffersInUse);
531     BufferPoolReset();
532     DEBUGPRINT("Closing device...\n");
533     waveOutReset(hDevice);
534     waveOutClose(hDevice);
535     DEBUGPRINT("Device closed.\n");
536 /** Free all buffers. **/
537     for (i = 0; i < data_block_num; i++)
538     {
539         struct MMBuffer *   block;
540
541         block = &Buffers[i];
542         GlobalUnlock(block->hHead);
543         GlobalFree  (block->hHead);
544         GlobalUnlock(block->hData);
545         GlobalFree  (block->hData);
546     }
547     safe_free(Buffers);
548     Buffers = NULL;
549 /** Reset the file descriptor. **/
550     dpm.fd = -1;
551 }
552
553 static int output_data(const uint8 *Data, size_t Size)
554 {
555     const uint8 *  d;
556     int32   s;
557     int32   c;
558     const int32  max_continue = 1164;
559         
560     if (!hDevice)
561                 return -1;      
562     OutputWorking = TRUE;
563     d = Data;
564     s = Size;
565         c = max_continue;
566     while (!DriverClosing && dpm.fd != -1 && s > 0 && c > 0)
567     {
568         int32               n;
569         struct MMBuffer *   b;
570         MMRESULT            Result;
571         LPWAVEHDR           wh;
572
573         if ((b = GetBuffer()) == NULL)
574         {
575                         DEBUGPRINT("%2d: WaitForBuffer %dms...\n", NumBuffersInUse, BufferBlockDelay);
576                         Sleep(BufferBlockDelay); /**  WaitForBuffer **/
577                         --c;
578             continue;
579         }
580                 if (DriverClosing || dpm.fd == -1) {
581                         break;
582                 }
583                 n = (s <= data_block_trunc_size) ? s : data_block_trunc_size;
584         CopyMemory(b->Data, d, n);
585         wh = b->Head;
586         wh->dwBufferLength = n;
587         wh->lpData         = b->Data;
588         wh->dwUser         = b->Number;
589     /** Prepare the buffer. **/
590         DEBUGPRINT("%2d: Preparing buffer %d...\n", NumBuffersInUse, wh->dwUser);
591         Result = waveOutPrepareHeader(hDevice, wh, sizeof(WAVEHDR));
592         if (Result)
593         {
594             DEBUGPRINT("%2d: Buffer preparation failed.\n", NumBuffersInUse);
595             ctl->cmsg (CMSG_ERROR, VERB_NORMAL, "waveOutPrepareHeader(): %s", MMErrorMessage(Result));
596             return -1;
597         }
598         else
599                 {
600             DEBUGPRINT("%2d: Buffer %d prepared.\n", NumBuffersInUse, wh->dwUser);
601                 }
602         b->Prepared = 1;
603     /** Queue the buffer. **/
604         DEBUGPRINT("%2d: Queueing buffer %d...\n", NumBuffersInUse, wh->dwUser);
605         Result = waveOutWrite(hDevice, wh, sizeof(WAVEHDR));
606         if (Result)
607         {
608             DEBUGPRINT("%2d: Buffer queueing failed.\n", NumBuffersInUse);
609             ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "waveOutWrite(): %s", MMErrorMessage(Result));
610             return -1;
611         }
612         else
613                 {
614             DEBUGPRINT("%2d: Buffer %d queued.\n", NumBuffersInUse, wh->dwUser);
615                 }
616         d += n;
617         s -= n;
618                 c = max_continue;
619     }   
620     OutputWorking = FALSE;
621     return 0;
622 }
623
624 static int acntl(int request, void *arg)
625 {
626     switch(request)
627     {
628     case PM_REQ_GETQSIZ:
629         *(int *)arg = (data_block_num-1) * data_block_trunc_size;
630         return 0;
631 /*
632     case PM_REQ_GETFILLABLE:
633                 *(int *)arg = (data_block_num - NumBuffersInUse - 1) * data_block_size;
634                 return 0;
635 */
636     case PM_REQ_GETFILLED:
637                 *(int *)arg = NumBuffersInUse * data_block_trunc_size;
638     return 0;
639
640     case PM_REQ_DISCARD:
641                 DEBUGPRINT("Resetting audio device.\n");
642                 waveOutReset(hDevice);
643                 close_output();
644                 open_output();
645                 DEBUGPRINT("Audio device reset.\n");
646                 return 0;
647
648     case PM_REQ_FLUSH:
649                 close_output();
650                 open_output();
651         return 0;
652  
653     case PM_REQ_PLAY_START: /* Called just before playing */
654     case PM_REQ_PLAY_END: /* Called just after playing */
655         return 0;
656     }
657     return -1;
658 }
659
660 static int detect(void)
661 {
662         if (waveOutGetNumDevs() == 0)
663                 return 0;       /* not found */
664         return 1;       /* found */
665 }
666
667 /*****************************************************************************************************************************/
668
669 int wmme_device_list(DEVICELIST *device)
670 {
671         int i, num;
672         WAVEOUTCAPS woc;
673
674         num = waveOutGetNumDevs();
675         for(i = -1 ; i < num  && i < (DEVLIST_MAX - 2) ; i++){ // -1, 0
676                 waveOutGetDevCaps((UINT)i, &woc, sizeof(woc));
677                 device[i+1].deviceID=i;
678                 strcpy(device[i+1].name, woc.szPname);
679         }
680         return num;
681 }