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