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