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