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