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