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