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