Removed warning.
[wine] / multimedia / mciwave.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*                                 
3  * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
4  *
5  * Copyright 1994 Martin Ayotte
6  */
7 /*
8  * FIXME:
9  *      - record/play should and must be done asynchronous
10  *      - segmented/linear pointer problems (lpData in waveheaders,W*_DONE cbs)
11  */
12
13 #define EMULATE_SB16
14
15 #define DEBUG_MCIWAVE
16
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <sys/ioctl.h>
22 #include "windows.h"
23 #include "user.h"
24 #include "driver.h"
25 #include "mmsystem.h"
26 #include "heap.h"
27 #include "ldt.h"
28 #include "debug.h"
29 #include "multimedia.h"
30
31 #define MAX_MCIWAVEDRV  (1)
32
33 typedef struct {
34     int                         nUseCount;      /* Incremented for each shared open */
35     BOOL16                      fShareable;     /* TRUE if first open was shareable */
36     WORD                        wNotifyDeviceID;/* MCI device ID with a pending notification */
37     HANDLE16                    hCallback;      /* Callback handle for pending notification */
38     HMMIO32                     hFile;          /* mmio file handle open as Element */
39     MCI_WAVE_OPEN_PARMS32A      openParms;
40     WAVEOPENDESC                waveDesc;
41     PCMWAVEFORMAT               WaveFormat;
42     WAVEHDR                     WaveHdr;
43     BOOL16                      fInput;         /* FALSE = Output, TRUE = Input */
44     WORD                        dwStatus;       /* one from MCI_MODE_xxxx */
45     DWORD                       dwMciTimeFormat;/* One of the supported MCI_FORMAT_xxxx */
46     DWORD                       dwFileOffset;   /* Offset of chunk in mmio file */
47     DWORD                       dwLength;       /* number of bytes in chunk for playing */
48     DWORD                       dwPosition;     /* position in bytes in chunk for playing */
49 } WINE_MCIWAVE;
50
51 static WINE_MCIWAVE     MCIWaveDev[MAX_MCIWAVEDRV];
52
53 /*======================================================================*
54  *                          MCI WAVE implemantation                     *
55  *======================================================================*/
56
57 /**************************************************************************
58  *                              WAVE_mciGetOpenDev              [internal]      
59  */
60 static WINE_MCIWAVE*  WAVE_mciGetOpenDev(UINT16 wDevID)
61 {
62     if (wDevID >= MAX_MCIWAVEDRV || MCIWaveDev[wDevID].nUseCount == 0) {
63         WARN(mciwave, "Invalid wDevID=%u\n", wDevID);
64         return 0;
65     }
66     return &MCIWaveDev[wDevID];
67 }
68
69 static  DWORD   WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE* wmw, DWORD val)
70 {
71     DWORD       ret = 0;
72
73     switch (wmw->dwMciTimeFormat) {
74     case MCI_FORMAT_MILLISECONDS:
75         ret = (val * 1000) / wmw->WaveFormat.wf.nAvgBytesPerSec;
76         break;
77     case MCI_FORMAT_BYTES:
78         ret = val;
79         break;
80     case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
81         ret = (val * 8) / wmw->WaveFormat.wBitsPerSample;
82         break;
83     default:
84         WARN(mciwave, "Bad time format %lu!\n", wmw->dwMciTimeFormat);
85     }
86     TRACE(mciwave, "val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
87     return ret;
88 }
89
90 static  DWORD   WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE* wmw, DWORD val)
91 {
92     DWORD       ret = 0;
93
94     switch (wmw->dwMciTimeFormat) {
95     case MCI_FORMAT_MILLISECONDS:
96         ret = (val * wmw->WaveFormat.wf.nAvgBytesPerSec) / 1000;
97         break;
98     case MCI_FORMAT_BYTES:
99         ret = val;
100         break;
101     case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
102         ret = (val * wmw->WaveFormat.wBitsPerSample) / 8;
103         break;
104     default:
105         WARN(mciwave, "Bad time format %lu!\n", wmw->dwMciTimeFormat);
106     }
107     TRACE(mciwave, "val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
108     return ret;
109 }
110
111 static  DWORD WAVE_mciReadFmt(WINE_MCIWAVE* wmw, MMCKINFO* pckMainRIFF)
112 {
113     MMCKINFO    mmckInfo;
114
115     mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
116     if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0)
117         return MCIERR_INVALID_FILE;
118     TRACE(mciwave, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
119           (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
120     if (mmioRead32(wmw->hFile, (HPSTR)&wmw->WaveFormat,
121                    (long)sizeof(PCMWAVEFORMAT)) != (long)sizeof(PCMWAVEFORMAT))
122         return MCIERR_INVALID_FILE;
123
124     TRACE(mciwave, "wFormatTag=%04X !\n",   wmw->WaveFormat.wf.wFormatTag);
125     TRACE(mciwave, "nChannels=%d \n",       wmw->WaveFormat.wf.nChannels);
126     TRACE(mciwave, "nSamplesPerSec=%ld\n",  wmw->WaveFormat.wf.nSamplesPerSec);
127     TRACE(mciwave, "nAvgBytesPerSec=%ld\n", wmw->WaveFormat.wf.nAvgBytesPerSec);
128     TRACE(mciwave, "nBlockAlign=%d \n",     wmw->WaveFormat.wf.nBlockAlign);
129     TRACE(mciwave, "wBitsPerSample=%u !\n", wmw->WaveFormat.wBitsPerSample);
130     mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
131     if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0)
132         return MCIERR_INVALID_FILE;
133     TRACE(mciwave,"Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
134           (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
135     TRACE(mciwave, "nChannels=%d nSamplesPerSec=%ld\n",
136           wmw->WaveFormat.wf.nChannels, wmw->WaveFormat.wf.nSamplesPerSec);
137     wmw->dwLength = mmckInfo.cksize;
138     wmw->dwFileOffset = mmioSeek32(wmw->hFile, 0, SEEK_CUR); /* >= 0 */
139     return 0;
140 }
141
142 /**************************************************************************
143  *                      WAVE_mciOpen                            [internal]
144  */
145 static DWORD WAVE_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMS32A lpOpenParms)
146 {
147     DWORD               dwRet = 0;
148     DWORD               dwDeviceID;
149     WINE_MCIWAVE*       wmw;
150     
151     TRACE(mciwave,"(%04X, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
152     if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
153     
154     if (wDevID >= MAX_MCIWAVEDRV) {
155         WARN(mciwave, "Invalid wDevID=%u\n", wDevID);
156         return MCIERR_INVALID_DEVICE_ID;
157     }
158     
159     wmw = &MCIWaveDev[wDevID];
160     
161     if (wmw->nUseCount > 0) {
162         /* The driver already open on this channel */
163         /* If the driver was opened shareable before and this open specifies */
164         /* shareable then increment the use count */
165         if (wmw->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
166             ++wmw->nUseCount;
167         else
168             return MCIERR_MUST_USE_SHAREABLE;
169     } else {
170         wmw->nUseCount = 1;
171         wmw->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
172     }
173     
174     dwDeviceID = lpOpenParms->wDeviceID;
175     
176     wmw->fInput = FALSE;
177     
178     TRACE(mciwave, "wDevID=%04X (lpParams->wDeviceID=%08lX)\n", wDevID, dwDeviceID);
179
180     if (dwFlags & MCI_OPEN_ELEMENT) {
181         LPCSTR          lpstrElementName;       
182         
183         lpstrElementName = lpOpenParms->lpstrElementName;
184         
185         /*FIXME : what should be done id wmw->hFile is already != 0, or the driver is playin' */
186         TRACE(mciwave,"MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName);
187         if (lpstrElementName && (strlen(lpstrElementName) > 0)) {
188             wmw->hFile = mmioOpen32A(lpstrElementName, NULL, 
189                                      MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_EXCLUSIVE);
190             if (wmw->hFile == 0) {
191                 WARN(mciwave, "can't find file='%s' !\n", lpstrElementName);
192                 return MCIERR_FILE_NOT_FOUND;
193             }
194         } else {
195             wmw->hFile = 0;
196         }
197     }
198     TRACE(mciwave,"hFile=%u\n", wmw->hFile);
199
200     memcpy(&wmw->openParms, lpOpenParms, sizeof(MCI_WAVE_OPEN_PARMS32A));
201     wmw->wNotifyDeviceID = dwDeviceID;
202     wmw->dwStatus = MCI_MODE_NOT_READY; /* while loading file contents */
203     
204     wmw->waveDesc.hWave = 0;
205
206     if (wmw->hFile != 0) {
207         MMCKINFO        ckMainRIFF;
208
209         if (mmioDescend(wmw->hFile, &ckMainRIFF, NULL, 0) != 0) {
210             dwRet = MCIERR_INVALID_FILE;
211         } else {
212         TRACE(mciwave, "ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
213               (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize);
214         if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
215                 (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) {
216                 dwRet = MCIERR_INVALID_FILE;
217             } else {
218                 dwRet = WAVE_mciReadFmt(wmw, &ckMainRIFF);
219             }
220         }
221     } else {
222         wmw->dwLength = 0;
223     }
224     if (dwRet == 0) {
225     wmw->WaveFormat.wf.nAvgBytesPerSec = 
226         wmw->WaveFormat.wf.nSamplesPerSec * wmw->WaveFormat.wf.nBlockAlign;
227     wmw->waveDesc.lpFormat = (LPWAVEFORMAT)&wmw->WaveFormat;
228     wmw->dwPosition = 0;
229     
230     /* By default the device will be opened for output, the MCI_CUE function is there to
231      * change from output to input and back
232      */
233     dwRet = wodMessage(wDevID, WODM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
234     wmw->dwStatus = MCI_MODE_STOP;
235     } else {
236         wmw->nUseCount--;
237         if (wmw->hFile != 0)
238             mmioClose32(wmw->hFile, 0);
239         wmw->hFile = 0;
240     }
241     return 0;
242 }
243
244 /**************************************************************************
245  *                               WAVE_mciCue             [internal]
246  */
247 static DWORD WAVE_mciCue(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
248 {
249     /*
250       FIXME
251       
252       This routine is far from complete. At the moment only a check is done on the
253       MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
254       is the default.
255       
256       The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
257       are ignored
258     */
259     
260     DWORD               dwRet;
261     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
262
263     TRACE(mciwave,"(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
264
265     if (wmw == NULL)    return MCIERR_INVALID_DEVICE_ID;
266
267     /* always close elements ? */    
268     if (wmw->hFile != 0) {
269         mmioClose32(wmw->hFile, 0);
270         wmw->hFile = 0;
271     }
272     
273     dwRet = MMSYSERR_NOERROR;  /* assume success */
274
275     if ((dwParam & MCI_WAVE_INPUT) && !wmw->fInput) {
276         dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
277         if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
278         dwRet = widMessage(wDevID, WIDM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
279         wmw->fInput = TRUE;
280     } else if (wmw->fInput) {
281         dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
282         if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
283         dwRet = wodMessage(wDevID, WODM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
284         wmw->fInput = FALSE;
285     }
286     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
287 }
288
289 /**************************************************************************
290  *                              WAVE_mciStop                    [internal]
291  */
292 static DWORD WAVE_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
293 {
294     DWORD               dwRet;
295     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
296     
297     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
298
299     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
300     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
301
302     wmw->dwStatus = MCI_MODE_STOP;
303     wmw->dwPosition = 0;
304     TRACE(mciwave, "wmw->dwStatus=%d\n", wmw->dwStatus);
305
306     if (wmw->fInput)
307         dwRet = widMessage(wDevID, WIDM_STOP, 0, dwFlags, (DWORD)lpParms);
308     else
309         dwRet = wodMessage(wDevID, WODM_STOP, 0, dwFlags, (DWORD)lpParms);
310     
311     if (dwFlags & MCI_NOTIFY) {
312         TRACE(mciwave, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
313         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
314                           wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
315     }
316
317     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
318 }
319
320 /**************************************************************************
321  *                              WAVE_mciClose           [internal]
322  */
323 static DWORD WAVE_mciClose(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
324 {
325     DWORD               dwRet;
326     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
327     
328     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
329     
330     if (wmw == NULL)    return MCIERR_INVALID_DEVICE_ID;
331     
332     if (wmw->dwStatus != MCI_MODE_STOP) {
333         WAVE_mciStop(wDevID, MCI_WAIT, lpParms);
334     }
335     
336     wmw->dwStatus = MCI_MODE_STOP;
337     wmw->nUseCount--;
338
339     if (wmw->nUseCount == 0) {
340         if (wmw->hFile != 0) {
341             mmioClose32(wmw->hFile, 0);
342             wmw->hFile = 0;
343         }
344         if (wmw->fInput)        dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
345         else                    dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
346         
347         if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
348     }
349
350     if (lpParms && (dwFlags & MCI_NOTIFY)) {
351         TRACE(mciwave, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
352         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
353                           wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
354     }
355     return 0;
356 }
357
358 /**************************************************************************
359  *                              WAVE_mciPlay            [internal]
360  */
361 static DWORD WAVE_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
362 {
363     DWORD               end;
364     LONG                bufsize, count;
365     HGLOBAL16           hData;
366     DWORD               dwRet;
367     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
368     
369     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
370     
371     if (wmw == NULL)    return MCIERR_INVALID_DEVICE_ID;
372
373     if (wmw->fInput) {
374         WARN(mciwave, "cannot play on input device\n");
375         return MCIERR_NONAPPLICABLE_FUNCTION;
376     }
377     
378     if (wmw->hFile == 0) {
379         WARN(mciwave, "Can't play: no file='%s' !\n", wmw->openParms.lpstrElementName);
380         return MCIERR_FILE_NOT_FOUND;
381     }
382
383     if (!(dwFlags & MCI_WAIT)) {        
384         /** FIXME: I'm not 100% sure that wNotifyDeviceID is the right value in all cases ??? */
385         return MCI_SendCommandAsync32(wmw->wNotifyDeviceID, MCI_PLAY, dwFlags, (DWORD)lpParms);
386     }
387
388     end = 0xFFFFFFFF;
389     if (lpParms && (dwFlags & MCI_FROM)) {
390         wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom); 
391     }
392     if (lpParms && (dwFlags & MCI_TO)) {
393         end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
394     }
395
396     TRACE(mciwave, "Playing from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
397
398     /* go back to begining of chunk */
399     mmioSeek32(wmw->hFile, wmw->dwFileOffset, SEEK_SET); /* >= 0 */
400
401     /* at 22050 bytes per sec => 30 ms by block */
402     bufsize = 10240;
403     hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
404     wmw->WaveHdr.lpData = (LPSTR)GlobalLock16(hData);
405
406     wmw->dwStatus = MCI_MODE_PLAY;
407
408     /* FIXME: this doesn't work if wmw->dwPosition != 0 */
409     while (wmw->dwStatus != MCI_MODE_STOP) {
410         wmw->WaveHdr.dwUser = 0L;
411         wmw->WaveHdr.dwFlags = 0L;
412         wmw->WaveHdr.dwLoops = 0L;
413         dwRet = wodMessage(wDevID, WODM_PREPARE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
414         count = mmioRead32(wmw->hFile, wmw->WaveHdr.lpData, bufsize);
415         TRACE(mciwave,"mmioRead bufsize=%ld count=%ld\n", bufsize, count);
416         if (count < 1) break;
417         wmw->WaveHdr.dwBufferLength = count;
418         wmw->WaveHdr.dwBytesRecorded = 0;
419         TRACE(mciwave,"before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
420               &wmw->WaveHdr, wmw->WaveHdr.dwBufferLength, wmw->WaveHdr.dwBytesRecorded);
421         dwRet = wodMessage(wDevID, WODM_WRITE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
422         /* FIXME: should use callback mechanisms from audio driver */
423 #if 1
424         while (!(wmw->WaveHdr.dwFlags & WHDR_DONE))
425             Sleep(1);
426 #endif
427         wmw->dwPosition += count;
428         TRACE(mciwave,"after WODM_WRITE dwPosition=%lu\n", wmw->dwPosition);
429         dwRet = wodMessage(wDevID, WODM_UNPREPARE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
430     }
431
432     if (wmw->WaveHdr.lpData != NULL) {
433         GlobalUnlock16(hData);
434         GlobalFree16(hData);
435         wmw->WaveHdr.lpData = NULL;
436     }
437     wmw->dwStatus = MCI_MODE_STOP;
438     if (lpParms && (dwFlags & MCI_NOTIFY)) {
439         TRACE(mciwave,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
440         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
441                         wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
442     }
443     return 0;
444 }
445
446 /**************************************************************************
447  *                              WAVE_mciRecord                  [internal]
448  */
449 static DWORD WAVE_mciRecord(UINT16 wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
450 {
451     int                 start, end;
452     LONG                bufsize;
453     HGLOBAL16           hData;
454     LPWAVEHDR           lpWaveHdr;
455     DWORD               dwRet;
456     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
457
458     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
459     
460     if (wmw == NULL)    return MCIERR_INVALID_DEVICE_ID;
461
462     if (!wmw->fInput) {
463         WARN(mciwave, "cannot record on output device\n");
464         return MCIERR_NONAPPLICABLE_FUNCTION;
465     }
466     
467     if (wmw->hFile == 0) {
468         WARN(mciwave, "can't find file='%s' !\n", 
469              wmw->openParms.lpstrElementName);
470         return MCIERR_FILE_NOT_FOUND;
471     }
472     start = 1;  end = 99999;
473     if (dwFlags & MCI_FROM) {
474         start = lpParms->dwFrom; 
475         TRACE(mciwave, "MCI_FROM=%d \n", start);
476     }
477     if (dwFlags & MCI_TO) {
478         end = lpParms->dwTo;
479         TRACE(mciwave,"MCI_TO=%d \n", end);
480     }
481     bufsize = 64000;
482     lpWaveHdr = &wmw->WaveHdr;
483     hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
484     lpWaveHdr->lpData = (LPSTR)GlobalLock16(hData);
485     lpWaveHdr->dwBufferLength = bufsize;
486     lpWaveHdr->dwUser = 0L;
487     lpWaveHdr->dwFlags = 0L;
488     lpWaveHdr->dwLoops = 0L;
489     dwRet=widMessage(wDevID,WIDM_PREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
490     TRACE(mciwave,"after WIDM_PREPARE \n");
491     while (TRUE) {
492         lpWaveHdr->dwBytesRecorded = 0;
493         dwRet = widMessage(wDevID, WIDM_START, 0, 0L, 0L);
494         TRACE(mciwave, "after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
495               lpWaveHdr, lpWaveHdr->dwBytesRecorded);
496         if (lpWaveHdr->dwBytesRecorded == 0) break;
497     }
498     TRACE(mciwave,"before WIDM_UNPREPARE \n");
499     dwRet = widMessage(wDevID,WIDM_UNPREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
500     TRACE(mciwave,"after WIDM_UNPREPARE \n");
501     if (lpWaveHdr->lpData != NULL) {
502         GlobalUnlock16(hData);
503         GlobalFree16(hData);
504         lpWaveHdr->lpData = NULL;
505     }
506     if (dwFlags & MCI_NOTIFY) {
507         TRACE(mciwave,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
508         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
509                         wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
510     }
511     return 0;
512 }
513
514 /**************************************************************************
515  *                              WAVE_mciPause                   [internal]
516  */
517 static DWORD WAVE_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
518 {
519     DWORD               dwRet;
520     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
521     
522     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
523
524     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
525     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
526
527     if (wmw->dwStatus == MCI_MODE_PLAY) {
528         wmw->dwStatus = MCI_MODE_PAUSE;
529     } 
530
531     if (wmw->fInput)    dwRet = widMessage(wDevID, WIDM_PAUSE, 0, dwFlags, (DWORD)lpParms);
532     else                dwRet = wodMessage(wDevID, WODM_PAUSE, 0, dwFlags, (DWORD)lpParms);
533     
534     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
535 }
536
537 /**************************************************************************
538  *                              WAVE_mciResume                  [internal]
539  */
540 static DWORD WAVE_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
541 {
542     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
543     DWORD               dwRet = 0;
544
545     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
546
547     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
548     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
549
550     if (wmw->dwStatus == MCI_MODE_PAUSE) {
551         wmw->dwStatus = MCI_MODE_PLAY;
552     } 
553
554 #if 0
555     if (wmw->fInput)    dwRet = widMessage(wDevID, WIDM_PLAY, 0, dwFlags, (DWORD)lpParms);
556     else                dwRet = wodMessage(wDevID, WODM_PLAY, 0, dwFlags, (DWORD)lpParms);
557     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
558 #else
559     return dwRet;
560 #endif
561
562 }
563
564 /**************************************************************************
565  *                              WAVE_mciSeek                    [internal]
566  */
567 static DWORD WAVE_mciSeek(UINT16 wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
568 {
569     DWORD               ret = 0;
570     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
571
572     TRACE(mciwave, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
573
574     if (lpParms == NULL) {
575         ret = MCIERR_NULL_PARAMETER_BLOCK;
576     } else if (wmw == NULL) {
577         ret = MCIERR_INVALID_DEVICE_ID;
578     } else {
579         WAVE_mciStop(wDevID, MCI_WAIT, 0);
580         
581         if (dwFlags & MCI_SEEK_TO_START) {
582             wmw->dwPosition = 0;
583         } else if (dwFlags & MCI_SEEK_TO_END) {
584             wmw->dwPosition = 0xFFFFFFFF; /* fixme */
585         } else if (dwFlags & MCI_TO) {
586             wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
587         } else {
588             WARN(mciwave, "dwFlag doesn't tell where to seek to...\n");
589             return MCIERR_MISSING_PARAMETER;
590         }
591         
592         TRACE(mciwave, "Seeking to position=%lu bytes\n", wmw->dwPosition);
593         
594         if (dwFlags & MCI_NOTIFY) {
595             TRACE(mciwave, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
596             mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
597                             wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
598         }
599     }
600     return ret; 
601 }    
602
603 /**************************************************************************
604  *                              WAVE_mciSet                     [internal]
605  */
606 static DWORD WAVE_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
607 {
608     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
609
610     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
611     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
612     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
613
614     if (dwFlags & MCI_SET_TIME_FORMAT) {
615         switch (lpParms->dwTimeFormat) {
616         case MCI_FORMAT_MILLISECONDS:
617             TRACE(mciwave, "MCI_FORMAT_MILLISECONDS !\n");
618             wmw->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
619             break;
620         case MCI_FORMAT_BYTES:
621             TRACE(mciwave, "MCI_FORMAT_BYTES !\n");
622             wmw->dwMciTimeFormat = MCI_FORMAT_BYTES;
623             break;
624         case MCI_FORMAT_SAMPLES:
625             TRACE(mciwave, "MCI_FORMAT_SAMPLES !\n");
626             wmw->dwMciTimeFormat = MCI_FORMAT_SAMPLES;
627             break;
628         default:
629             WARN(mciwave,"Bad time format %lu!\n", lpParms->dwTimeFormat);
630             return MCIERR_BAD_TIME_FORMAT;
631         }
632     }
633     if (dwFlags & MCI_SET_VIDEO) {
634         TRACE(mciwave, "No support for video !\n");
635         return MCIERR_UNSUPPORTED_FUNCTION;
636     }
637     if (dwFlags & MCI_SET_DOOR_OPEN) {
638         TRACE(mciwave, "No support for door open !\n");
639         return MCIERR_UNSUPPORTED_FUNCTION;
640     }
641     if (dwFlags & MCI_SET_DOOR_CLOSED) {
642         TRACE(mciwave, "No support for door close !\n");
643         return MCIERR_UNSUPPORTED_FUNCTION;
644     }
645     if (dwFlags & MCI_SET_AUDIO) {
646         if (dwFlags & MCI_SET_ON) {
647             TRACE(mciwave, "MCI_SET_ON audio !\n");
648         } else if (dwFlags & MCI_SET_OFF) {
649             TRACE(mciwave, "MCI_SET_OFF audio !\n");
650         } else {
651             WARN(mciwave, "MCI_SET_AUDIO without SET_ON or SET_OFF\n");
652             return MCIERR_BAD_INTEGER;
653         }
654             
655         if (lpParms->dwAudio & MCI_SET_AUDIO_ALL)
656             TRACE(mciwave, "MCI_SET_AUDIO_ALL !\n");
657         if (lpParms->dwAudio & MCI_SET_AUDIO_LEFT)
658             TRACE(mciwave, "MCI_SET_AUDIO_LEFT !\n");
659         if (lpParms->dwAudio & MCI_SET_AUDIO_RIGHT)
660             TRACE(mciwave, "MCI_SET_AUDIO_RIGHT !\n");
661     }
662     if (dwFlags & MCI_WAVE_INPUT) 
663         TRACE(mciwave, "MCI_WAVE_INPUT !\n");
664     if (dwFlags & MCI_WAVE_OUTPUT) 
665         TRACE(mciwave, "MCI_WAVE_OUTPUT !\n");
666     if (dwFlags & MCI_WAVE_SET_ANYINPUT) 
667         TRACE(mciwave, "MCI_WAVE_SET_ANYINPUT !\n");
668     if (dwFlags & MCI_WAVE_SET_ANYOUTPUT) 
669         TRACE(mciwave, "MCI_WAVE_SET_ANYOUTPUT !\n");
670     if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC) 
671         TRACE(mciwave, "MCI_WAVE_SET_AVGBYTESPERSEC !\n");
672     if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE) 
673         TRACE(mciwave, "MCI_WAVE_SET_BITSPERSAMPLE !\n");
674     if (dwFlags & MCI_WAVE_SET_BLOCKALIGN) 
675         TRACE(mciwave, "MCI_WAVE_SET_BLOCKALIGN !\n");
676     if (dwFlags & MCI_WAVE_SET_CHANNELS) 
677         TRACE(mciwave, "MCI_WAVE_SET_CHANNELS !\n");
678     if (dwFlags & MCI_WAVE_SET_FORMATTAG) 
679         TRACE(mciwave, "MCI_WAVE_SET_FORMATTAG !\n");
680     if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC) 
681         TRACE(mciwave, "MCI_WAVE_SET_SAMPLESPERSEC !\n");
682     return 0;
683 }
684
685 /**************************************************************************
686  *                              WAVE_mciStatus          [internal]
687  */
688 static DWORD WAVE_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
689 {
690     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
691
692     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
693     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
694     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
695
696     if (dwFlags & MCI_STATUS_ITEM) {
697         switch(lpParms->dwItem) {
698         case MCI_STATUS_CURRENT_TRACK:
699             lpParms->dwReturn = 1;
700             TRACE(mciwave, "MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
701             break;
702         case MCI_STATUS_LENGTH:
703             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
704             lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->dwLength);
705             TRACE(mciwave, "MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
706             break;
707         case MCI_STATUS_MODE:
708             lpParms->dwReturn = wmw->dwStatus;
709             TRACE(mciwave, "MCI_STATUS_MODE => %lu\n", lpParms->dwReturn);
710             break;
711         case MCI_STATUS_MEDIA_PRESENT:
712             TRACE(mciwave, "MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
713             lpParms->dwReturn = TRUE;
714             break;
715         case MCI_STATUS_NUMBER_OF_TRACKS:
716             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
717             lpParms->dwReturn = 1;
718             TRACE(mciwave, "MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms->dwReturn);
719             break;
720         case MCI_STATUS_POSITION:
721             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
722             lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, 
723                                                              (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition);
724             TRACE(mciwave, "MCI_STATUS_POSITION %s => %lu\n", 
725                   (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
726             break;
727         case MCI_STATUS_READY:
728             lpParms->dwReturn = (wmw->dwStatus != MCI_MODE_NOT_READY);
729             TRACE(mciwave,"MCI_STATUS_READY => %lu!\n", lpParms->dwReturn);
730             break;
731         case MCI_STATUS_TIME_FORMAT:
732             lpParms->dwReturn = wmw->dwMciTimeFormat;
733             TRACE(mciwave, "MCI_STATUS_TIME_FORMAT => %lu\n", lpParms->dwReturn);
734             break;
735         case MCI_WAVE_INPUT:
736             TRACE(mciwave,"MCI_WAVE_INPUT !\n");
737             lpParms->dwReturn = 0;
738             break;
739         case MCI_WAVE_OUTPUT:
740             TRACE(mciwave,"MCI_WAVE_OUTPUT !\n");
741             lpParms->dwReturn = 0;
742             break;
743         case MCI_WAVE_STATUS_AVGBYTESPERSEC:
744             lpParms->dwReturn = wmw->WaveFormat.wf.nAvgBytesPerSec;
745             TRACE(mciwave,"MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms->dwReturn);
746             break;
747         case MCI_WAVE_STATUS_BITSPERSAMPLE:
748             lpParms->dwReturn = wmw->WaveFormat.wBitsPerSample;
749             TRACE(mciwave,"MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms->dwReturn);
750             break;
751         case MCI_WAVE_STATUS_BLOCKALIGN:
752             lpParms->dwReturn = wmw->WaveFormat.wf.nBlockAlign;
753             TRACE(mciwave,"MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms->dwReturn);
754             break;
755         case MCI_WAVE_STATUS_CHANNELS:
756             lpParms->dwReturn = wmw->WaveFormat.wf.nChannels;
757             TRACE(mciwave,"MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms->dwReturn);
758             break;
759         case MCI_WAVE_STATUS_FORMATTAG:
760             lpParms->dwReturn = wmw->WaveFormat.wf.
761 wFormatTag;
762             TRACE(mciwave,"MCI_WAVE_FORMATTAG => %lu!\n", lpParms->dwReturn);
763             break;
764         case MCI_WAVE_STATUS_LEVEL:
765             TRACE(mciwave,"MCI_WAVE_STATUS_LEVEL !\n");
766             lpParms->dwReturn = 0xAAAA5555;
767             break;
768         case MCI_WAVE_STATUS_SAMPLESPERSEC:
769             lpParms->dwReturn = wmw->WaveFormat.wf.nSamplesPerSec;
770             TRACE(mciwave,"MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms->dwReturn);
771             break;
772         default:
773             WARN(mciwave,"unknown command %08lX !\n", lpParms->dwItem);
774             return MCIERR_UNRECOGNIZED_COMMAND;
775         }
776     }
777     if (dwFlags & MCI_NOTIFY) {
778         TRACE(mciwave,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
779         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
780                         wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
781     }
782     return 0;
783 }
784
785 /**************************************************************************
786  *                              WAVE_mciGetDevCaps              [internal]
787  */
788 static DWORD WAVE_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags, 
789                                 LPMCI_GETDEVCAPS_PARMS lpParms)
790 {
791     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
792
793     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
794     
795     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
796     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
797
798     if (dwFlags & MCI_GETDEVCAPS_ITEM) {
799         switch(lpParms->dwItem) {
800         case MCI_GETDEVCAPS_DEVICE_TYPE:
801             lpParms->dwReturn = MCI_DEVTYPE_WAVEFORM_AUDIO;
802             break;
803         case MCI_GETDEVCAPS_HAS_AUDIO:
804             lpParms->dwReturn = TRUE;
805             break;
806         case MCI_GETDEVCAPS_HAS_VIDEO:
807             lpParms->dwReturn = FALSE;
808             break;
809         case MCI_GETDEVCAPS_USES_FILES:
810             lpParms->dwReturn = TRUE;
811             break;
812         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
813             lpParms->dwReturn = TRUE;
814             break;
815         case MCI_GETDEVCAPS_CAN_RECORD:
816             lpParms->dwReturn = TRUE;
817             break;
818         case MCI_GETDEVCAPS_CAN_EJECT:
819             lpParms->dwReturn = FALSE;
820             break;
821         case MCI_GETDEVCAPS_CAN_PLAY:
822             lpParms->dwReturn = TRUE;
823             break;
824         case MCI_GETDEVCAPS_CAN_SAVE:
825             lpParms->dwReturn = TRUE;
826             break;
827         case MCI_WAVE_GETDEVCAPS_INPUTS:
828             lpParms->dwReturn = 1;
829             break;
830         case MCI_WAVE_GETDEVCAPS_OUTPUTS:
831             lpParms->dwReturn = 1;
832             break;
833         default:
834             TRACE(mciwave, "Unknown capability (%08lx) !\n", lpParms->dwItem);
835             return MCIERR_UNRECOGNIZED_COMMAND;
836         }
837     }
838     return 0;
839 }
840
841 /**************************************************************************
842  *                              WAVE_mciInfo                    [internal]
843  */
844 static DWORD WAVE_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS16 lpParms)
845 {
846     DWORD               ret = 0;
847     LPCSTR              str = 0;
848     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
849
850     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
851
852     if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
853         ret = MCIERR_NULL_PARAMETER_BLOCK;
854     } else if (wmw == NULL) {
855         ret = MCIERR_INVALID_DEVICE_ID;
856     } else {
857         TRACE(mciwave, "buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
858
859         switch(dwFlags) {
860         case MCI_INFO_PRODUCT:
861             str = "Wine's audio player";
862             break;
863         case MCI_INFO_FILE:
864             str = wmw->openParms.lpstrElementName;
865             break;
866         case MCI_WAVE_INPUT:
867             str = "Wine Wave In";
868             break;
869         case MCI_WAVE_OUTPUT:
870             str = "Wine Wave Out";
871             break;
872         default:
873             WARN(mciwave, "Don't know this info command (%lu)\n", dwFlags);
874             return MCIERR_UNRECOGNIZED_COMMAND;
875         }
876     }
877     if (str) {
878         if (strlen(str) + 1 > lpParms->dwRetSize) {
879             ret = MCIERR_PARAM_OVERFLOW;
880         } else {
881             lstrcpyn32A(lpParms->lpstrReturn, str, lpParms->dwRetSize);
882         }
883     } else {
884         lpParms->lpstrReturn[0] = 0;
885     }
886
887     return ret;
888 }
889
890 /**************************************************************************
891  *                              WAVE_DriverProc32               [sample driver]
892  */
893 LONG MCIWAVE_DriverProc32(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg, 
894                           DWORD dwParam1, DWORD dwParam2)
895 {
896     TRACE(mciwave,"(%08lX, %04X, %08lX, %08lX, %08lX)\n", 
897           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
898
899     switch(wMsg) {
900     case DRV_LOAD:              return 1;
901     case DRV_FREE:              return 1;
902     case DRV_OPEN:              return 1;
903     case DRV_CLOSE:             return 1;
904     case DRV_ENABLE:            return 1;
905     case DRV_DISABLE:           return 1;
906     case DRV_QUERYCONFIGURE:    return 1;
907     case DRV_CONFIGURE:         MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK);   return 1;
908     case DRV_INSTALL:           return DRVCNF_RESTART;
909     case DRV_REMOVE:            return DRVCNF_RESTART;
910     case MCI_OPEN_DRIVER:       return WAVE_mciOpen      (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMS32A)dwParam2);
911     case MCI_CLOSE_DRIVER:      return WAVE_mciClose     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
912     case MCI_CUE:               return WAVE_mciCue       (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
913     case MCI_PLAY:              return WAVE_mciPlay      (dwDevID, dwParam1, (LPMCI_PLAY_PARMS)        dwParam2);
914     case MCI_RECORD:            return WAVE_mciRecord    (dwDevID, dwParam1, (LPMCI_RECORD_PARMS)      dwParam2);
915     case MCI_STOP:              return WAVE_mciStop      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
916     case MCI_SET:               return WAVE_mciSet       (dwDevID, dwParam1, (LPMCI_SET_PARMS)         dwParam2);
917     case MCI_PAUSE:             return WAVE_mciPause     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
918     case MCI_RESUME:            return WAVE_mciResume    (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
919     case MCI_STATUS:            return WAVE_mciStatus    (dwDevID, dwParam1, (LPMCI_STATUS_PARMS)      dwParam2);
920     case MCI_GETDEVCAPS:        return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)  dwParam2);
921     case MCI_INFO:              return WAVE_mciInfo      (dwDevID, dwParam1, (LPMCI_INFO_PARMS16)      dwParam2);
922     case MCI_SEEK:              return WAVE_mciSeek      (dwDevID, dwParam1, (LPMCI_SEEK_PARMS)        dwParam2);               
923     case MCI_LOAD:              
924     case MCI_SAVE:              
925     case MCI_FREEZE:            
926     case MCI_PUT:               
927     case MCI_REALIZE:           
928     case MCI_UNFREEZE:          
929     case MCI_UPDATE:            
930     case MCI_WHERE:             
931     case MCI_WINDOW:            
932     case MCI_STEP:              
933     case MCI_SPIN:              
934     case MCI_ESCAPE:            
935     case MCI_COPY:              
936     case MCI_CUT:               
937     case MCI_DELETE:            
938     case MCI_PASTE:             
939         WARN(mciwave, "Unsupported command=%s\n", MCI_CommandToString(wMsg));
940         break;
941     case MCI_OPEN:
942     case MCI_CLOSE:
943         FIXME(mciwave, "Shouldn't receive a MCI_OPEN or CLOSE message\n");
944         break;
945     default:
946         FIXME(mciwave, "is probably wrong msg=%s\n", MCI_CommandToString(wMsg));
947         return DefDriverProc32(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
948     }
949     return MCIERR_UNRECOGNIZED_COMMAND;
950 }