1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 * Wine Wave mapper driver
5 * Copyright 1999,2001 Eric Pouech
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.
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.
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
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...
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(wavemap
);
45 typedef struct tagWAVEMAPDATA
{
46 struct tagWAVEMAPDATA
* self
;
57 HACMSTREAM hAcmStream
;
58 /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */
60 DWORD_PTR dwClientInstance
;
62 /* ratio to compute position from a PCM playback to any format */
65 /* channel size of inner and outer */
66 DWORD nSamplesPerSecOuter
;
67 DWORD nSamplesPerSecInner
;
70 static BOOL
WAVEMAP_IsData(const WAVEMAPDATA
* wm
)
72 return (!IsBadReadPtr(wm
, sizeof(WAVEMAPDATA
)) && wm
->self
== wm
);
75 /*======================================================================*
77 *======================================================================*/
79 static void CALLBACK
wodCallback(HWAVEOUT hWave
, UINT uMsg
, DWORD_PTR dwInstance
,
80 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
82 WAVEMAPDATA
* wom
= (WAVEMAPDATA
*)dwInstance
;
84 TRACE("(%p %u %ld %lx %lx);\n", hWave
, uMsg
, dwInstance
, dwParam1
, dwParam2
);
86 if (!WAVEMAP_IsData(wom
)) {
91 if (uMsg
!= WOM_OPEN
&& hWave
!= wom
->u
.out
.hInnerWave
)
92 ERR("Shouldn't happen (%p %p)\n", hWave
, wom
->u
.out
.hInnerWave
);
97 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
100 if (wom
->hAcmStream
) {
101 LPWAVEHDR lpWaveHdrDst
= (LPWAVEHDR
)dwParam1
;
102 PACMSTREAMHEADER ash
= (PACMSTREAMHEADER
)((LPSTR
)lpWaveHdrDst
- sizeof(ACMSTREAMHEADER
));
103 LPWAVEHDR lpWaveHdrSrc
= (LPWAVEHDR
)ash
->dwUser
;
105 lpWaveHdrSrc
->dwFlags
&= ~WHDR_INQUEUE
;
106 lpWaveHdrSrc
->dwFlags
|= WHDR_DONE
;
107 dwParam1
= (DWORD_PTR
)lpWaveHdrSrc
;
111 ERR("Unknown msg %u\n", uMsg
);
114 DriverCallback(wom
->dwCallback
, HIWORD(wom
->dwFlags
), (HDRVR
)wom
->u
.out
.hOuterWave
,
115 uMsg
, wom
->dwClientInstance
, dwParam1
, dwParam2
);
118 /******************************************************************
123 static DWORD
wodOpenHelper(WAVEMAPDATA
* wom
, UINT idx
,
124 LPWAVEOPENDESC lpDesc
, LPWAVEFORMATEX lpwfx
,
129 TRACE("(%p %04x %p %p %08x)\n", wom
, idx
, lpDesc
, lpwfx
, dwFlags
);
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
);
137 ret
= acmStreamOpen(&wom
->hAcmStream
, 0, lpDesc
->lpFormat
, lpwfx
, NULL
, 0L, 0L, 0L);
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);
148 TRACE("ret = %08x\n", ret
);
152 static DWORD
wodOpen(DWORD_PTR
*lpdwUser
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
156 WAVEMAPDATA
* wom
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA
));
159 TRACE("(%p %p %08x)\n", lpdwUser
, lpDesc
, dwFlags
);
163 return MMSYSERR_NOMEM
;
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
;
173 ndlo
= lpDesc
->uMappedDeviceID
;
175 dwFlags
&= ~WAVE_MAPPED
;
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
;
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
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
) {
199 if ((dwFlags
& WAVE_FORMAT_DIRECT
) == 0) {
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 */
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; \
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
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);
224 /* Our resampling algorithm is quite primitive so first try
225 * to just change the bit depth and number of channels
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);
233 TRY(wfx
.nSamplesPerSec
, 16);
234 TRY(wfx
.nSamplesPerSec
, 8);
237 for (i
= ndlo
; i
< ndhi
; i
++) {
238 /* first try with same stereo/mono option as source */
239 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
246 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
254 /* first try with same stereo/mono option as source */
255 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
262 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
274 HeapFree(GetProcessHeap(), 0, wom
);
275 WARN("ret = WAVERR_BADFORMAT\n");
276 return WAVERR_BADFORMAT
;
279 if (dwFlags
& WAVE_FORMAT_QUERY
) {
281 HeapFree(GetProcessHeap(), 0, wom
);
283 *lpdwUser
= (DWORD_PTR
)wom
;
285 return MMSYSERR_NOERROR
;
287 HeapFree(GetProcessHeap(), 0, wom
);
288 if (res
==ACMERR_NOTPOSSIBLE
) {
289 WARN("ret = WAVERR_BADFORMAT\n");
290 return WAVERR_BADFORMAT
;
292 WARN("ret = 0x%08x\n", res
);
296 static DWORD
wodClose(WAVEMAPDATA
* wom
)
300 TRACE("(%p)\n", wom
);
302 ret
= waveOutClose(wom
->u
.out
.hInnerWave
);
303 if (ret
== MMSYSERR_NOERROR
) {
304 if (wom
->hAcmStream
) {
305 ret
= acmStreamClose(wom
->hAcmStream
, 0);
307 if (ret
== MMSYSERR_NOERROR
) {
308 HeapFree(GetProcessHeap(), 0, wom
);
314 static DWORD
wodWrite(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
316 PACMSTREAMHEADER ash
;
317 LPWAVEHDR lpWaveHdrDst
;
319 TRACE("(%p %p %08x)\n", wom
, lpWaveHdrSrc
, dwParam2
);
321 if (!wom
->hAcmStream
) {
322 return waveOutWrite(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
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
;
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");
340 if (ash
->cbDstLengthUsed
== 0) {
341 /* something went wrong in decoding */
342 FIXME("Got 0 length\n");
343 return MMSYSERR_ERROR
;
345 lpWaveHdrDst
->dwBufferLength
= ash
->cbDstLengthUsed
;
346 return waveOutWrite(wom
->u
.out
.hInnerWave
, lpWaveHdrDst
, sizeof(*lpWaveHdrDst
));
349 static DWORD
wodPrepare(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
351 PACMSTREAMHEADER ash
;
354 LPWAVEHDR lpWaveHdrDst
;
356 TRACE("(%p %p %08x)\n", wom
, lpWaveHdrSrc
, dwParam2
);
358 if (!wom
->hAcmStream
)
359 return waveOutPrepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
361 if (acmStreamSize(wom
->hAcmStream
, lpWaveHdrSrc
->dwBufferLength
, &size
, ACM_STREAMSIZEF_SOURCE
) != MMSYSERR_NOERROR
) {
362 WARN("acmStreamSize failed\n");
363 return MMSYSERR_ERROR
;
366 ash
= HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
) + size
);
369 return MMSYSERR_NOMEM
;
372 ash
->cbStruct
= sizeof(*ash
);
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");
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");
400 lpWaveHdrSrc
->reserved
= (DWORD_PTR
)ash
;
401 lpWaveHdrSrc
->dwFlags
= WHDR_PREPARED
;
403 return MMSYSERR_NOERROR
;
405 TRACE("=> (%d)\n", dwRet
);
406 HeapFree(GetProcessHeap(), 0, ash
);
410 static DWORD
wodUnprepare(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
412 PACMSTREAMHEADER ash
;
413 LPWAVEHDR lpWaveHdrDst
;
414 DWORD dwRet1
, dwRet2
;
416 TRACE("(%p %p %08x)\n", wom
, lpWaveHdrSrc
, dwParam2
);
418 if (!wom
->hAcmStream
) {
419 return waveOutUnprepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
421 ash
= (PACMSTREAMHEADER
)lpWaveHdrSrc
->reserved
;
422 dwRet1
= acmStreamUnprepareHeader(wom
->hAcmStream
, ash
, 0L);
424 lpWaveHdrDst
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
425 dwRet2
= waveOutUnprepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrDst
, sizeof(*lpWaveHdrDst
));
427 HeapFree(GetProcessHeap(), 0, ash
);
429 lpWaveHdrSrc
->dwFlags
&= ~WHDR_PREPARED
;
430 return (dwRet1
== MMSYSERR_NOERROR
) ? dwRet2
: dwRet1
;
433 static DWORD
wodGetPosition(WAVEMAPDATA
* wom
, LPMMTIME lpTime
, DWORD dwParam2
)
437 TRACE("(%p %p %08x)\n", wom
, lpTime
, dwParam2
);
441 /* For TIME_MS, we're going to recalculate using TIME_BYTES */
442 if (lpTime
->wType
== TIME_MS
)
443 timepos
.wType
= TIME_BYTES
;
445 /* This can change timepos.wType if the requested type is not supported */
446 val
= waveOutGetPosition(wom
->u
.out
.hInnerWave
, &timepos
, dwParam2
);
448 if (timepos
.wType
== TIME_BYTES
)
450 DWORD dwInnerSamplesPerOuter
= wom
->nSamplesPerSecInner
/ wom
->nSamplesPerSecOuter
;
451 if (dwInnerSamplesPerOuter
> 0)
453 DWORD dwInnerBytesPerSample
= wom
->avgSpeedInner
/ wom
->nSamplesPerSecInner
;
454 DWORD dwInnerBytesPerOuterSample
= dwInnerBytesPerSample
* dwInnerSamplesPerOuter
;
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.
470 remainder
= timepos
.u
.cb
% dwInnerBytesPerOuterSample
;
473 timepos
.u
.cb
-= remainder
;
474 timepos
.u
.cb
+= dwInnerBytesPerOuterSample
;
478 lpTime
->u
.cb
= MulDiv(timepos
.u
.cb
, wom
->avgSpeedOuter
, wom
->avgSpeedInner
);
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
);
484 lpTime
->wType
= TIME_BYTES
;
486 else if (lpTime
->wType
== TIME_SAMPLES
&& timepos
.wType
== TIME_SAMPLES
)
487 lpTime
->u
.sample
= MulDiv(timepos
.u
.sample
, wom
->nSamplesPerSecOuter
, wom
->nSamplesPerSecInner
);
489 /* other time types don't require conversion */
490 lpTime
->u
= timepos
.u
;
495 static DWORD
wodGetDevCaps(UINT wDevID
, WAVEMAPDATA
* wom
, LPWAVEOUTCAPSW lpWaveCaps
, DWORD dwParam2
)
497 static const WCHAR name
[] = {'W','i','n','e',' ','w','a','v','e',' ','o','u','t',' ','m','a','p','p','e','r',0};
499 TRACE("(%04x %p %p %08x)\n",wDevID
, wom
, lpWaveCaps
, dwParam2
);
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
;
509 /* otherwise, return caps of mapper itself */
510 if (wDevID
== (UINT
)-1 || wDevID
== (UINT16
)-1) {
514 woc
.vDriverVersion
= 0x0332;
515 lstrcpyW(woc
.szPname
, name
);
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
;
523 woc
.dwSupport
= WAVECAPS_VOLUME
| WAVECAPS_LRVOLUME
;
524 memcpy(lpWaveCaps
, &woc
, min(dwParam2
, sizeof(woc
)));
526 return MMSYSERR_NOERROR
;
528 ERR("This shouldn't happen\n");
529 return MMSYSERR_ERROR
;
532 static DWORD
wodGetVolume(UINT wDevID
, WAVEMAPDATA
* wom
, LPDWORD lpVol
)
534 TRACE("(%04x %p %p)\n",wDevID
, wom
, lpVol
);
536 if (WAVEMAP_IsData(wom
))
537 return waveOutGetVolume(wom
->u
.out
.hInnerWave
, lpVol
);
538 return MMSYSERR_NOERROR
;
541 static DWORD
wodSetVolume(UINT wDevID
, WAVEMAPDATA
* wom
, DWORD vol
)
543 TRACE("(%04x %p %08x)\n",wDevID
, wom
, vol
);
545 if (WAVEMAP_IsData(wom
))
546 return waveOutSetVolume(wom
->u
.out
.hInnerWave
, vol
);
547 return MMSYSERR_NOERROR
;
550 static DWORD
wodPause(WAVEMAPDATA
* wom
)
554 return waveOutPause(wom
->u
.out
.hInnerWave
);
557 static DWORD
wodRestart(WAVEMAPDATA
* wom
)
561 return waveOutRestart(wom
->u
.out
.hInnerWave
);
564 static DWORD
wodReset(WAVEMAPDATA
* wom
)
568 return waveOutReset(wom
->u
.out
.hInnerWave
);
571 static DWORD
wodBreakLoop(WAVEMAPDATA
* wom
)
575 return waveOutBreakLoop(wom
->u
.out
.hInnerWave
);
578 static DWORD
wodMapperStatus(WAVEMAPDATA
* wom
, DWORD flags
, LPVOID ptr
)
581 DWORD ret
= MMSYSERR_NOTSUPPORTED
;
583 TRACE("(%p %08x %p)\n",wom
, flags
, ptr
);
586 case WAVEOUT_MAPPER_STATUS_DEVICE
:
587 ret
= waveOutGetID(wom
->u
.out
.hInnerWave
, &id
);
590 case WAVEOUT_MAPPER_STATUS_MAPPED
:
591 FIXME("Unsupported flag=%d\n", flags
);
592 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
594 case WAVEOUT_MAPPER_STATUS_FORMAT
:
595 FIXME("Unsupported flag=%d\n", flags
);
596 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
600 FIXME("Unsupported flag=%d\n", flags
);
607 static DWORD
wodMapperReconfigure(WAVEMAPDATA
* wom
, DWORD dwParam1
, DWORD dwParam2
)
609 FIXME("(%p %08x %08x) stub!\n", wom
, dwParam1
, dwParam2
);
611 return MMSYSERR_NOERROR
;
614 /**************************************************************************
615 * wodMessage (MSACM.@)
617 DWORD WINAPI
WAVEMAP_wodMessage(UINT wDevID
, UINT wMsg
, DWORD_PTR dwUser
,
618 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
620 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
621 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
628 /* FIXME: Pretend this is supported */
630 case WODM_OPEN
: return wodOpen ((DWORD_PTR
*)dwUser
, (LPWAVEOPENDESC
)dwParam1
,dwParam2
);
631 case WODM_CLOSE
: return wodClose ((WAVEMAPDATA
*)dwUser
);
632 case WODM_WRITE
: return wodWrite ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
633 case WODM_PAUSE
: return wodPause ((WAVEMAPDATA
*)dwUser
);
634 case WODM_GETPOS
: return wodGetPosition ((WAVEMAPDATA
*)dwUser
, (LPMMTIME
)dwParam1
, dwParam2
);
635 case WODM_BREAKLOOP
: return wodBreakLoop ((WAVEMAPDATA
*)dwUser
);
636 case WODM_PREPARE
: return wodPrepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
637 case WODM_UNPREPARE
: return wodUnprepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
638 case WODM_GETDEVCAPS
: return wodGetDevCaps (wDevID
, (WAVEMAPDATA
*)dwUser
, (LPWAVEOUTCAPSW
)dwParam1
,dwParam2
);
639 case WODM_GETNUMDEVS
: return 1;
640 case WODM_GETPITCH
: return MMSYSERR_NOTSUPPORTED
;
641 case WODM_SETPITCH
: return MMSYSERR_NOTSUPPORTED
;
642 case WODM_GETPLAYBACKRATE
: return MMSYSERR_NOTSUPPORTED
;
643 case WODM_SETPLAYBACKRATE
: return MMSYSERR_NOTSUPPORTED
;
644 case WODM_GETVOLUME
: return wodGetVolume (wDevID
, (WAVEMAPDATA
*)dwUser
, (LPDWORD
)dwParam1
);
645 case WODM_SETVOLUME
: return wodSetVolume (wDevID
, (WAVEMAPDATA
*)dwUser
, dwParam1
);
646 case WODM_RESTART
: return wodRestart ((WAVEMAPDATA
*)dwUser
);
647 case WODM_RESET
: return wodReset ((WAVEMAPDATA
*)dwUser
);
648 case WODM_MAPPER_STATUS
: return wodMapperStatus ((WAVEMAPDATA
*)dwUser
, dwParam1
, (LPVOID
)dwParam2
);
649 case DRVM_MAPPER_RECONFIGURE
: return wodMapperReconfigure((WAVEMAPDATA
*)dwUser
, dwParam1
, dwParam2
);
650 /* known but not supported */
651 case DRV_QUERYDEVICEINTERFACESIZE
:
652 case DRV_QUERYDEVICEINTERFACE
:
653 return MMSYSERR_NOTSUPPORTED
;
655 FIXME("unknown message %d!\n", wMsg
);
657 return MMSYSERR_NOTSUPPORTED
;
660 /*======================================================================*
662 *======================================================================*/
664 static void CALLBACK
widCallback(HWAVEIN hWave
, UINT uMsg
, DWORD_PTR dwInstance
,
665 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
667 WAVEMAPDATA
* wim
= (WAVEMAPDATA
*)dwInstance
;
669 TRACE("(%p %u %lx %lx %lx);\n", hWave
, uMsg
, dwInstance
, dwParam1
, dwParam2
);
671 if (!WAVEMAP_IsData(wim
)) {
676 if (uMsg
!= WIM_OPEN
&& hWave
!= wim
->u
.in
.hInnerWave
)
677 ERR("Shouldn't happen (%p %p)\n", hWave
, wim
->u
.in
.hInnerWave
);
682 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
685 if (wim
->hAcmStream
) {
686 LPWAVEHDR lpWaveHdrSrc
= (LPWAVEHDR
)dwParam1
;
687 PACMSTREAMHEADER ash
= (PACMSTREAMHEADER
)((LPSTR
)lpWaveHdrSrc
- sizeof(ACMSTREAMHEADER
));
688 LPWAVEHDR lpWaveHdrDst
= (LPWAVEHDR
)ash
->dwUser
;
690 /* convert data just gotten from waveIn into requested format */
691 if (acmStreamConvert(wim
->hAcmStream
, ash
, 0L) != MMSYSERR_NOERROR
) {
692 ERR("ACM conversion failed\n");
695 TRACE("Converted %d bytes into %d\n", ash
->cbSrcLengthUsed
, ash
->cbDstLengthUsed
);
697 /* and setup the wavehdr to return accordingly */
698 lpWaveHdrDst
->dwFlags
&= ~WHDR_INQUEUE
;
699 lpWaveHdrDst
->dwFlags
|= WHDR_DONE
;
700 lpWaveHdrDst
->dwBytesRecorded
= ash
->cbDstLengthUsed
;
701 dwParam1
= (DWORD_PTR
)lpWaveHdrDst
;
705 ERR("Unknown msg %u\n", uMsg
);
708 DriverCallback(wim
->dwCallback
, HIWORD(wim
->dwFlags
), (HDRVR
)wim
->u
.in
.hOuterWave
,
709 uMsg
, wim
->dwClientInstance
, dwParam1
, dwParam2
);
712 static DWORD
widOpenHelper(WAVEMAPDATA
* wim
, UINT idx
,
713 LPWAVEOPENDESC lpDesc
, LPWAVEFORMATEX lpwfx
,
718 TRACE("(%p %04x %p %p %08x)\n", wim
, idx
, lpDesc
, lpwfx
, dwFlags
);
720 /* source is always PCM, so the formulas below apply */
721 lpwfx
->nBlockAlign
= (lpwfx
->nChannels
* lpwfx
->wBitsPerSample
) / 8;
722 lpwfx
->nAvgBytesPerSec
= lpwfx
->nSamplesPerSec
* lpwfx
->nBlockAlign
;
723 if (dwFlags
& WAVE_FORMAT_QUERY
) {
724 ret
= acmStreamOpen(NULL
, 0, lpwfx
, lpDesc
->lpFormat
, NULL
, 0L, 0L, ACM_STREAMOPENF_QUERY
);
726 ret
= acmStreamOpen(&wim
->hAcmStream
, 0, lpwfx
, lpDesc
->lpFormat
, NULL
, 0L, 0L, 0L);
728 if (ret
== MMSYSERR_NOERROR
) {
729 ret
= waveInOpen(&wim
->u
.in
.hInnerWave
, idx
, lpwfx
,
730 (DWORD_PTR
)widCallback
, (DWORD_PTR
)wim
,
731 (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
);
732 if (ret
!= MMSYSERR_NOERROR
&& !(dwFlags
& WAVE_FORMAT_QUERY
)) {
733 acmStreamClose(wim
->hAcmStream
, 0);
737 TRACE("ret = %08x\n", ret
);
741 static DWORD
widOpen(DWORD_PTR
*lpdwUser
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
745 WAVEMAPDATA
* wim
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA
));
748 TRACE("(%p %p %08x)\n", lpdwUser
, lpDesc
, dwFlags
);
752 return MMSYSERR_NOMEM
;
756 wim
->dwCallback
= lpDesc
->dwCallback
;
757 wim
->dwFlags
= dwFlags
;
758 wim
->dwClientInstance
= lpDesc
->dwInstance
;
759 wim
->u
.in
.hOuterWave
= (HWAVEIN
)lpDesc
->hWave
;
761 ndhi
= waveInGetNumDevs();
762 if (dwFlags
& WAVE_MAPPED
) {
763 if (lpDesc
->uMappedDeviceID
>= ndhi
) return MMSYSERR_INVALPARAM
;
764 ndlo
= lpDesc
->uMappedDeviceID
;
766 dwFlags
&= ~WAVE_MAPPED
;
771 wim
->avgSpeedOuter
= wim
->avgSpeedInner
= lpDesc
->lpFormat
->nAvgBytesPerSec
;
772 wim
->nSamplesPerSecOuter
= wim
->nSamplesPerSecInner
= lpDesc
->lpFormat
->nSamplesPerSec
;
774 for (i
= ndlo
; i
< ndhi
; i
++) {
775 if (waveInOpen(&wim
->u
.in
.hInnerWave
, i
, lpDesc
->lpFormat
,
776 (DWORD_PTR
)widCallback
, (DWORD_PTR
)wim
,
777 (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
| WAVE_FORMAT_DIRECT
) == MMSYSERR_NOERROR
) {
783 if ((dwFlags
& WAVE_FORMAT_DIRECT
) == 0)
787 wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
788 wfx
.cbSize
= 0; /* normally, this field is not used for PCM format, just in case */
789 /* try some ACM stuff */
791 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
792 switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
793 case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; wim->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \
794 case WAVERR_BADFORMAT: break; \
795 default: goto error; \
798 for (i
= ndlo
; i
< ndhi
; i
++) {
799 wfx
.nSamplesPerSec
=lpDesc
->lpFormat
->nSamplesPerSec
;
800 /* first try with same stereo/mono option as source */
801 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
802 TRY(wfx
.nSamplesPerSec
, 16);
803 TRY(wfx
.nSamplesPerSec
, 8);
805 TRY(wfx
.nSamplesPerSec
, 16);
806 TRY(wfx
.nSamplesPerSec
, 8);
809 for (i
= ndlo
; i
< ndhi
; i
++) {
810 wfx
.nSamplesPerSec
=lpDesc
->lpFormat
->nSamplesPerSec
;
811 /* first try with same stereo/mono option as source */
812 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
819 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
827 /* first try with same stereo/mono option as source */
828 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
835 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
846 HeapFree(GetProcessHeap(), 0, wim
);
847 WARN("ret = WAVERR_BADFORMAT\n");
848 return WAVERR_BADFORMAT
;
850 if (dwFlags
& WAVE_FORMAT_QUERY
) {
852 HeapFree(GetProcessHeap(), 0, wim
);
854 *lpdwUser
= (DWORD_PTR
)wim
;
856 TRACE("Ok (stream=%p)\n", wim
->hAcmStream
);
857 return MMSYSERR_NOERROR
;
859 HeapFree(GetProcessHeap(), 0, wim
);
860 if (res
==ACMERR_NOTPOSSIBLE
) {
861 WARN("ret = WAVERR_BADFORMAT\n");
862 return WAVERR_BADFORMAT
;
864 WARN("ret = 0x%08x\n", res
);
868 static DWORD
widClose(WAVEMAPDATA
* wim
)
872 TRACE("(%p)\n", wim
);
874 ret
= waveInClose(wim
->u
.in
.hInnerWave
);
875 if (ret
== MMSYSERR_NOERROR
) {
876 if (wim
->hAcmStream
) {
877 ret
= acmStreamClose(wim
->hAcmStream
, 0);
879 if (ret
== MMSYSERR_NOERROR
) {
880 HeapFree(GetProcessHeap(), 0, wim
);
886 static DWORD
widAddBuffer(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
888 PACMSTREAMHEADER ash
;
889 LPWAVEHDR lpWaveHdrSrc
;
891 TRACE("(%p %p %08x)\n", wim
, lpWaveHdrDst
, dwParam2
);
893 if (!wim
->hAcmStream
) {
894 return waveInAddBuffer(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
897 lpWaveHdrDst
->dwFlags
|= WHDR_INQUEUE
;
898 ash
= (PACMSTREAMHEADER
)lpWaveHdrDst
->reserved
;
900 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
901 return waveInAddBuffer(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
904 static DWORD
widPrepare(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
906 PACMSTREAMHEADER ash
;
909 LPWAVEHDR lpWaveHdrSrc
;
911 TRACE("(%p %p %08x)\n", wim
, lpWaveHdrDst
, dwParam2
);
913 if (!wim
->hAcmStream
) {
914 return waveInPrepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
916 if (acmStreamSize(wim
->hAcmStream
, lpWaveHdrDst
->dwBufferLength
, &size
,
917 ACM_STREAMSIZEF_DESTINATION
) != MMSYSERR_NOERROR
) {
918 WARN("acmStreamSize failed\n");
919 return MMSYSERR_ERROR
;
922 ash
= HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
) + size
);
925 return MMSYSERR_NOMEM
;
928 ash
->cbStruct
= sizeof(*ash
);
930 ash
->dwUser
= (DWORD_PTR
)lpWaveHdrDst
;
931 ash
->pbSrc
= (LPBYTE
)ash
+ sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
);
932 ash
->cbSrcLength
= size
;
933 /* ash->cbSrcLengthUsed */
934 ash
->dwSrcUser
= 0L; /* FIXME ? */
935 ash
->pbDst
= (LPBYTE
)lpWaveHdrDst
->lpData
;
936 ash
->cbDstLength
= lpWaveHdrDst
->dwBufferLength
;
937 /* ash->cbDstLengthUsed */
938 ash
->dwDstUser
= lpWaveHdrDst
->dwUser
; /* FIXME ? */
939 dwRet
= acmStreamPrepareHeader(wim
->hAcmStream
, ash
, 0L);
940 if (dwRet
!= MMSYSERR_NOERROR
) {
941 WARN("acmStreamPrepareHeader failed\n");
945 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
946 lpWaveHdrSrc
->lpData
= (LPSTR
)ash
->pbSrc
;
947 lpWaveHdrSrc
->dwBufferLength
= size
; /* conversion is not done yet */
948 lpWaveHdrSrc
->dwFlags
= 0;
949 lpWaveHdrSrc
->dwLoops
= 0;
950 dwRet
= waveInPrepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
951 if (dwRet
!= MMSYSERR_NOERROR
) {
952 WARN("waveInPrepareHeader failed\n");
956 lpWaveHdrDst
->reserved
= (DWORD_PTR
)ash
;
957 lpWaveHdrDst
->dwFlags
= WHDR_PREPARED
;
959 return MMSYSERR_NOERROR
;
961 TRACE("=> (%d)\n", dwRet
);
962 HeapFree(GetProcessHeap(), 0, ash
);
966 static DWORD
widUnprepare(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
968 PACMSTREAMHEADER ash
;
969 LPWAVEHDR lpWaveHdrSrc
;
970 DWORD dwRet1
, dwRet2
;
972 TRACE("(%p %p %08x)\n", wim
, lpWaveHdrDst
, dwParam2
);
974 if (!wim
->hAcmStream
) {
975 return waveInUnprepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
977 ash
= (PACMSTREAMHEADER
)lpWaveHdrDst
->reserved
;
978 dwRet1
= acmStreamUnprepareHeader(wim
->hAcmStream
, ash
, 0L);
980 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
981 dwRet2
= waveInUnprepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
983 HeapFree(GetProcessHeap(), 0, ash
);
985 lpWaveHdrDst
->dwFlags
&= ~WHDR_PREPARED
;
986 return (dwRet1
== MMSYSERR_NOERROR
) ? dwRet2
: dwRet1
;
989 static DWORD
widGetPosition(WAVEMAPDATA
* wim
, LPMMTIME lpTime
, DWORD dwParam2
)
993 TRACE("(%p %p %08x)\n", wim
, lpTime
, dwParam2
);
997 /* For TIME_MS, we're going to recalculate using TIME_BYTES */
998 if (lpTime
->wType
== TIME_MS
)
999 timepos
.wType
= TIME_BYTES
;
1001 /* This can change timepos.wType if the requested type is not supported */
1002 val
= waveInGetPosition(wim
->u
.in
.hInnerWave
, &timepos
, dwParam2
);
1004 if (timepos
.wType
== TIME_BYTES
)
1006 DWORD dwInnerSamplesPerOuter
= wim
->nSamplesPerSecInner
/ wim
->nSamplesPerSecOuter
;
1007 if (dwInnerSamplesPerOuter
> 0)
1009 DWORD dwInnerBytesPerSample
= wim
->avgSpeedInner
/ wim
->nSamplesPerSecInner
;
1010 DWORD dwInnerBytesPerOuterSample
= dwInnerBytesPerSample
* dwInnerSamplesPerOuter
;
1011 DWORD remainder
= 0;
1013 /* If we are up sampling (going from lower sample rate to higher),
1014 ** we need to make a special accommodation for times when we've
1015 ** written a partial output sample. This happens frequently
1016 ** to us because we use msacm to do our up sampling, and it
1017 ** will up sample on an unaligned basis.
1018 ** For example, if you convert a 2 byte wide 8,000 'outer'
1019 ** buffer to a 2 byte wide 48,000 inner device, you would
1020 ** expect 2 bytes of input to produce 12 bytes of output.
1021 ** Instead, msacm will produce 8 bytes of output.
1022 ** But reporting our position as 1 byte of output is
1023 ** nonsensical; the output buffer position needs to be
1024 ** aligned on outer sample size, and aggressively rounded up.
1026 remainder
= timepos
.u
.cb
% dwInnerBytesPerOuterSample
;
1029 timepos
.u
.cb
-= remainder
;
1030 timepos
.u
.cb
+= dwInnerBytesPerOuterSample
;
1034 lpTime
->u
.cb
= MulDiv(timepos
.u
.cb
, wim
->avgSpeedOuter
, wim
->avgSpeedInner
);
1036 /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
1037 if (lpTime
->wType
== TIME_MS
)
1038 lpTime
->u
.ms
= MulDiv(lpTime
->u
.cb
, 1000, wim
->avgSpeedOuter
);
1040 lpTime
->wType
= TIME_BYTES
;
1042 else if (lpTime
->wType
== TIME_SAMPLES
&& timepos
.wType
== TIME_SAMPLES
)
1043 lpTime
->u
.sample
= MulDiv(timepos
.u
.sample
, wim
->nSamplesPerSecOuter
, wim
->nSamplesPerSecInner
);
1045 /* other time types don't require conversion */
1046 lpTime
->u
= timepos
.u
;
1051 static DWORD
widGetDevCaps(UINT wDevID
, WAVEMAPDATA
* wim
, LPWAVEINCAPSW lpWaveCaps
, DWORD dwParam2
)
1053 TRACE("(%04x, %p %p %08x)\n", wDevID
, wim
, lpWaveCaps
, dwParam2
);
1055 /* if opened low driver, forward message */
1056 if (WAVEMAP_IsData(wim
))
1057 return waveInGetDevCapsW((UINT_PTR
)wim
->u
.in
.hInnerWave
, lpWaveCaps
, dwParam2
);
1058 /* else if no drivers, nothing to map so return bad device */
1059 if (waveInGetNumDevs() == 0) {
1060 WARN("bad device id\n");
1061 return MMSYSERR_BADDEVICEID
;
1063 /* otherwise, return caps of mapper itself */
1064 if (wDevID
== (UINT
)-1 || wDevID
== (UINT16
)-1) {
1066 static const WCHAR init
[] = {'W','i','n','e',' ','w','a','v','e',' ','i','n',' ','m','a','p','p','e','r',0};
1069 wic
.vDriverVersion
= 0x0001;
1070 strcpyW(wic
.szPname
, init
);
1072 WAVE_FORMAT_96M08
| WAVE_FORMAT_96S08
| WAVE_FORMAT_96M16
| WAVE_FORMAT_96S16
|
1073 WAVE_FORMAT_48M08
| WAVE_FORMAT_48S08
| WAVE_FORMAT_48M16
| WAVE_FORMAT_48S16
|
1074 WAVE_FORMAT_4M08
| WAVE_FORMAT_4S08
| WAVE_FORMAT_4M16
| WAVE_FORMAT_4S16
|
1075 WAVE_FORMAT_2M08
| WAVE_FORMAT_2S08
| WAVE_FORMAT_2M16
| WAVE_FORMAT_2S16
|
1076 WAVE_FORMAT_1M08
| WAVE_FORMAT_1S08
| WAVE_FORMAT_1M16
| WAVE_FORMAT_1S16
;
1078 memcpy(lpWaveCaps
, &wic
, min(dwParam2
, sizeof(wic
)));
1080 return MMSYSERR_NOERROR
;
1082 ERR("This shouldn't happen\n");
1083 return MMSYSERR_ERROR
;
1086 static DWORD
widStop(WAVEMAPDATA
* wim
)
1088 TRACE("(%p)\n", wim
);
1090 return waveInStop(wim
->u
.in
.hInnerWave
);
1093 static DWORD
widStart(WAVEMAPDATA
* wim
)
1095 TRACE("(%p)\n", wim
);
1097 return waveInStart(wim
->u
.in
.hInnerWave
);
1100 static DWORD
widReset(WAVEMAPDATA
* wim
)
1102 TRACE("(%p)\n", wim
);
1104 return waveInReset(wim
->u
.in
.hInnerWave
);
1107 static DWORD
widMapperStatus(WAVEMAPDATA
* wim
, DWORD flags
, LPVOID ptr
)
1110 DWORD ret
= MMSYSERR_NOTSUPPORTED
;
1112 TRACE("(%p %08x %p)\n", wim
, flags
, ptr
);
1115 case WAVEIN_MAPPER_STATUS_DEVICE
:
1116 ret
= waveInGetID(wim
->u
.in
.hInnerWave
, &id
);
1119 case WAVEIN_MAPPER_STATUS_MAPPED
:
1120 FIXME("Unsupported yet flag=%d\n", flags
);
1121 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
1123 case WAVEIN_MAPPER_STATUS_FORMAT
:
1124 FIXME("Unsupported flag=%d\n", flags
);
1125 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
1126 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
1129 FIXME("Unsupported flag=%d\n", flags
);
1136 static DWORD
widMapperReconfigure(WAVEMAPDATA
* wim
, DWORD dwParam1
, DWORD dwParam2
)
1138 FIXME("(%p %08x %08x) stub!\n", wim
, dwParam1
, dwParam2
);
1140 return MMSYSERR_NOERROR
;
1143 /**************************************************************************
1144 * widMessage (MSACM.@)
1146 DWORD WINAPI
WAVEMAP_widMessage(WORD wDevID
, WORD wMsg
, DWORD_PTR dwUser
,
1147 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
1149 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1150 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1157 /* FIXME: Pretend this is supported */
1160 case WIDM_OPEN
: return widOpen ((DWORD_PTR
*)dwUser
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
1161 case WIDM_CLOSE
: return widClose ((WAVEMAPDATA
*)dwUser
);
1163 case WIDM_ADDBUFFER
: return widAddBuffer ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1164 case WIDM_PREPARE
: return widPrepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1165 case WIDM_UNPREPARE
: return widUnprepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1166 case WIDM_GETDEVCAPS
: return widGetDevCaps (wDevID
, (WAVEMAPDATA
*)dwUser
, (LPWAVEINCAPSW
)dwParam1
, dwParam2
);
1167 case WIDM_GETNUMDEVS
: return 1;
1168 case WIDM_GETPOS
: return widGetPosition ((WAVEMAPDATA
*)dwUser
, (LPMMTIME
)dwParam1
, dwParam2
);
1169 case WIDM_RESET
: return widReset ((WAVEMAPDATA
*)dwUser
);
1170 case WIDM_START
: return widStart ((WAVEMAPDATA
*)dwUser
);
1171 case WIDM_STOP
: return widStop ((WAVEMAPDATA
*)dwUser
);
1172 case WIDM_MAPPER_STATUS
: return widMapperStatus ((WAVEMAPDATA
*)dwUser
, dwParam1
, (LPVOID
)dwParam2
);
1173 case DRVM_MAPPER_RECONFIGURE
: return widMapperReconfigure((WAVEMAPDATA
*)dwUser
, dwParam1
, dwParam2
);
1174 /* known but not supported */
1175 case DRV_QUERYDEVICEINTERFACESIZE
:
1176 case DRV_QUERYDEVICEINTERFACE
:
1177 return MMSYSERR_NOTSUPPORTED
;
1179 FIXME("unknown message %u!\n", wMsg
);
1181 return MMSYSERR_NOTSUPPORTED
;
1184 /*======================================================================*
1186 *======================================================================*/
1188 static struct WINE_WAVEMAP
* oss
= NULL
;
1190 /**************************************************************************
1191 * WAVEMAP_drvOpen [internal]
1193 static LRESULT
WAVEMAP_drvOpen(LPSTR str
)
1195 TRACE("(%p)\n", str
);
1200 /* I know, this is ugly, but who cares... */
1201 oss
= (struct WINE_WAVEMAP
*)1;
1205 /**************************************************************************
1206 * WAVEMAP_drvClose [internal]
1208 static LRESULT
WAVEMAP_drvClose(DWORD_PTR dwDevID
)
1210 TRACE("(%08lx)\n", dwDevID
);
1219 /**************************************************************************
1220 * DriverProc (MSACM.@)
1222 LRESULT CALLBACK
WAVEMAP_DriverProc(DWORD_PTR dwDevID
, HDRVR hDriv
, UINT wMsg
,
1223 LPARAM dwParam1
, LPARAM dwParam2
)
1225 TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
1226 dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1229 case DRV_LOAD
: return 1;
1230 case DRV_FREE
: return 1;
1231 case DRV_OPEN
: return WAVEMAP_drvOpen((LPSTR
)dwParam1
);
1232 case DRV_CLOSE
: return WAVEMAP_drvClose(dwDevID
);
1233 case DRV_ENABLE
: return 1;
1234 case DRV_DISABLE
: return 1;
1235 case DRV_QUERYCONFIGURE
: return 1;
1236 case DRV_CONFIGURE
: MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK
); return 1;
1237 case DRV_INSTALL
: return DRVCNF_RESTART
;
1238 case DRV_REMOVE
: return DRVCNF_RESTART
;
1240 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);