Returns proper error code when trying to get caps when no devices
[wine] / dlls / winmm / wavemap / wavemap.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * Wine Wave mapper driver
4  *
5  * Copyright    1999,2001 Eric Pouech
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 /* TODOs
23  *      + better protection against evilish dwUser parameters
24  *      + use asynchronous ACM conversion
25  *      + don't use callback functions when none is required in open
26  *      + the buffer sizes may not be accurate, so there may be some
27  *        remaining bytes in src and dst buffers after ACM conversions...
28  *              those should be taken care of...
29  */
30
31 #include <stdarg.h>
32 #include <string.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wingdi.h"
36 #include "winuser.h"
37 #include "mmddk.h"
38 #include "mmreg.h"
39 #include "msacm.h"
40 #include "wine/debug.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(msacm);
43
44 typedef struct tagWAVEMAPDATA {
45     struct tagWAVEMAPDATA*      self;
46     union {
47         struct {
48             HWAVEOUT    hOuterWave;
49             HWAVEOUT    hInnerWave;
50         } out;
51         struct {
52             HWAVEIN     hOuterWave;
53             HWAVEIN     hInnerWave;
54         } in;
55     } u;
56     HACMSTREAM  hAcmStream;
57     /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */
58     DWORD       dwCallback;
59     DWORD       dwClientInstance;
60     DWORD       dwFlags;
61     /* ratio to compute position from a PCM playback to any format */
62     DWORD       avgSpeedOuter;
63     DWORD       avgSpeedInner;
64 } WAVEMAPDATA;
65
66 static  BOOL    WAVEMAP_IsData(WAVEMAPDATA* wm)
67 {
68     return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm);
69 }
70
71 /*======================================================================*
72  *                  WAVE OUT part                                       *
73  *======================================================================*/
74
75 static void     CALLBACK wodCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwInstance,
76                                      DWORD dwParam1, DWORD dwParam2)
77 {
78     WAVEMAPDATA*        wom = (WAVEMAPDATA*)dwInstance;
79
80     TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
81
82     if (!WAVEMAP_IsData(wom)) {
83         ERR("Bad data\n");
84         return;
85     }
86
87     if (hWave != wom->u.out.hInnerWave && uMsg != WOM_OPEN)
88         ERR("Shouldn't happen (%p %p)\n", hWave, wom->u.out.hInnerWave);
89
90     switch (uMsg) {
91     case WOM_OPEN:
92     case WOM_CLOSE:
93         /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
94         break;
95     case WOM_DONE:
96         if (wom->hAcmStream) {
97             LPWAVEHDR           lpWaveHdrDst = (LPWAVEHDR)dwParam1;
98             PACMSTREAMHEADER    ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER));
99             LPWAVEHDR           lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser;
100
101             lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE;
102             lpWaveHdrSrc->dwFlags |= WHDR_DONE;
103             dwParam1 = (DWORD)lpWaveHdrSrc;
104         }
105         break;
106     default:
107         ERR("Unknown msg %u\n", uMsg);
108     }
109
110     DriverCallback(wom->dwCallback, HIWORD(wom->dwFlags), (HDRVR)wom->u.out.hOuterWave,
111                    uMsg, wom->dwClientInstance, dwParam1, dwParam2);
112 }
113
114 /******************************************************************
115  *              wodOpenHelper
116  *
117  *
118  */
119 static  DWORD   wodOpenHelper(WAVEMAPDATA* wom, UINT idx,
120                               LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx,
121                               DWORD dwFlags)
122 {
123     DWORD       ret;
124     TRACE("(%p, %04x, %p, %p, %08lx)\n", wom, idx, lpDesc, lpwfx, dwFlags);
125
126     /* destination is always PCM, so the formulas below apply */
127     lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
128     lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
129     if (dwFlags & WAVE_FORMAT_QUERY) {
130         ret = acmStreamOpen(NULL, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);
131     } else {
132         ret = acmStreamOpen(&wom->hAcmStream, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, 0L);
133     }
134     if (ret == MMSYSERR_NOERROR) {
135         ret = waveOutOpen(&wom->u.out.hInnerWave, idx, lpwfx, (DWORD)wodCallback,
136                           (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
137         if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
138             acmStreamClose(wom->hAcmStream, 0);
139             wom->hAcmStream = 0;
140         }
141     }
142     WARN("ret = %08lx\n", ret);
143     return ret;
144 }
145
146 static  DWORD   wodOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
147 {
148     UINT                ndlo, ndhi;
149     UINT                i;
150     WAVEMAPDATA*        wom = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
151     DWORD               res;
152
153     TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags);
154
155     if (!wom)
156         return MMSYSERR_NOMEM;
157
158     ndhi = waveOutGetNumDevs();
159     if (dwFlags & WAVE_MAPPED) {
160         if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM;
161         ndlo = lpDesc->uMappedDeviceID;
162         ndhi = ndlo + 1;
163         dwFlags &= ~WAVE_MAPPED;
164     } else {
165         ndlo = 0;
166     }
167     wom->self = wom;
168     wom->dwCallback = lpDesc->dwCallback;
169     wom->dwFlags = dwFlags;
170     wom->dwClientInstance = lpDesc->dwInstance;
171     wom->u.out.hOuterWave = (HWAVEOUT)lpDesc->hWave;
172     wom->avgSpeedOuter = wom->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;
173
174     for (i = ndlo; i < ndhi; i++) {
175         /* if no ACM stuff is involved, no need to handle callbacks at this
176          * level, this will be done transparently
177          */
178         if (waveOutOpen(&wom->u.out.hInnerWave, i, lpDesc->lpFormat, (DWORD)wodCallback,
179                         (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) {
180             wom->hAcmStream = 0;
181             goto found;
182         }
183     }
184
185     if ((dwFlags & WAVE_FORMAT_DIRECT) == 0) {
186         WAVEFORMATEX    wfx;
187
188         wfx.wFormatTag = WAVE_FORMAT_PCM;
189         wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
190         /* try some ACM stuff */
191
192 #define TRY(sps,bps)    wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
193                         switch (res=wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
194                             case MMSYSERR_NOERROR: wom->avgSpeedInner = wfx.nAvgBytesPerSec; goto found; \
195                             case WAVERR_BADFORMAT: break; \
196                             default: goto error; \
197                         }
198
199         /* Our resampling algorithm is quite primitive so first try
200          * to just change the bit depth and number of channels
201          */
202         for (i = ndlo; i < ndhi; i++) {
203             wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
204             wfx.nChannels = lpDesc->lpFormat->nChannels;
205             TRY(wfx.nSamplesPerSec, 16);
206             TRY(wfx.nSamplesPerSec, 8);
207             wfx.nChannels ^= 3;
208             TRY(wfx.nSamplesPerSec, 16);
209             TRY(wfx.nSamplesPerSec, 8);
210         }
211
212         for (i = ndlo; i < ndhi; i++) {
213             /* first try with same stereo/mono option as source */
214             wfx.nChannels = lpDesc->lpFormat->nChannels;
215             TRY(96000, 16);
216             TRY(48000, 16);
217             TRY(44100, 16);
218             TRY(22050, 16);
219             TRY(11025, 16);
220
221             /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
222             wfx.nChannels ^= 3;
223             TRY(96000, 16);
224             TRY(48000, 16);
225             TRY(44100, 16);
226             TRY(22050, 16);
227             TRY(11025, 16);
228
229             /* first try with same stereo/mono option as source */
230             wfx.nChannels = lpDesc->lpFormat->nChannels;
231             TRY(96000, 8);
232             TRY(48000, 8);
233             TRY(44100, 8);
234             TRY(22050, 8);
235             TRY(11025, 8);
236
237             /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
238             wfx.nChannels ^= 3;
239             TRY(96000, 8);
240             TRY(48000, 8);
241             TRY(44100, 8);
242             TRY(22050, 8);
243             TRY(11025, 8);
244         }
245 #undef TRY
246     }
247
248     HeapFree(GetProcessHeap(), 0, wom);
249     return WAVERR_BADFORMAT;
250
251 found:
252     if (dwFlags & WAVE_FORMAT_QUERY) {
253         *lpdwUser = 0L;
254         HeapFree(GetProcessHeap(), 0, wom);
255     } else {
256         *lpdwUser = (DWORD)wom;
257     }
258     return MMSYSERR_NOERROR;
259 error:
260     HeapFree(GetProcessHeap(), 0, wom);
261     if (res==ACMERR_NOTPOSSIBLE) {
262         WARN("ret = WAVERR_BADFORMAT\n");
263         return WAVERR_BADFORMAT;
264     }
265     WARN("ret = MMSYSERR_ERROR\n");
266     return MMSYSERR_ERROR;
267 }
268
269 static  DWORD   wodClose(WAVEMAPDATA* wom)
270 {
271     DWORD ret = waveOutClose(wom->u.out.hInnerWave);
272
273     if (ret == MMSYSERR_NOERROR) {
274         if (wom->hAcmStream) {
275             ret = acmStreamClose(wom->hAcmStream, 0);
276         }
277         if (ret == MMSYSERR_NOERROR) {
278             HeapFree(GetProcessHeap(), 0, wom);
279         }
280     }
281     return ret;
282 }
283
284 static  DWORD   wodWrite(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
285 {
286     PACMSTREAMHEADER    ash;
287     LPWAVEHDR           lpWaveHdrDst;
288
289     if (!wom->hAcmStream) {
290         return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
291     }
292
293     lpWaveHdrSrc->dwFlags |= WHDR_INQUEUE;
294     ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
295     /* acmStreamConvert will actually check that the new size is less than initial size */
296     ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
297     if (acmStreamConvert(wom->hAcmStream, ash, 0L) != MMSYSERR_NOERROR)
298         return MMSYSERR_ERROR;
299
300     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
301     if (ash->cbSrcLength > ash->cbSrcLengthUsed)
302         FIXME("Not all src buffer has been written, expect bogus sound\n");
303     else if (ash->cbSrcLength < ash->cbSrcLengthUsed)
304         ERR("CoDec has read more data than it is allowed to\n");
305
306     if (ash->cbDstLengthUsed == 0)
307     {
308         /* something went wrong in decoding */
309         FIXME("Got 0 length\n");
310         return MMSYSERR_ERROR;
311     }
312     lpWaveHdrDst->dwBufferLength = ash->cbDstLengthUsed;
313     return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
314 }
315
316 static  DWORD   wodPrepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
317 {
318     PACMSTREAMHEADER    ash;
319     DWORD               size;
320     DWORD               dwRet;
321     LPWAVEHDR           lpWaveHdrDst;
322
323     if (!wom->hAcmStream) {
324         return waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
325     }
326     if (acmStreamSize(wom->hAcmStream, lpWaveHdrSrc->dwBufferLength, &size, ACM_STREAMSIZEF_SOURCE) != MMSYSERR_NOERROR)
327         return MMSYSERR_ERROR;
328
329     ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
330     if (ash == NULL)
331         return MMSYSERR_NOMEM;
332
333     ash->cbStruct = sizeof(*ash);
334     ash->fdwStatus = 0L;
335     ash->dwUser = (DWORD)lpWaveHdrSrc;
336     ash->pbSrc = lpWaveHdrSrc->lpData;
337     ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
338     /* ash->cbSrcLengthUsed */
339     ash->dwSrcUser = lpWaveHdrSrc->dwUser; /* FIXME ? */
340     ash->pbDst = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
341     ash->cbDstLength = size;
342     /* ash->cbDstLengthUsed */
343     ash->dwDstUser = 0; /* FIXME ? */
344     dwRet = acmStreamPrepareHeader(wom->hAcmStream, ash, 0L);
345     if (dwRet != MMSYSERR_NOERROR)
346         goto errCleanUp;
347
348     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
349     lpWaveHdrDst->lpData = ash->pbDst;
350     lpWaveHdrDst->dwBufferLength = size; /* conversion is not done yet */
351     lpWaveHdrDst->dwFlags = 0;
352     lpWaveHdrDst->dwLoops = 0;
353     dwRet = waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
354     if (dwRet != MMSYSERR_NOERROR)
355         goto errCleanUp;
356
357     lpWaveHdrSrc->reserved = (DWORD)ash;
358     lpWaveHdrSrc->dwFlags = WHDR_PREPARED;
359     TRACE("=> (0)\n");
360     return MMSYSERR_NOERROR;
361 errCleanUp:
362     TRACE("=> (%ld)\n", dwRet);
363     HeapFree(GetProcessHeap(), 0, ash);
364     return dwRet;
365 }
366
367 static  DWORD   wodUnprepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
368 {
369     PACMSTREAMHEADER    ash;
370     LPWAVEHDR           lpWaveHdrDst;
371     DWORD               dwRet1, dwRet2;
372
373     if (!wom->hAcmStream) {
374         return waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
375     }
376     ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
377     dwRet1 = acmStreamUnprepareHeader(wom->hAcmStream, ash, 0L);
378
379     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
380     dwRet2 = waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
381
382     HeapFree(GetProcessHeap(), 0, ash);
383
384     lpWaveHdrSrc->dwFlags &= ~WHDR_PREPARED;
385     return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
386 }
387
388 static  DWORD   wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2)
389 {
390     DWORD       val = waveOutGetPosition(wom->u.out.hInnerWave, lpTime, dwParam2);
391     if (lpTime->wType == TIME_BYTES)
392         lpTime->u.cb = MulDiv(lpTime->u.cb, wom->avgSpeedOuter, wom->avgSpeedInner);
393     /* other time types don't require conversion */
394     return val;
395 }
396
397 static  DWORD   wodGetDevCaps(UINT wDevID, WAVEMAPDATA* wom, LPWAVEOUTCAPSA lpWaveCaps, DWORD dwParam2)
398 {
399     /* if opened low driver, forward message */
400     if (WAVEMAP_IsData(wom))
401         return waveOutGetDevCapsA((UINT)wom->u.out.hInnerWave, lpWaveCaps, dwParam2);
402     /* else if no drivers, nothing to map so return bad device */
403     if (waveOutGetNumDevs() == 0)
404         return MMSYSERR_BADDEVICEID;
405     /* otherwise, return caps of mapper itself */
406     if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
407         lpWaveCaps->wMid = 0x00FF;
408         lpWaveCaps->wPid = 0x0001;
409         lpWaveCaps->vDriverVersion = 0x0100;
410         strcpy(lpWaveCaps->szPname, "Wine wave out mapper");
411         lpWaveCaps->dwFormats =
412             WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 |
413             WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 |
414             WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
415             WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
416             WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
417         lpWaveCaps->wChannels = 2;
418         lpWaveCaps->dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME;
419
420         return MMSYSERR_NOERROR;
421     }
422     ERR("This shouldn't happen\n");
423     return MMSYSERR_ERROR;
424 }
425
426 static  DWORD   wodGetVolume(UINT wDevID, WAVEMAPDATA* wom, LPDWORD lpVol)
427 {
428     if (WAVEMAP_IsData(wom))
429         return waveOutGetVolume(wom->u.out.hInnerWave, lpVol);
430     return MMSYSERR_NOERROR;
431 }
432
433 static  DWORD   wodSetVolume(UINT wDevID, WAVEMAPDATA* wom, DWORD vol)
434 {
435     if (WAVEMAP_IsData(wom))
436         return waveOutSetVolume(wom->u.out.hInnerWave, vol);
437     return MMSYSERR_NOERROR;
438 }
439
440 static  DWORD   wodPause(WAVEMAPDATA* wom)
441 {
442     return waveOutPause(wom->u.out.hInnerWave);
443 }
444
445 static  DWORD   wodRestart(WAVEMAPDATA* wom)
446 {
447     return waveOutRestart(wom->u.out.hInnerWave);
448 }
449
450 static  DWORD   wodReset(WAVEMAPDATA* wom)
451 {
452     return waveOutReset(wom->u.out.hInnerWave);
453 }
454
455 static  DWORD   wodBreakLoop(WAVEMAPDATA* wom)
456 {
457     return waveOutBreakLoop(wom->u.out.hInnerWave);
458 }
459
460 static  DWORD   wodMapperStatus(WAVEMAPDATA* wom, DWORD flags, LPVOID ptr)
461 {
462     UINT        id;
463     DWORD       ret = MMSYSERR_NOTSUPPORTED;
464
465     switch (flags) {
466     case WAVEOUT_MAPPER_STATUS_DEVICE:
467         ret = waveOutGetID(wom->u.out.hInnerWave, &id);
468         *(LPDWORD)ptr = id;
469         break;
470     case WAVEOUT_MAPPER_STATUS_MAPPED:
471         FIXME("Unsupported flag=%ld\n", flags);
472         *(LPDWORD)ptr = 0; /* FIXME ?? */
473         break;
474     case WAVEOUT_MAPPER_STATUS_FORMAT:
475         FIXME("Unsupported flag=%ld\n", flags);
476         /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
477         *(LPDWORD)ptr = 0;
478         break;
479     default:
480         FIXME("Unsupported flag=%ld\n", flags);
481         *(LPDWORD)ptr = 0;
482         break;
483     }
484     return ret;
485 }
486
487 /**************************************************************************
488  *                              wodMessage (MSACM.@)
489  */
490 DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
491                                 DWORD dwParam1, DWORD dwParam2)
492 {
493     TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
494           wDevID, wMsg, dwUser, dwParam1, dwParam2);
495
496     switch (wMsg) {
497     case DRVM_INIT:
498     case DRVM_EXIT:
499     case DRVM_ENABLE:
500     case DRVM_DISABLE:
501         /* FIXME: Pretend this is supported */
502         return 0;
503     case WODM_OPEN:             return wodOpen          ((LPDWORD)dwUser,      (LPWAVEOPENDESC)dwParam1,dwParam2);
504     case WODM_CLOSE:            return wodClose         ((WAVEMAPDATA*)dwUser);
505     case WODM_WRITE:            return wodWrite         ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
506     case WODM_PAUSE:            return wodPause         ((WAVEMAPDATA*)dwUser);
507     case WODM_GETPOS:           return wodGetPosition   ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1,      dwParam2);
508     case WODM_BREAKLOOP:        return wodBreakLoop     ((WAVEMAPDATA*)dwUser);
509     case WODM_PREPARE:          return wodPrepare       ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
510     case WODM_UNPREPARE:        return wodUnprepare     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
511     case WODM_GETDEVCAPS:       return wodGetDevCaps    (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSA)dwParam1,dwParam2);
512     case WODM_GETNUMDEVS:       return 1;
513     case WODM_GETPITCH:         return MMSYSERR_NOTSUPPORTED;
514     case WODM_SETPITCH:         return MMSYSERR_NOTSUPPORTED;
515     case WODM_GETPLAYBACKRATE:  return MMSYSERR_NOTSUPPORTED;
516     case WODM_SETPLAYBACKRATE:  return MMSYSERR_NOTSUPPORTED;
517     case WODM_GETVOLUME:        return wodGetVolume     (wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1);
518     case WODM_SETVOLUME:        return wodSetVolume     (wDevID, (WAVEMAPDATA*)dwUser, dwParam1);
519     case WODM_RESTART:          return wodRestart       ((WAVEMAPDATA*)dwUser);
520     case WODM_RESET:            return wodReset         ((WAVEMAPDATA*)dwUser);
521     case WODM_MAPPER_STATUS:    return wodMapperStatus  ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
522     default:
523         FIXME("unknown message %d!\n", wMsg);
524     }
525     return MMSYSERR_NOTSUPPORTED;
526 }
527
528 /*======================================================================*
529  *                  WAVE IN part                                        *
530  *======================================================================*/
531
532 static void     CALLBACK widCallback(HWAVEIN hWave, UINT uMsg, DWORD dwInstance,
533                                      DWORD dwParam1, DWORD dwParam2)
534 {
535     WAVEMAPDATA*        wim = (WAVEMAPDATA*)dwInstance;
536
537     TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
538
539     if (!WAVEMAP_IsData(wim)) {
540         ERR("Bad data\n");
541         return;
542     }
543
544     if (hWave != wim->u.in.hInnerWave && uMsg != WIM_OPEN)
545         ERR("Shouldn't happen (%p %p)\n", hWave, wim->u.in.hInnerWave);
546
547     switch (uMsg) {
548     case WIM_OPEN:
549     case WIM_CLOSE:
550         /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
551         break;
552     case WIM_DATA:
553         if (wim->hAcmStream) {
554             LPWAVEHDR           lpWaveHdrSrc = (LPWAVEHDR)dwParam1;
555             PACMSTREAMHEADER    ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrSrc - sizeof(ACMSTREAMHEADER));
556             LPWAVEHDR           lpWaveHdrDst = (LPWAVEHDR)ash->dwUser;
557
558             /* convert data just gotten from waveIn into requested format */
559             if (acmStreamConvert(wim->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) {
560                 ERR("ACM conversion failed\n");
561                 return;
562             } else {
563                 TRACE("Converted %ld bytes into %ld\n", ash->cbSrcLengthUsed, ash->cbDstLengthUsed);
564             }
565             /* and setup the wavehdr to return accordingly */
566             lpWaveHdrDst->dwFlags &= ~WHDR_INQUEUE;
567             lpWaveHdrDst->dwFlags |= WHDR_DONE;
568             lpWaveHdrDst->dwBytesRecorded = ash->cbDstLengthUsed;
569             dwParam1 = (DWORD)lpWaveHdrDst;
570         }
571         break;
572     default:
573         ERR("Unknown msg %u\n", uMsg);
574     }
575
576     DriverCallback(wim->dwCallback, HIWORD(wim->dwFlags), (HDRVR)wim->u.in.hOuterWave,
577                    uMsg, wim->dwClientInstance, dwParam1, dwParam2);
578 }
579
580 static  DWORD   widOpenHelper(WAVEMAPDATA* wim, UINT idx,
581                               LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx,
582                               DWORD dwFlags)
583 {
584     DWORD       ret;
585
586     /* source is always PCM, so the formulas below apply */
587     lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
588     lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
589     if (dwFlags & WAVE_FORMAT_QUERY) {
590         ret = acmStreamOpen(NULL, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);
591     } else {
592         ret = acmStreamOpen(&wim->hAcmStream, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, 0L);
593     }
594     if (ret == MMSYSERR_NOERROR) {
595         ret = waveInOpen(&wim->u.in.hInnerWave, idx, lpwfx, (DWORD)widCallback,
596                          (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
597         if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
598             acmStreamClose(wim->hAcmStream, 0);
599             wim->hAcmStream = 0;
600         }
601     }
602     return ret;
603 }
604
605 static  DWORD   widOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
606 {
607     UINT                ndlo, ndhi;
608     UINT                i;
609     WAVEMAPDATA*        wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
610     DWORD               res;
611
612     TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags);
613
614     if (!wim)
615         return MMSYSERR_NOMEM;
616
617     wim->self = wim;
618     wim->dwCallback = lpDesc->dwCallback;
619     wim->dwFlags = dwFlags;
620     wim->dwClientInstance = lpDesc->dwInstance;
621     wim->u.in.hOuterWave = (HWAVEIN)lpDesc->hWave;
622
623     ndhi = waveInGetNumDevs();
624     if (dwFlags & WAVE_MAPPED) {
625         if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM;
626         ndlo = lpDesc->uMappedDeviceID;
627         ndhi = ndlo + 1;
628         dwFlags &= ~WAVE_MAPPED;
629     } else {
630         ndlo = 0;
631     }
632
633     wim->avgSpeedOuter = wim->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;
634
635     for (i = ndlo; i < ndhi; i++) {
636         if (waveInOpen(&wim->u.in.hInnerWave, i, lpDesc->lpFormat, (DWORD)widCallback,
637                        (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) {
638             wim->hAcmStream = 0;
639             goto found;
640         }
641     }
642
643     if ((dwFlags & WAVE_FORMAT_DIRECT) == 0)
644     {
645         WAVEFORMATEX    wfx;
646
647         wfx.wFormatTag = WAVE_FORMAT_PCM;
648         wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
649         /* try some ACM stuff */
650         
651 #define TRY(sps,bps)    wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
652                         switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
653                         case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; goto found; \
654                         case WAVERR_BADFORMAT: break; \
655                         default: goto error; \
656                         }
657         
658         for (i = ndlo; i < ndhi; i++) {
659             wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
660             /* first try with same stereo/mono option as source */
661             wfx.nChannels = lpDesc->lpFormat->nChannels;
662                         TRY(wfx.nSamplesPerSec, 16);
663                         TRY(wfx.nSamplesPerSec, 8);
664                         wfx.nChannels ^= 3;
665                         TRY(wfx.nSamplesPerSec, 16);
666                         TRY(wfx.nSamplesPerSec, 8);
667         }
668
669         for (i = ndlo; i < ndhi; i++) {
670             wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
671             /* first try with same stereo/mono option as source */
672             wfx.nChannels = lpDesc->lpFormat->nChannels;
673             TRY(96000, 16);
674             TRY(48000, 16);
675             TRY(44100, 16);
676             TRY(22050, 16);
677             TRY(11025, 16);
678             
679             /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
680             wfx.nChannels ^= 3;
681             TRY(96000, 16);
682             TRY(48000, 16);
683             TRY(44100, 16);
684             TRY(22050, 16);
685             TRY(11025, 16);
686
687             /* first try with same stereo/mono option as source */
688             wfx.nChannels = lpDesc->lpFormat->nChannels;
689             TRY(96000, 8);
690             TRY(48000, 8);
691             TRY(44100, 8);
692             TRY(22050, 8);
693             TRY(11025, 8);
694             
695             /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
696             wfx.nChannels ^= 3;
697             TRY(96000, 8);
698             TRY(48000, 8);
699             TRY(44100, 8);
700             TRY(22050, 8);
701             TRY(11025, 8);
702         }
703 #undef TRY
704     }
705
706     HeapFree(GetProcessHeap(), 0, wim);
707     return WAVERR_BADFORMAT;
708 found:
709     if (dwFlags & WAVE_FORMAT_QUERY) {
710         *lpdwUser = 0L;
711         HeapFree(GetProcessHeap(), 0, wim);
712     } else {
713         *lpdwUser = (DWORD)wim;
714     }
715     TRACE("Ok (stream=%08lx)\n", (DWORD)wim->hAcmStream);
716     return MMSYSERR_NOERROR;
717 error:
718     HeapFree(GetProcessHeap(), 0, wim);
719     if (res==ACMERR_NOTPOSSIBLE) {
720         WARN("ret = WAVERR_BADFORMAT\n");
721         return WAVERR_BADFORMAT;
722     }
723     WARN("ret = MMSYSERR_ERROR\n");
724     return MMSYSERR_ERROR;
725 }
726
727 static  DWORD   widClose(WAVEMAPDATA* wim)
728 {
729     DWORD ret = waveInClose(wim->u.in.hInnerWave);
730
731     if (ret == MMSYSERR_NOERROR) {
732         if (wim->hAcmStream) {
733             ret = acmStreamClose(wim->hAcmStream, 0);
734         }
735         if (ret == MMSYSERR_NOERROR) {
736             HeapFree(GetProcessHeap(), 0, wim);
737         }
738     }
739     return ret;
740 }
741
742 static  DWORD   widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
743 {
744     PACMSTREAMHEADER    ash;
745     LPWAVEHDR           lpWaveHdrSrc;
746
747     if (!wim->hAcmStream) {
748         return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
749     }
750
751     lpWaveHdrDst->dwFlags |= WHDR_INQUEUE;
752     ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
753
754     lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
755     return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
756 }
757
758 static  DWORD   widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
759 {
760     PACMSTREAMHEADER    ash;
761     DWORD               size;
762     DWORD               dwRet;
763     LPWAVEHDR           lpWaveHdrSrc;
764
765     if (!wim->hAcmStream) {
766         return waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
767     }
768     if (acmStreamSize(wim->hAcmStream, lpWaveHdrDst->dwBufferLength, &size,
769                       ACM_STREAMSIZEF_DESTINATION) != MMSYSERR_NOERROR)
770         return MMSYSERR_ERROR;
771
772     ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
773     if (ash == NULL)
774         return MMSYSERR_NOMEM;
775
776     ash->cbStruct = sizeof(*ash);
777     ash->fdwStatus = 0L;
778     ash->dwUser = (DWORD)lpWaveHdrDst;
779     ash->pbSrc = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
780     ash->cbSrcLength = size;
781     /* ash->cbSrcLengthUsed */
782     ash->dwSrcUser = 0L; /* FIXME ? */
783     ash->pbDst = lpWaveHdrDst->lpData;
784     ash->cbDstLength = lpWaveHdrDst->dwBufferLength;
785     /* ash->cbDstLengthUsed */
786     ash->dwDstUser = lpWaveHdrDst->dwUser; /* FIXME ? */
787     dwRet = acmStreamPrepareHeader(wim->hAcmStream, ash, 0L);
788     if (dwRet != MMSYSERR_NOERROR)
789         goto errCleanUp;
790
791     lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
792     lpWaveHdrSrc->lpData = ash->pbSrc;
793     lpWaveHdrSrc->dwBufferLength = size; /* conversion is not done yet */
794     lpWaveHdrSrc->dwFlags = 0;
795     lpWaveHdrSrc->dwLoops = 0;
796     dwRet = waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
797     if (dwRet != MMSYSERR_NOERROR)
798         goto errCleanUp;
799
800     lpWaveHdrDst->reserved = (DWORD)ash;
801     lpWaveHdrDst->dwFlags = WHDR_PREPARED;
802     TRACE("=> (0)\n");
803     return MMSYSERR_NOERROR;
804 errCleanUp:
805     TRACE("=> (%ld)\n", dwRet);
806     HeapFree(GetProcessHeap(), 0, ash);
807     return dwRet;
808 }
809
810 static  DWORD   widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
811 {
812     PACMSTREAMHEADER    ash;
813     LPWAVEHDR           lpWaveHdrSrc;
814     DWORD               dwRet1, dwRet2;
815
816     if (!wim->hAcmStream) {
817         return waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
818     }
819     ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
820     dwRet1 = acmStreamUnprepareHeader(wim->hAcmStream, ash, 0L);
821
822     lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
823     dwRet2 = waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
824
825     HeapFree(GetProcessHeap(), 0, ash);
826
827     lpWaveHdrDst->dwFlags &= ~WHDR_PREPARED;
828     return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
829 }
830
831 static  DWORD   widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2)
832 {
833     DWORD       val = waveInGetPosition(wim->u.in.hInnerWave, lpTime, dwParam2);
834     if (lpTime->wType == TIME_BYTES)
835         lpTime->u.cb = MulDiv(lpTime->u.cb, wim->avgSpeedOuter, wim->avgSpeedInner);
836     /* other time types don't require conversion */
837     return val;
838 }
839
840 static  DWORD   widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSA lpWaveCaps, DWORD dwParam2)
841 {
842     /* if opened low driver, forward message */
843     if (WAVEMAP_IsData(wim))
844         return waveInGetDevCapsA((UINT)wim->u.in.hInnerWave, lpWaveCaps, dwParam2);
845     /* else if no drivers, nothing to map so return bad device */
846     if (waveInGetNumDevs() == 0)
847         return MMSYSERR_BADDEVICEID;
848     /* otherwise, return caps of mapper itself */
849     if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
850         lpWaveCaps->wMid = 0x00FF;
851         lpWaveCaps->wPid = 0x0001;
852         lpWaveCaps->vDriverVersion = 0x0001;
853         strcpy(lpWaveCaps->szPname, "Wine wave in mapper");
854         lpWaveCaps->dwFormats =
855             WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 |
856             WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 |
857             WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
858             WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
859             WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
860         lpWaveCaps->wChannels = 2;
861         return MMSYSERR_NOERROR;
862     }
863     ERR("This shouldn't happen\n");
864     return MMSYSERR_ERROR;
865 }
866
867 static  DWORD   widStop(WAVEMAPDATA* wim)
868 {
869     return waveInStop(wim->u.in.hInnerWave);
870 }
871
872 static  DWORD   widStart(WAVEMAPDATA* wim)
873 {
874     return waveInStart(wim->u.in.hInnerWave);
875 }
876
877 static  DWORD   widReset(WAVEMAPDATA* wim)
878 {
879     return waveInReset(wim->u.in.hInnerWave);
880 }
881
882 static  DWORD   widMapperStatus(WAVEMAPDATA* wim, DWORD flags, LPVOID ptr)
883 {
884     UINT        id;
885     DWORD       ret = MMSYSERR_NOTSUPPORTED;
886
887     switch (flags) {
888     case WAVEIN_MAPPER_STATUS_DEVICE:
889         ret = waveInGetID(wim->u.in.hInnerWave, &id);
890         *(LPDWORD)ptr = id;
891         break;
892     case WAVEIN_MAPPER_STATUS_MAPPED:
893         FIXME("Unsupported yet flag=%ld\n", flags);
894         *(LPDWORD)ptr = 0; /* FIXME ?? */
895         break;
896     case WAVEIN_MAPPER_STATUS_FORMAT:
897         FIXME("Unsupported flag=%ld\n", flags);
898         /* ptr points to a WAVEFORMATEX struct  - before or after streaming ? */
899         *(LPDWORD)ptr = 0; /* FIXME ?? */
900         break;
901     default:
902         FIXME("Unsupported flag=%ld\n", flags);
903         *(LPDWORD)ptr = 0;
904         break;
905     }
906     return ret;
907 }
908
909 /**************************************************************************
910  *                              widMessage (MSACM.@)
911  */
912 DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
913                                 DWORD dwParam1, DWORD dwParam2)
914 {
915     TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
916           wDevID, wMsg, dwUser, dwParam1, dwParam2);
917
918     switch (wMsg) {
919     case DRVM_INIT:
920     case DRVM_EXIT:
921     case DRVM_ENABLE:
922     case DRVM_DISABLE:
923         /* FIXME: Pretend this is supported */
924         return 0;
925
926     case WIDM_OPEN:             return widOpen          ((LPDWORD)dwUser,     (LPWAVEOPENDESC)dwParam1, dwParam2);
927     case WIDM_CLOSE:            return widClose         ((WAVEMAPDATA*)dwUser);
928
929     case WIDM_ADDBUFFER:        return widAddBuffer     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
930     case WIDM_PREPARE:          return widPrepare       ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
931     case WIDM_UNPREPARE:        return widUnprepare     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
932     case WIDM_GETDEVCAPS:       return widGetDevCaps    (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSA)dwParam1, dwParam2);
933     case WIDM_GETNUMDEVS:       return 1;
934     case WIDM_GETPOS:           return widGetPosition   ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1,      dwParam2);
935     case WIDM_RESET:            return widReset         ((WAVEMAPDATA*)dwUser);
936     case WIDM_START:            return widStart         ((WAVEMAPDATA*)dwUser);
937     case WIDM_STOP:             return widStop          ((WAVEMAPDATA*)dwUser);
938     case WIDM_MAPPER_STATUS:    return widMapperStatus  ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
939     default:
940         FIXME("unknown message %u!\n", wMsg);
941     }
942     return MMSYSERR_NOTSUPPORTED;
943 }
944
945 /*======================================================================*
946  *                  Driver part                                         *
947  *======================================================================*/
948
949 static  struct WINE_WAVEMAP* oss = NULL;
950
951 /**************************************************************************
952  *                              WAVEMAP_drvOpen                 [internal]
953  */
954 static  DWORD   WAVEMAP_drvOpen(LPSTR str)
955 {
956     if (oss)
957         return 0;
958
959     /* I know, this is ugly, but who cares... */
960     oss = (struct WINE_WAVEMAP*)1;
961     return 1;
962 }
963
964 /**************************************************************************
965  *                              WAVEMAP_drvClose                [internal]
966  */
967 static  DWORD   WAVEMAP_drvClose(DWORD dwDevID)
968 {
969     if (oss) {
970         oss = NULL;
971         return 1;
972     }
973     return 0;
974 }
975
976 /**************************************************************************
977  *                              DriverProc (MSACM.@)
978  */
979 LONG CALLBACK   WAVEMAP_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
980                                    DWORD dwParam1, DWORD dwParam2)
981 {
982     TRACE("(%08lX, %p, %08lX, %08lX, %08lX)\n",
983           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
984
985     switch(wMsg) {
986     case DRV_LOAD:              return 1;
987     case DRV_FREE:              return 1;
988     case DRV_OPEN:              return WAVEMAP_drvOpen((LPSTR)dwParam1);
989     case DRV_CLOSE:             return WAVEMAP_drvClose(dwDevID);
990     case DRV_ENABLE:            return 1;
991     case DRV_DISABLE:           return 1;
992     case DRV_QUERYCONFIGURE:    return 1;
993     case DRV_CONFIGURE:         MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK);     return 1;
994     case DRV_INSTALL:           return DRVCNF_RESTART;
995     case DRV_REMOVE:            return DRVCNF_RESTART;
996     default:
997         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
998     }
999 }