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