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