[MSACM32.DRV] Move to dll/win32.
[reactos.git] / reactos / dll / win32 / 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.wReserved1 = 0;
526 woc.dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME;
527 memcpy(lpWaveCaps, &woc, min(dwParam2, sizeof(woc)));
528
529 return MMSYSERR_NOERROR;
530 }
531 ERR("This shouldn't happen\n");
532 return MMSYSERR_ERROR;
533 }
534
535 static DWORD wodGetVolume(UINT wDevID, WAVEMAPDATA* wom, LPDWORD lpVol)
536 {
537 TRACE("(%04x %p %p)\n",wDevID, wom, lpVol);
538
539 if (WAVEMAP_IsData(wom))
540 return waveOutGetVolume(wom->u.out.hInnerWave, lpVol);
541 return MMSYSERR_NOERROR;
542 }
543
544 static DWORD wodSetVolume(UINT wDevID, WAVEMAPDATA* wom, DWORD vol)
545 {
546 TRACE("(%04x %p %08x)\n",wDevID, wom, vol);
547
548 if (WAVEMAP_IsData(wom))
549 return waveOutSetVolume(wom->u.out.hInnerWave, vol);
550 return MMSYSERR_NOERROR;
551 }
552
553 static DWORD wodPause(WAVEMAPDATA* wom)
554 {
555 TRACE("(%p)\n",wom);
556
557 return waveOutPause(wom->u.out.hInnerWave);
558 }
559
560 static DWORD wodRestart(WAVEMAPDATA* wom)
561 {
562 TRACE("(%p)\n",wom);
563
564 return waveOutRestart(wom->u.out.hInnerWave);
565 }
566
567 static DWORD wodReset(WAVEMAPDATA* wom)
568 {
569 TRACE("(%p)\n",wom);
570
571 return waveOutReset(wom->u.out.hInnerWave);
572 }
573
574 static DWORD wodBreakLoop(WAVEMAPDATA* wom)
575 {
576 TRACE("(%p)\n",wom);
577
578 return waveOutBreakLoop(wom->u.out.hInnerWave);
579 }
580
581 static DWORD wodMapperStatus(WAVEMAPDATA* wom, DWORD flags, LPVOID ptr)
582 {
583 UINT id;
584 DWORD ret = MMSYSERR_NOTSUPPORTED;
585
586 TRACE("(%p %08x %p)\n",wom, flags, ptr);
587
588 switch (flags) {
589 case WAVEOUT_MAPPER_STATUS_DEVICE:
590 ret = waveOutGetID(wom->u.out.hInnerWave, &id);
591 *(LPDWORD)ptr = id;
592 break;
593 case WAVEOUT_MAPPER_STATUS_MAPPED:
594 FIXME("Unsupported flag=%d\n", flags);
595 *(LPDWORD)ptr = 0; /* FIXME ?? */
596 break;
597 case WAVEOUT_MAPPER_STATUS_FORMAT:
598 FIXME("Unsupported flag=%d\n", flags);
599 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
600 *(LPDWORD)ptr = 0;
601 break;
602 default:
603 FIXME("Unsupported flag=%d\n", flags);
604 *(LPDWORD)ptr = 0;
605 break;
606 }
607 return ret;
608 }
609
610 static DWORD wodMapperReconfigure(WAVEMAPDATA* wom, DWORD dwParam1, DWORD dwParam2)
611 {
612 FIXME("(%p %08x %08x) stub!\n", wom, dwParam1, dwParam2);
613
614 return MMSYSERR_NOERROR;
615 }
616
617 /**************************************************************************
618 * wodMessage (MSACM.@)
619 */
620 DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
621 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
622 {
623 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
624 wDevID, wMsg, dwUser, dwParam1, dwParam2);
625
626 switch (wMsg) {
627 case DRVM_INIT:
628 case DRVM_EXIT:
629 case DRVM_ENABLE:
630 case DRVM_DISABLE:
631 /* FIXME: Pretend this is supported */
632 return 0;
633 case WODM_OPEN: return wodOpen ((DWORD_PTR*)dwUser, (LPWAVEOPENDESC)dwParam1,dwParam2);
634 case WODM_CLOSE: return wodClose ((WAVEMAPDATA*)dwUser);
635 case WODM_WRITE: return wodWrite ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
636 case WODM_PAUSE: return wodPause ((WAVEMAPDATA*)dwUser);
637 case WODM_GETPOS: return wodGetPosition ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, dwParam2);
638 case WODM_BREAKLOOP: return wodBreakLoop ((WAVEMAPDATA*)dwUser);
639 case WODM_PREPARE: return wodPrepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
640 case WODM_UNPREPARE: return wodUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
641 case WODM_GETDEVCAPS: return wodGetDevCaps (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSW)dwParam1,dwParam2);
642 case WODM_GETNUMDEVS: return 1;
643 case WODM_GETPITCH: return MMSYSERR_NOTSUPPORTED;
644 case WODM_SETPITCH: return MMSYSERR_NOTSUPPORTED;
645 case WODM_GETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED;
646 case WODM_SETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED;
647 case WODM_GETVOLUME: return wodGetVolume (wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1);
648 case WODM_SETVOLUME: return wodSetVolume (wDevID, (WAVEMAPDATA*)dwUser, dwParam1);
649 case WODM_RESTART: return wodRestart ((WAVEMAPDATA*)dwUser);
650 case WODM_RESET: return wodReset ((WAVEMAPDATA*)dwUser);
651 case WODM_MAPPER_STATUS: return wodMapperStatus ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
652 case DRVM_MAPPER_RECONFIGURE: return wodMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2);
653 /* known but not supported */
654 case DRV_QUERYDEVICEINTERFACESIZE:
655 case DRV_QUERYDEVICEINTERFACE:
656 return MMSYSERR_NOTSUPPORTED;
657 default:
658 FIXME("unknown message %d!\n", wMsg);
659 }
660 return MMSYSERR_NOTSUPPORTED;
661 }
662
663 /*======================================================================*
664 * WAVE IN part *
665 *======================================================================*/
666
667 static void CALLBACK widCallback(HWAVEIN hWave, UINT uMsg, DWORD_PTR dwInstance,
668 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
669 {
670 WAVEMAPDATA* wim = (WAVEMAPDATA*)dwInstance;
671
672 TRACE("(%p %u %lx %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
673
674 if (!WAVEMAP_IsData(wim)) {
675 ERR("Bad data\n");
676 return;
677 }
678
679 if (uMsg != WIM_OPEN && hWave != wim->u.in.hInnerWave)
680 ERR("Shouldn't happen (%p %p)\n", hWave, wim->u.in.hInnerWave);
681
682 switch (uMsg) {
683 case WIM_OPEN:
684 case WIM_CLOSE:
685 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
686 break;
687 case WIM_DATA:
688 if (wim->hAcmStream) {
689 LPWAVEHDR lpWaveHdrSrc = (LPWAVEHDR)dwParam1;
690 PACMSTREAMHEADER ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrSrc - sizeof(ACMSTREAMHEADER));
691 LPWAVEHDR lpWaveHdrDst = (LPWAVEHDR)ash->dwUser;
692
693 /* convert data just gotten from waveIn into requested format */
694 if (acmStreamConvert(wim->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) {
695 ERR("ACM conversion failed\n");
696 return;
697 } else {
698 TRACE("Converted %d bytes into %d\n", ash->cbSrcLengthUsed, ash->cbDstLengthUsed);
699 }
700 /* and setup the wavehdr to return accordingly */
701 lpWaveHdrDst->dwFlags &= ~WHDR_INQUEUE;
702 lpWaveHdrDst->dwFlags |= WHDR_DONE;
703 lpWaveHdrDst->dwBytesRecorded = ash->cbDstLengthUsed;
704 dwParam1 = (DWORD_PTR)lpWaveHdrDst;
705 }
706 break;
707 default:
708 ERR("Unknown msg %u\n", uMsg);
709 }
710
711 DriverCallback(wim->dwCallback, HIWORD(wim->dwFlags), (HDRVR)wim->u.in.hOuterWave,
712 uMsg, wim->dwClientInstance, dwParam1, dwParam2);
713 }
714
715 static DWORD widOpenHelper(WAVEMAPDATA* wim, UINT idx,
716 LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx,
717 DWORD dwFlags)
718 {
719 DWORD ret;
720
721 TRACE("(%p %04x %p %p %08x)\n", wim, idx, lpDesc, lpwfx, dwFlags);
722
723 /* source is always PCM, so the formulas below apply */
724 lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
725 lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
726 if (dwFlags & WAVE_FORMAT_QUERY) {
727 ret = acmStreamOpen(NULL, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);
728 } else {
729 ret = acmStreamOpen(&wim->hAcmStream, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, 0L);
730 }
731 if (ret == MMSYSERR_NOERROR) {
732 ret = waveInOpen(&wim->u.in.hInnerWave, idx, lpwfx,
733 (DWORD_PTR)widCallback, (DWORD_PTR)wim,
734 (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
735 if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
736 acmStreamClose(wim->hAcmStream, 0);
737 wim->hAcmStream = 0;
738 }
739 }
740 TRACE("ret = %08x\n", ret);
741 return ret;
742 }
743
744 static DWORD widOpen(DWORD_PTR *lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
745 {
746 UINT ndlo, ndhi;
747 UINT i;
748 WAVEMAPDATA* wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
749 DWORD res;
750
751 TRACE("(%p %p %08x)\n", lpdwUser, lpDesc, dwFlags);
752
753 if (!wim) {
754 WARN("no memory\n");
755 return MMSYSERR_NOMEM;
756 }
757
758 wim->self = wim;
759 wim->dwCallback = lpDesc->dwCallback;
760 wim->dwFlags = dwFlags;
761 wim->dwClientInstance = lpDesc->dwInstance;
762 wim->u.in.hOuterWave = (HWAVEIN)lpDesc->hWave;
763
764 ndhi = waveInGetNumDevs();
765 if (dwFlags & WAVE_MAPPED) {
766 if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM;
767 ndlo = lpDesc->uMappedDeviceID;
768 ndhi = ndlo + 1;
769 dwFlags &= ~WAVE_MAPPED;
770 } else {
771 ndlo = 0;
772 }
773
774 wim->avgSpeedOuter = wim->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;
775 wim->nSamplesPerSecOuter = wim->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec;
776
777 for (i = ndlo; i < ndhi; i++) {
778 if (waveInOpen(&wim->u.in.hInnerWave, i, lpDesc->lpFormat,
779 (DWORD_PTR)widCallback, (DWORD_PTR)wim,
780 (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) {
781 wim->hAcmStream = 0;
782 goto found;
783 }
784 }
785
786 if ((dwFlags & WAVE_FORMAT_DIRECT) == 0)
787 {
788 WAVEFORMATEX wfx;
789
790 wfx.wFormatTag = WAVE_FORMAT_PCM;
791 wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
792 /* try some ACM stuff */
793
794 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
795 switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
796 case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; wim->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \
797 case WAVERR_BADFORMAT: break; \
798 default: goto error; \
799 }
800
801 for (i = ndlo; i < ndhi; i++) {
802 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
803 /* first try with same stereo/mono option as source */
804 wfx.nChannels = lpDesc->lpFormat->nChannels;
805 TRY(wfx.nSamplesPerSec, 16);
806 TRY(wfx.nSamplesPerSec, 8);
807 wfx.nChannels ^= 3;
808 TRY(wfx.nSamplesPerSec, 16);
809 TRY(wfx.nSamplesPerSec, 8);
810 }
811
812 for (i = ndlo; i < ndhi; i++) {
813 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
814 /* first try with same stereo/mono option as source */
815 wfx.nChannels = lpDesc->lpFormat->nChannels;
816 TRY(96000, 16);
817 TRY(48000, 16);
818 TRY(44100, 16);
819 TRY(22050, 16);
820 TRY(11025, 16);
821
822 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
823 wfx.nChannels ^= 3;
824 TRY(96000, 16);
825 TRY(48000, 16);
826 TRY(44100, 16);
827 TRY(22050, 16);
828 TRY(11025, 16);
829
830 /* first try with same stereo/mono option as source */
831 wfx.nChannels = lpDesc->lpFormat->nChannels;
832 TRY(96000, 8);
833 TRY(48000, 8);
834 TRY(44100, 8);
835 TRY(22050, 8);
836 TRY(11025, 8);
837
838 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
839 wfx.nChannels ^= 3;
840 TRY(96000, 8);
841 TRY(48000, 8);
842 TRY(44100, 8);
843 TRY(22050, 8);
844 TRY(11025, 8);
845 }
846 #undef TRY
847 }
848
849 HeapFree(GetProcessHeap(), 0, wim);
850 WARN("ret = WAVERR_BADFORMAT\n");
851 return WAVERR_BADFORMAT;
852 found:
853 if (dwFlags & WAVE_FORMAT_QUERY) {
854 *lpdwUser = 0L;
855 HeapFree(GetProcessHeap(), 0, wim);
856 } else {
857 *lpdwUser = (DWORD_PTR)wim;
858 TRACE("Ok (stream=%p)\n", wim->hAcmStream);
859 }
860 return MMSYSERR_NOERROR;
861 error:
862 HeapFree(GetProcessHeap(), 0, wim);
863 if (res==ACMERR_NOTPOSSIBLE) {
864 WARN("ret = WAVERR_BADFORMAT\n");
865 return WAVERR_BADFORMAT;
866 }
867 WARN("ret = 0x%08x\n", res);
868 return res;
869 }
870
871 static DWORD widClose(WAVEMAPDATA* wim)
872 {
873 DWORD ret;
874
875 TRACE("(%p)\n", wim);
876
877 ret = waveInClose(wim->u.in.hInnerWave);
878 if (ret == MMSYSERR_NOERROR) {
879 if (wim->hAcmStream) {
880 ret = acmStreamClose(wim->hAcmStream, 0);
881 }
882 if (ret == MMSYSERR_NOERROR) {
883 HeapFree(GetProcessHeap(), 0, wim);
884 }
885 }
886 return ret;
887 }
888
889 static DWORD widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
890 {
891 PACMSTREAMHEADER ash;
892 LPWAVEHDR lpWaveHdrSrc;
893
894 TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2);
895
896 if (!wim->hAcmStream) {
897 return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
898 }
899
900 lpWaveHdrDst->dwFlags |= WHDR_INQUEUE;
901 ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
902
903 lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
904 return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
905 }
906
907 static DWORD widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
908 {
909 PACMSTREAMHEADER ash;
910 DWORD size;
911 DWORD dwRet;
912 LPWAVEHDR lpWaveHdrSrc;
913
914 TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2);
915
916 if (!wim->hAcmStream) {
917 return waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
918 }
919 if (acmStreamSize(wim->hAcmStream, lpWaveHdrDst->dwBufferLength, &size,
920 ACM_STREAMSIZEF_DESTINATION) != MMSYSERR_NOERROR) {
921 WARN("acmStreamSize failed\n");
922 return MMSYSERR_ERROR;
923 }
924
925 ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
926 if (ash == NULL) {
927 WARN("no memory\n");
928 return MMSYSERR_NOMEM;
929 }
930
931 ash->cbStruct = sizeof(*ash);
932 ash->fdwStatus = 0L;
933 ash->dwUser = (DWORD_PTR)lpWaveHdrDst;
934 ash->pbSrc = (LPBYTE)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
935 ash->cbSrcLength = size;
936 /* ash->cbSrcLengthUsed */
937 ash->dwSrcUser = 0L; /* FIXME ? */
938 ash->pbDst = (LPBYTE)lpWaveHdrDst->lpData;
939 ash->cbDstLength = lpWaveHdrDst->dwBufferLength;
940 /* ash->cbDstLengthUsed */
941 ash->dwDstUser = lpWaveHdrDst->dwUser; /* FIXME ? */
942 dwRet = acmStreamPrepareHeader(wim->hAcmStream, ash, 0L);
943 if (dwRet != MMSYSERR_NOERROR) {
944 WARN("acmStreamPrepareHeader failed\n");
945 goto errCleanUp;
946 }
947
948 lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
949 lpWaveHdrSrc->lpData = (LPSTR)ash->pbSrc;
950 lpWaveHdrSrc->dwBufferLength = size; /* conversion is not done yet */
951 lpWaveHdrSrc->dwFlags = 0;
952 lpWaveHdrSrc->dwLoops = 0;
953 dwRet = waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
954 if (dwRet != MMSYSERR_NOERROR) {
955 WARN("waveInPrepareHeader failed\n");
956 goto errCleanUp;
957 }
958
959 lpWaveHdrDst->reserved = (DWORD_PTR)ash;
960 lpWaveHdrDst->dwFlags = WHDR_PREPARED;
961 TRACE("=> (0)\n");
962 return MMSYSERR_NOERROR;
963 errCleanUp:
964 TRACE("=> (%d)\n", dwRet);
965 HeapFree(GetProcessHeap(), 0, ash);
966 return dwRet;
967 }
968
969 static DWORD widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
970 {
971 PACMSTREAMHEADER ash;
972 LPWAVEHDR lpWaveHdrSrc;
973 DWORD dwRet1, dwRet2;
974
975 TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2);
976
977 if (!wim->hAcmStream) {
978 return waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
979 }
980 ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
981 dwRet1 = acmStreamUnprepareHeader(wim->hAcmStream, ash, 0L);
982
983 lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
984 dwRet2 = waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
985
986 HeapFree(GetProcessHeap(), 0, ash);
987
988 lpWaveHdrDst->dwFlags &= ~WHDR_PREPARED;
989 return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
990 }
991
992 static DWORD widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2)
993 {
994 DWORD val;
995 MMTIME timepos;
996 TRACE("(%p %p %08x)\n", wim, lpTime, dwParam2);
997
998 timepos = *lpTime;
999
1000 /* For TIME_MS, we're going to recalculate using TIME_BYTES */
1001 if (lpTime->wType == TIME_MS)
1002 timepos.wType = TIME_BYTES;
1003
1004 /* This can change timepos.wType if the requested type is not supported */
1005 val = waveInGetPosition(wim->u.in.hInnerWave, &timepos, dwParam2);
1006
1007 if (timepos.wType == TIME_BYTES)
1008 {
1009 DWORD dwInnerSamplesPerOuter = wim->nSamplesPerSecInner / wim->nSamplesPerSecOuter;
1010 if (dwInnerSamplesPerOuter > 0)
1011 {
1012 DWORD dwInnerBytesPerSample = wim->avgSpeedInner / wim->nSamplesPerSecInner;
1013 DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter;
1014 DWORD remainder = 0;
1015
1016 /* If we are up sampling (going from lower sample rate to higher),
1017 ** we need to make a special accommodation for times when we've
1018 ** written a partial output sample. This happens frequently
1019 ** to us because we use msacm to do our up sampling, and it
1020 ** will up sample on an unaligned basis.
1021 ** For example, if you convert a 2 byte wide 8,000 'outer'
1022 ** buffer to a 2 byte wide 48,000 inner device, you would
1023 ** expect 2 bytes of input to produce 12 bytes of output.
1024 ** Instead, msacm will produce 8 bytes of output.
1025 ** But reporting our position as 1 byte of output is
1026 ** nonsensical; the output buffer position needs to be
1027 ** aligned on outer sample size, and aggressively rounded up.
1028 */
1029 remainder = timepos.u.cb % dwInnerBytesPerOuterSample;
1030 if (remainder > 0)
1031 {
1032 timepos.u.cb -= remainder;
1033 timepos.u.cb += dwInnerBytesPerOuterSample;
1034 }
1035 }
1036
1037 lpTime->u.cb = MulDiv(timepos.u.cb, wim->avgSpeedOuter, wim->avgSpeedInner);
1038
1039 /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
1040 if (lpTime->wType == TIME_MS)
1041 lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wim->avgSpeedOuter);
1042 else
1043 lpTime->wType = TIME_BYTES;
1044 }
1045 else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES)
1046 lpTime->u.sample = MulDiv(timepos.u.sample, wim->nSamplesPerSecOuter, wim->nSamplesPerSecInner);
1047 else
1048 /* other time types don't require conversion */
1049 lpTime->u = timepos.u;
1050
1051 return val;
1052 }
1053
1054 static DWORD widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSW lpWaveCaps, DWORD dwParam2)
1055 {
1056 TRACE("(%04x, %p %p %08x)\n", wDevID, wim, lpWaveCaps, dwParam2);
1057
1058 /* if opened low driver, forward message */
1059 if (WAVEMAP_IsData(wim))
1060 return waveInGetDevCapsW((UINT_PTR)wim->u.in.hInnerWave, lpWaveCaps, dwParam2);
1061 /* else if no drivers, nothing to map so return bad device */
1062 if (waveInGetNumDevs() == 0) {
1063 WARN("bad device id\n");
1064 return MMSYSERR_BADDEVICEID;
1065 }
1066 /* otherwise, return caps of mapper itself */
1067 if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
1068 WAVEINCAPSW wic;
1069 static const WCHAR init[] = {'W','i','n','e',' ','w','a','v','e',' ','i','n',' ','m','a','p','p','e','r',0};
1070 wic.wMid = 0x00FF;
1071 wic.wPid = 0x0001;
1072 wic.vDriverVersion = 0x0001;
1073 strcpyW(wic.szPname, init);
1074 wic.dwFormats =
1075 WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 |
1076 WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 |
1077 WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
1078 WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
1079 WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
1080 wic.wChannels = 2;
1081 wic.wReserved1 = 0;
1082 memcpy(lpWaveCaps, &wic, min(dwParam2, sizeof(wic)));
1083
1084 return MMSYSERR_NOERROR;
1085 }
1086 ERR("This shouldn't happen\n");
1087 return MMSYSERR_ERROR;
1088 }
1089
1090 static DWORD widStop(WAVEMAPDATA* wim)
1091 {
1092 TRACE("(%p)\n", wim);
1093
1094 return waveInStop(wim->u.in.hInnerWave);
1095 }
1096
1097 static DWORD widStart(WAVEMAPDATA* wim)
1098 {
1099 TRACE("(%p)\n", wim);
1100
1101 return waveInStart(wim->u.in.hInnerWave);
1102 }
1103
1104 static DWORD widReset(WAVEMAPDATA* wim)
1105 {
1106 TRACE("(%p)\n", wim);
1107
1108 return waveInReset(wim->u.in.hInnerWave);
1109 }
1110
1111 static DWORD widMapperStatus(WAVEMAPDATA* wim, DWORD flags, LPVOID ptr)
1112 {
1113 UINT id;
1114 DWORD ret = MMSYSERR_NOTSUPPORTED;
1115
1116 TRACE("(%p %08x %p)\n", wim, flags, ptr);
1117
1118 switch (flags) {
1119 case WAVEIN_MAPPER_STATUS_DEVICE:
1120 ret = waveInGetID(wim->u.in.hInnerWave, &id);
1121 *(LPDWORD)ptr = id;
1122 break;
1123 case WAVEIN_MAPPER_STATUS_MAPPED:
1124 FIXME("Unsupported yet flag=%d\n", flags);
1125 *(LPDWORD)ptr = 0; /* FIXME ?? */
1126 break;
1127 case WAVEIN_MAPPER_STATUS_FORMAT:
1128 FIXME("Unsupported flag=%d\n", flags);
1129 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
1130 *(LPDWORD)ptr = 0; /* FIXME ?? */
1131 break;
1132 default:
1133 FIXME("Unsupported flag=%d\n", flags);
1134 *(LPDWORD)ptr = 0;
1135 break;
1136 }
1137 return ret;
1138 }
1139
1140 static DWORD widMapperReconfigure(WAVEMAPDATA* wim, DWORD dwParam1, DWORD dwParam2)
1141 {
1142 FIXME("(%p %08x %08x) stub!\n", wim, dwParam1, dwParam2);
1143
1144 return MMSYSERR_NOERROR;
1145 }
1146
1147 /**************************************************************************
1148 * widMessage (MSACM.@)
1149 */
1150 DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD_PTR dwUser,
1151 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1152 {
1153 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1154 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1155
1156 switch (wMsg) {
1157 case DRVM_INIT:
1158 case DRVM_EXIT:
1159 case DRVM_ENABLE:
1160 case DRVM_DISABLE:
1161 /* FIXME: Pretend this is supported */
1162 return 0;
1163
1164 case WIDM_OPEN: return widOpen ((DWORD_PTR*)dwUser, (LPWAVEOPENDESC)dwParam1, dwParam2);
1165 case WIDM_CLOSE: return widClose ((WAVEMAPDATA*)dwUser);
1166
1167 case WIDM_ADDBUFFER: return widAddBuffer ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
1168 case WIDM_PREPARE: return widPrepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
1169 case WIDM_UNPREPARE: return widUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
1170 case WIDM_GETDEVCAPS: return widGetDevCaps (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSW)dwParam1, dwParam2);
1171 case WIDM_GETNUMDEVS: return 1;
1172 case WIDM_GETPOS: return widGetPosition ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, dwParam2);
1173 case WIDM_RESET: return widReset ((WAVEMAPDATA*)dwUser);
1174 case WIDM_START: return widStart ((WAVEMAPDATA*)dwUser);
1175 case WIDM_STOP: return widStop ((WAVEMAPDATA*)dwUser);
1176 case WIDM_MAPPER_STATUS: return widMapperStatus ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
1177 case DRVM_MAPPER_RECONFIGURE: return widMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2);
1178 /* known but not supported */
1179 case DRV_QUERYDEVICEINTERFACESIZE:
1180 case DRV_QUERYDEVICEINTERFACE:
1181 return MMSYSERR_NOTSUPPORTED;
1182 default:
1183 FIXME("unknown message %u!\n", wMsg);
1184 }
1185 return MMSYSERR_NOTSUPPORTED;
1186 }
1187
1188 /*======================================================================*
1189 * Driver part *
1190 *======================================================================*/
1191
1192 static struct WINE_WAVEMAP* oss = NULL;
1193
1194 /**************************************************************************
1195 * WAVEMAP_drvOpen [internal]
1196 */
1197 static LRESULT WAVEMAP_drvOpen(LPSTR str)
1198 {
1199 TRACE("(%p)\n", str);
1200
1201 if (oss)
1202 return 0;
1203
1204 /* I know, this is ugly, but who cares... */
1205 oss = (struct WINE_WAVEMAP*)1;
1206 return 1;
1207 }
1208
1209 /**************************************************************************
1210 * WAVEMAP_drvClose [internal]
1211 */
1212 static LRESULT WAVEMAP_drvClose(DWORD_PTR dwDevID)
1213 {
1214 TRACE("(%08lx)\n", dwDevID);
1215
1216 if (oss) {
1217 oss = NULL;
1218 return 1;
1219 }
1220 return 0;
1221 }
1222
1223 /**************************************************************************
1224 * DriverProc (MSACM.@)
1225 */
1226 LRESULT CALLBACK WAVEMAP_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
1227 LPARAM dwParam1, LPARAM dwParam2)
1228 {
1229 TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
1230 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1231
1232 switch(wMsg) {
1233 case DRV_LOAD: return 1;
1234 case DRV_FREE: return 1;
1235 case DRV_OPEN: return WAVEMAP_drvOpen((LPSTR)dwParam1);
1236 case DRV_CLOSE: return WAVEMAP_drvClose(dwDevID);
1237 case DRV_ENABLE: return 1;
1238 case DRV_DISABLE: return 1;
1239 case DRV_QUERYCONFIGURE: return 1;
1240 case DRV_CONFIGURE: MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK); return 1;
1241 case DRV_INSTALL: return DRVCNF_RESTART;
1242 case DRV_REMOVE: return DRVCNF_RESTART;
1243 default:
1244 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1245 }
1246 }