Accept MCI_OPEN and MCI_CLOSE messages in MCICDAUDIO_DriverProc32().
[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 /**************************************************************************
448  *                              WAVE_mciRecord                  [internal]
449  */
450 static DWORD WAVE_mciRecord(UINT16 wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
451 {
452     int                 start, end;
453     LONG                bufsize;
454     HGLOBAL16           hData;
455     LPWAVEHDR           lpWaveHdr;
456     DWORD               dwRet;
457     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
458
459     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
460     
461     if (wmw == NULL)    return MCIERR_INVALID_DEVICE_ID;
462
463     if (!wmw->fInput) {
464         WARN(mciwave, "cannot record on output device\n");
465         return MCIERR_NONAPPLICABLE_FUNCTION;
466     }
467     
468     if (wmw->hFile == 0) {
469         WARN(mciwave, "can't find file='%s' !\n", 
470              wmw->openParms.lpstrElementName);
471         return MCIERR_FILE_NOT_FOUND;
472     }
473     start = 1;  end = 99999;
474     if (dwFlags & MCI_FROM) {
475         start = lpParms->dwFrom; 
476         TRACE(mciwave, "MCI_FROM=%d \n", start);
477     }
478     if (dwFlags & MCI_TO) {
479         end = lpParms->dwTo;
480         TRACE(mciwave,"MCI_TO=%d \n", end);
481     }
482     bufsize = 64000;
483     lpWaveHdr = &wmw->WaveHdr;
484     hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
485     lpWaveHdr->lpData = (LPSTR)GlobalLock16(hData);
486     lpWaveHdr->dwBufferLength = bufsize;
487     lpWaveHdr->dwUser = 0L;
488     lpWaveHdr->dwFlags = 0L;
489     lpWaveHdr->dwLoops = 0L;
490     dwRet=widMessage(wDevID,WIDM_PREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
491     TRACE(mciwave,"after WIDM_PREPARE \n");
492     while (TRUE) {
493         lpWaveHdr->dwBytesRecorded = 0;
494         dwRet = widMessage(wDevID, WIDM_START, 0, 0L, 0L);
495         TRACE(mciwave, "after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
496               lpWaveHdr, lpWaveHdr->dwBytesRecorded);
497         if (lpWaveHdr->dwBytesRecorded == 0) break;
498     }
499     TRACE(mciwave,"before WIDM_UNPREPARE \n");
500     dwRet = widMessage(wDevID,WIDM_UNPREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
501     TRACE(mciwave,"after WIDM_UNPREPARE \n");
502     if (lpWaveHdr->lpData != NULL) {
503         GlobalUnlock16(hData);
504         GlobalFree16(hData);
505         lpWaveHdr->lpData = NULL;
506     }
507     if (dwFlags & MCI_NOTIFY) {
508         TRACE(mciwave,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
509         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
510                         wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
511     }
512     return 0;
513 }
514
515 /**************************************************************************
516  *                              WAVE_mciPause                   [internal]
517  */
518 static DWORD WAVE_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
519 {
520     DWORD               dwRet;
521     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
522     
523     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
524
525     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
526     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
527
528     if (wmw->dwStatus == MCI_MODE_PLAY) {
529         wmw->dwStatus = MCI_MODE_PAUSE;
530     } 
531
532     if (wmw->fInput)    dwRet = widMessage(wDevID, WIDM_PAUSE, 0, dwFlags, (DWORD)lpParms);
533     else                dwRet = wodMessage(wDevID, WODM_PAUSE, 0, dwFlags, (DWORD)lpParms);
534     
535     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
536 }
537
538
539 /**************************************************************************
540  *                              WAVE_mciResume                  [internal]
541  */
542 static DWORD WAVE_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
543 {
544     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
545     DWORD               dwRet = 0;
546
547     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
548
549     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
550     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
551
552     if (wmw->dwStatus == MCI_MODE_PAUSE) {
553         wmw->dwStatus = MCI_MODE_PLAY;
554     } 
555
556 #if 0
557     if (wmw->fInput)    dwRet = widMessage(wDevID, WIDM_PLAY, 0, dwFlags, (DWORD)lpParms);
558     else                dwRet = wodMessage(wDevID, WODM_PLAY, 0, dwFlags, (DWORD)lpParms);
559     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
560 #else
561     return 0;
562 #endif
563
564 }
565
566 /**************************************************************************
567  *                              WAVE_mciSeek                    [internal]
568  */
569 static DWORD WAVE_mciSeek(UINT16 wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
570 {
571     DWORD               ret = 0;
572     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
573
574     TRACE(mciwave, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
575
576     if (lpParms == NULL) {
577         ret = MCIERR_NULL_PARAMETER_BLOCK;
578     } else if (wmw == NULL) {
579         ret = MCIERR_INVALID_DEVICE_ID;
580     } else {
581         WAVE_mciStop(wDevID, MCI_WAIT, 0);
582         
583         if (dwFlags & MCI_SEEK_TO_START) {
584             wmw->dwPosition = 0;
585         } else if (dwFlags & MCI_SEEK_TO_END) {
586             wmw->dwPosition = 0xFFFFFFFF; /* fixme */
587         } else if (dwFlags & MCI_TO) {
588             wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
589         } else {
590             WARN(mciwave, "dwFlag doesn't tell where to seek to...\n");
591             return MCIERR_MISSING_PARAMETER;
592         }
593         
594         TRACE(mciwave, "Seeking to position=%lu bytes\n", wmw->dwPosition);
595         
596         if (dwFlags & MCI_NOTIFY) {
597             TRACE(mciwave, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
598             mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
599                             wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
600         }
601     }
602     return ret; 
603 }    
604
605 /**************************************************************************
606  *                              WAVE_mciSet                     [internal]
607  */
608 static DWORD WAVE_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
609 {
610     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
611
612     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
613     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
614     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
615
616     if (dwFlags & MCI_SET_TIME_FORMAT) {
617         switch (lpParms->dwTimeFormat) {
618         case MCI_FORMAT_MILLISECONDS:
619             TRACE(mciwave, "MCI_FORMAT_MILLISECONDS !\n");
620             wmw->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
621             break;
622         case MCI_FORMAT_BYTES:
623             TRACE(mciwave, "MCI_FORMAT_BYTES !\n");
624             wmw->dwMciTimeFormat = MCI_FORMAT_BYTES;
625             break;
626         case MCI_FORMAT_SAMPLES:
627             TRACE(mciwave, "MCI_FORMAT_SAMPLES !\n");
628             wmw->dwMciTimeFormat = MCI_FORMAT_SAMPLES;
629             break;
630         default:
631             WARN(mciwave,"Bad time format %lu!\n", lpParms->dwTimeFormat);
632             return MCIERR_BAD_TIME_FORMAT;
633         }
634     }
635     if (dwFlags & MCI_SET_VIDEO) {
636         TRACE(mciwave, "No support for video !\n");
637         return MCIERR_UNSUPPORTED_FUNCTION;
638     }
639     if (dwFlags & MCI_SET_DOOR_OPEN) {
640         TRACE(mciwave, "No support for door open !\n");
641         return MCIERR_UNSUPPORTED_FUNCTION;
642     }
643     if (dwFlags & MCI_SET_DOOR_CLOSED) {
644         TRACE(mciwave, "No support for door close !\n");
645         return MCIERR_UNSUPPORTED_FUNCTION;
646     }
647     if (dwFlags & MCI_SET_AUDIO) {
648         if (dwFlags & MCI_SET_ON) {
649             TRACE(mciwave, "MCI_SET_ON audio !\n");
650         } else if (dwFlags & MCI_SET_OFF) {
651             TRACE(mciwave, "MCI_SET_OFF audio !\n");
652         } else {
653             WARN(mciwave, "MCI_SET_AUDIO without SET_ON or SET_OFF\n");
654             return MCIERR_BAD_INTEGER;
655         }
656             
657         if (lpParms->dwAudio & MCI_SET_AUDIO_ALL)
658             TRACE(mciwave, "MCI_SET_AUDIO_ALL !\n");
659         if (lpParms->dwAudio & MCI_SET_AUDIO_LEFT)
660             TRACE(mciwave, "MCI_SET_AUDIO_LEFT !\n");
661         if (lpParms->dwAudio & MCI_SET_AUDIO_RIGHT)
662             TRACE(mciwave, "MCI_SET_AUDIO_RIGHT !\n");
663     }
664     if (dwFlags & MCI_WAVE_INPUT) 
665         TRACE(mciwave, "MCI_WAVE_INPUT !\n");
666     if (dwFlags & MCI_WAVE_OUTPUT) 
667         TRACE(mciwave, "MCI_WAVE_OUTPUT !\n");
668     if (dwFlags & MCI_WAVE_SET_ANYINPUT) 
669         TRACE(mciwave, "MCI_WAVE_SET_ANYINPUT !\n");
670     if (dwFlags & MCI_WAVE_SET_ANYOUTPUT) 
671         TRACE(mciwave, "MCI_WAVE_SET_ANYOUTPUT !\n");
672     if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC) 
673         TRACE(mciwave, "MCI_WAVE_SET_AVGBYTESPERSEC !\n");
674     if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE) 
675         TRACE(mciwave, "MCI_WAVE_SET_BITSPERSAMPLE !\n");
676     if (dwFlags & MCI_WAVE_SET_BLOCKALIGN) 
677         TRACE(mciwave, "MCI_WAVE_SET_BLOCKALIGN !\n");
678     if (dwFlags & MCI_WAVE_SET_CHANNELS) 
679         TRACE(mciwave, "MCI_WAVE_SET_CHANNELS !\n");
680     if (dwFlags & MCI_WAVE_SET_FORMATTAG) 
681         TRACE(mciwave, "MCI_WAVE_SET_FORMATTAG !\n");
682     if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC) 
683         TRACE(mciwave, "MCI_WAVE_SET_SAMPLESPERSEC !\n");
684     return 0;
685 }
686
687
688 /**************************************************************************
689  *                              WAVE_mciStatus          [internal]
690  */
691 static DWORD WAVE_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
692 {
693     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
694
695     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
696     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
697     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
698
699     if (dwFlags & MCI_STATUS_ITEM) {
700         switch(lpParms->dwItem) {
701         case MCI_STATUS_CURRENT_TRACK:
702             lpParms->dwReturn = 1;
703             TRACE(mciwave, "MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
704             break;
705         case MCI_STATUS_LENGTH:
706             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
707             lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->dwLength);
708             TRACE(mciwave, "MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
709             break;
710         case MCI_STATUS_MODE:
711             lpParms->dwReturn = wmw->dwStatus;
712             TRACE(mciwave, "MCI_STATUS_MODE => %lu\n", lpParms->dwReturn);
713             break;
714         case MCI_STATUS_MEDIA_PRESENT:
715             TRACE(mciwave, "MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
716             lpParms->dwReturn = TRUE;
717             break;
718         case MCI_STATUS_NUMBER_OF_TRACKS:
719             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
720             lpParms->dwReturn = 1;
721             TRACE(mciwave, "MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms->dwReturn);
722             break;
723         case MCI_STATUS_POSITION:
724             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
725             lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, 
726                                                              (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition);
727             TRACE(mciwave, "MCI_STATUS_POSITION %s => %lu\n", 
728                   (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
729             break;
730         case MCI_STATUS_READY:
731             lpParms->dwReturn = (wmw->dwStatus != MCI_MODE_NOT_READY);
732             TRACE(mciwave,"MCI_STATUS_READY => %lu!\n", lpParms->dwReturn);
733             break;
734         case MCI_STATUS_TIME_FORMAT:
735             lpParms->dwReturn = wmw->dwMciTimeFormat;
736             TRACE(mciwave, "MCI_STATUS_TIME_FORMAT => %lu\n", lpParms->dwReturn);
737             break;
738         case MCI_WAVE_INPUT:
739             TRACE(mciwave,"MCI_WAVE_INPUT !\n");
740             lpParms->dwReturn = 0;
741             break;
742         case MCI_WAVE_OUTPUT:
743             TRACE(mciwave,"MCI_WAVE_OUTPUT !\n");
744             lpParms->dwReturn = 0;
745             break;
746         case MCI_WAVE_STATUS_AVGBYTESPERSEC:
747             lpParms->dwReturn = wmw->WaveFormat.wf.nAvgBytesPerSec;
748             TRACE(mciwave,"MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms->dwReturn);
749             break;
750         case MCI_WAVE_STATUS_BITSPERSAMPLE:
751             lpParms->dwReturn = wmw->WaveFormat.wBitsPerSample;
752             TRACE(mciwave,"MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms->dwReturn);
753             break;
754         case MCI_WAVE_STATUS_BLOCKALIGN:
755             lpParms->dwReturn = wmw->WaveFormat.wf.nBlockAlign;
756             TRACE(mciwave,"MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms->dwReturn);
757             break;
758         case MCI_WAVE_STATUS_CHANNELS:
759             lpParms->dwReturn = wmw->WaveFormat.wf.nChannels;
760             TRACE(mciwave,"MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms->dwReturn);
761             break;
762         case MCI_WAVE_STATUS_FORMATTAG:
763             lpParms->dwReturn = wmw->WaveFormat.wf.
764 wFormatTag;
765             TRACE(mciwave,"MCI_WAVE_FORMATTAG => %lu!\n", lpParms->dwReturn);
766             break;
767         case MCI_WAVE_STATUS_LEVEL:
768             TRACE(mciwave,"MCI_WAVE_STATUS_LEVEL !\n");
769             lpParms->dwReturn = 0xAAAA5555;
770             break;
771         case MCI_WAVE_STATUS_SAMPLESPERSEC:
772             lpParms->dwReturn = wmw->WaveFormat.wf.nSamplesPerSec;
773             TRACE(mciwave,"MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms->dwReturn);
774             break;
775         default:
776             WARN(mciwave,"unknown command %08lX !\n", lpParms->dwItem);
777             return MCIERR_UNRECOGNIZED_COMMAND;
778         }
779     }
780     if (dwFlags & MCI_NOTIFY) {
781         TRACE(mciwave,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
782         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
783                         wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
784     }
785     return 0;
786 }
787
788 /**************************************************************************
789  *                              WAVE_mciGetDevCaps              [internal]
790  */
791 static DWORD WAVE_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags, 
792                                 LPMCI_GETDEVCAPS_PARMS lpParms)
793 {
794     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
795
796     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
797     
798     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
799     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
800
801     if (dwFlags & MCI_GETDEVCAPS_ITEM) {
802         switch(lpParms->dwItem) {
803         case MCI_GETDEVCAPS_DEVICE_TYPE:
804             lpParms->dwReturn = MCI_DEVTYPE_WAVEFORM_AUDIO;
805             break;
806         case MCI_GETDEVCAPS_HAS_AUDIO:
807             lpParms->dwReturn = TRUE;
808             break;
809         case MCI_GETDEVCAPS_HAS_VIDEO:
810             lpParms->dwReturn = FALSE;
811             break;
812         case MCI_GETDEVCAPS_USES_FILES:
813             lpParms->dwReturn = TRUE;
814             break;
815         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
816             lpParms->dwReturn = TRUE;
817             break;
818         case MCI_GETDEVCAPS_CAN_RECORD:
819             lpParms->dwReturn = TRUE;
820             break;
821         case MCI_GETDEVCAPS_CAN_EJECT:
822             lpParms->dwReturn = FALSE;
823             break;
824         case MCI_GETDEVCAPS_CAN_PLAY:
825             lpParms->dwReturn = TRUE;
826             break;
827         case MCI_GETDEVCAPS_CAN_SAVE:
828             lpParms->dwReturn = TRUE;
829             break;
830         case MCI_WAVE_GETDEVCAPS_INPUTS:
831             lpParms->dwReturn = 1;
832             break;
833         case MCI_WAVE_GETDEVCAPS_OUTPUTS:
834             lpParms->dwReturn = 1;
835             break;
836         default:
837             TRACE(mciwave, "Unknown capability (%08lx) !\n", lpParms->dwItem);
838             return MCIERR_UNRECOGNIZED_COMMAND;
839         }
840     }
841     return 0;
842 }
843
844 /**************************************************************************
845  *                              WAVE_mciInfo                    [internal]
846  */
847 static DWORD WAVE_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS16 lpParms)
848 {
849     DWORD               ret = 0;
850     LPCSTR              str = 0;
851     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
852
853     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
854
855     if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
856         ret = MCIERR_NULL_PARAMETER_BLOCK;
857     } else if (wmw == NULL) {
858         ret = MCIERR_INVALID_DEVICE_ID;
859     } else {
860         TRACE(mciwave, "buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
861
862         switch(dwFlags) {
863         case MCI_INFO_PRODUCT:
864             str = "Wine's audio player";
865             break;
866         case MCI_INFO_FILE:
867             str = wmw->openParms.lpstrElementName;
868             break;
869         case MCI_WAVE_INPUT:
870             str = "Wine Wave In";
871             break;
872         case MCI_WAVE_OUTPUT:
873             str = "Wine Wave Out";
874             break;
875         default:
876             WARN(mciwave, "Don't know this info command (%lu)\n", dwFlags);
877             return MCIERR_UNRECOGNIZED_COMMAND;
878         }
879     }
880     if (str) {
881         if (strlen(str) + 1 > lpParms->dwRetSize) {
882             ret = MCIERR_PARAM_OVERFLOW;
883         } else {
884             lstrcpyn32A(lpParms->lpstrReturn, str, lpParms->dwRetSize);
885         }
886     } else {
887         lpParms->lpstrReturn[0] = 0;
888     }
889
890     return ret;
891 }
892
893 /**************************************************************************
894  *                              WAVE_DriverProc32               [sample driver]
895  */
896 LONG MCIWAVE_DriverProc32(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg, 
897                           DWORD dwParam1, DWORD dwParam2)
898 {
899     TRACE(mciwave,"(%08lX, %04X, %08lX, %08lX, %08lX)\n", 
900           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
901
902     switch(wMsg) {
903     case DRV_LOAD:              return 1;
904     case DRV_FREE:              return 1;
905     case DRV_OPEN:              return 1;
906     case DRV_CLOSE:             return 1;
907     case DRV_ENABLE:            return 1;
908     case DRV_DISABLE:           return 1;
909     case DRV_QUERYCONFIGURE:    return 1;
910     case DRV_CONFIGURE:         MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK);   return 1;
911     case DRV_INSTALL:           return DRVCNF_RESTART;
912     case DRV_REMOVE:            return DRVCNF_RESTART;
913     case MCI_OPEN_DRIVER:       return WAVE_mciOpen      (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMS32A)dwParam2);
914     case MCI_CLOSE_DRIVER:      return WAVE_mciClose     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
915     case MCI_CUE:               return WAVE_mciCue       (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
916     case MCI_PLAY:              return WAVE_mciPlay      (dwDevID, dwParam1, (LPMCI_PLAY_PARMS)        dwParam2);
917     case MCI_RECORD:            return WAVE_mciRecord    (dwDevID, dwParam1, (LPMCI_RECORD_PARMS)      dwParam2);
918     case MCI_STOP:              return WAVE_mciStop      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
919     case MCI_SET:               return WAVE_mciSet       (dwDevID, dwParam1, (LPMCI_SET_PARMS)         dwParam2);
920     case MCI_PAUSE:             return WAVE_mciPause     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
921     case MCI_RESUME:            return WAVE_mciResume    (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
922     case MCI_STATUS:            return WAVE_mciStatus    (dwDevID, dwParam1, (LPMCI_STATUS_PARMS)      dwParam2);
923     case MCI_GETDEVCAPS:        return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)  dwParam2);
924     case MCI_INFO:              return WAVE_mciInfo      (dwDevID, dwParam1, (LPMCI_INFO_PARMS16)      dwParam2);
925     case MCI_SEEK:              return WAVE_mciSeek      (dwDevID, dwParam1, (LPMCI_SEEK_PARMS)        dwParam2);               
926     case MCI_LOAD:              
927     case MCI_SAVE:              
928     case MCI_FREEZE:            
929     case MCI_PUT:               
930     case MCI_REALIZE:           
931     case MCI_UNFREEZE:          
932     case MCI_UPDATE:            
933     case MCI_WHERE:             
934     case MCI_WINDOW:            
935     case MCI_STEP:              
936     case MCI_SPIN:              
937     case MCI_ESCAPE:            
938     case MCI_COPY:              
939     case MCI_CUT:               
940     case MCI_DELETE:            
941     case MCI_PASTE:             
942         WARN(mciwave, "Unsupported command=%s\n", MCI_CommandToString(wMsg));
943         break;
944     case MCI_OPEN:
945     case MCI_CLOSE:
946         FIXME(mciwave, "Shouldn't receive a MCI_OPEN or CLOSE message\n");
947         break;
948     default:
949         FIXME(mciwave, "is probably wrong msg=%s\n", MCI_CommandToString(wMsg));
950         return DefDriverProc32(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
951     }
952     return MCIERR_UNRECOGNIZED_COMMAND;
953 }
954
955