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