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