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...
31 #define WIN32_NO_STATUS
36 //#include "winbase.h"
42 #include <wine/unicode.h>
43 #include <wine/debug.h>
45 WINE_DEFAULT_DEBUG_CHANNEL(wavemap
);
47 typedef struct tagWAVEMAPDATA
{
48 struct tagWAVEMAPDATA
* self
;
59 HACMSTREAM hAcmStream
;
60 /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */
62 DWORD_PTR dwClientInstance
;
64 /* ratio to compute position from a PCM playback to any format */
67 /* channel size of inner and outer */
68 DWORD nSamplesPerSecOuter
;
69 DWORD nSamplesPerSecInner
;
72 static BOOL
WAVEMAP_IsData(const WAVEMAPDATA
* wm
)
74 return (!IsBadReadPtr(wm
, sizeof(WAVEMAPDATA
)) && wm
->self
== wm
);
77 /*======================================================================*
79 *======================================================================*/
81 static void CALLBACK
wodCallback(HWAVEOUT hWave
, UINT uMsg
, DWORD_PTR dwInstance
,
82 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
84 WAVEMAPDATA
* wom
= (WAVEMAPDATA
*)dwInstance
;
86 TRACE("(%p %u %ld %lx %lx);\n", hWave
, uMsg
, dwInstance
, dwParam1
, dwParam2
);
88 if (!WAVEMAP_IsData(wom
)) {
93 if (uMsg
!= WOM_OPEN
&& hWave
!= wom
->u
.out
.hInnerWave
)
94 ERR("Shouldn't happen (%p %p)\n", hWave
, wom
->u
.out
.hInnerWave
);
99 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
102 if (wom
->hAcmStream
) {
103 LPWAVEHDR lpWaveHdrDst
= (LPWAVEHDR
)dwParam1
;
104 PACMSTREAMHEADER ash
= (PACMSTREAMHEADER
)((LPSTR
)lpWaveHdrDst
- sizeof(ACMSTREAMHEADER
));
105 LPWAVEHDR lpWaveHdrSrc
= (LPWAVEHDR
)ash
->dwUser
;
107 lpWaveHdrSrc
->dwFlags
&= ~WHDR_INQUEUE
;
108 lpWaveHdrSrc
->dwFlags
|= WHDR_DONE
;
109 dwParam1
= (DWORD_PTR
)lpWaveHdrSrc
;
113 ERR("Unknown msg %u\n", uMsg
);
116 DriverCallback(wom
->dwCallback
, HIWORD(wom
->dwFlags
), (HDRVR
)wom
->u
.out
.hOuterWave
,
117 uMsg
, wom
->dwClientInstance
, dwParam1
, dwParam2
);
120 /******************************************************************
125 static DWORD
wodOpenHelper(WAVEMAPDATA
* wom
, UINT idx
,
126 LPWAVEOPENDESC lpDesc
, LPWAVEFORMATEX lpwfx
,
131 TRACE("(%p %04x %p %p %08x)\n", wom
, idx
, lpDesc
, lpwfx
, dwFlags
);
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
);
139 ret
= acmStreamOpen(&wom
->hAcmStream
, 0, lpDesc
->lpFormat
, lpwfx
, NULL
, 0L, 0L, 0L);
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);
150 TRACE("ret = %08x\n", ret
);
154 static DWORD
wodOpen(DWORD_PTR
*lpdwUser
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
158 WAVEMAPDATA
* wom
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA
));
161 TRACE("(%p %p %08x)\n", lpdwUser
, lpDesc
, dwFlags
);
165 return MMSYSERR_NOMEM
;
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
;
175 ndlo
= lpDesc
->uMappedDeviceID
;
177 dwFlags
&= ~WAVE_MAPPED
;
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
;
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
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
) {
201 if ((dwFlags
& WAVE_FORMAT_DIRECT
) == 0) {
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 */
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; \
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
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);
226 /* Our resampling algorithm is quite primitive so first try
227 * to just change the bit depth and number of channels
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);
235 TRY(wfx
.nSamplesPerSec
, 16);
236 TRY(wfx
.nSamplesPerSec
, 8);
239 for (i
= ndlo
; i
< ndhi
; i
++) {
240 /* first try with same stereo/mono option as source */
241 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
248 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
256 /* first try with same stereo/mono option as source */
257 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
264 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
276 HeapFree(GetProcessHeap(), 0, wom
);
277 WARN("ret = WAVERR_BADFORMAT\n");
278 return WAVERR_BADFORMAT
;
281 if (dwFlags
& WAVE_FORMAT_QUERY
) {
283 HeapFree(GetProcessHeap(), 0, wom
);
285 *lpdwUser
= (DWORD_PTR
)wom
;
287 return MMSYSERR_NOERROR
;
289 HeapFree(GetProcessHeap(), 0, wom
);
290 if (res
==ACMERR_NOTPOSSIBLE
) {
291 WARN("ret = WAVERR_BADFORMAT\n");
292 return WAVERR_BADFORMAT
;
294 WARN("ret = 0x%08x\n", res
);
298 static DWORD
wodClose(WAVEMAPDATA
* wom
)
302 TRACE("(%p)\n", wom
);
304 ret
= waveOutClose(wom
->u
.out
.hInnerWave
);
305 if (ret
== MMSYSERR_NOERROR
) {
306 if (wom
->hAcmStream
) {
307 ret
= acmStreamClose(wom
->hAcmStream
, 0);
309 if (ret
== MMSYSERR_NOERROR
) {
310 HeapFree(GetProcessHeap(), 0, wom
);
316 static DWORD
wodWrite(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
318 PACMSTREAMHEADER ash
;
319 LPWAVEHDR lpWaveHdrDst
;
321 TRACE("(%p %p %08x)\n", wom
, lpWaveHdrSrc
, dwParam2
);
323 if (!wom
->hAcmStream
) {
324 return waveOutWrite(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
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
;
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");
342 if (ash
->cbDstLengthUsed
== 0) {
343 /* something went wrong in decoding */
344 FIXME("Got 0 length\n");
345 return MMSYSERR_ERROR
;
347 lpWaveHdrDst
->dwBufferLength
= ash
->cbDstLengthUsed
;
348 return waveOutWrite(wom
->u
.out
.hInnerWave
, lpWaveHdrDst
, sizeof(*lpWaveHdrDst
));
351 static DWORD
wodPrepare(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
353 PACMSTREAMHEADER ash
;
356 LPWAVEHDR lpWaveHdrDst
;
358 TRACE("(%p %p %08x)\n", wom
, lpWaveHdrSrc
, dwParam2
);
360 if (!wom
->hAcmStream
)
361 return waveOutPrepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
363 if (acmStreamSize(wom
->hAcmStream
, lpWaveHdrSrc
->dwBufferLength
, &size
, ACM_STREAMSIZEF_SOURCE
) != MMSYSERR_NOERROR
) {
364 WARN("acmStreamSize failed\n");
365 return MMSYSERR_ERROR
;
368 ash
= HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
) + size
);
371 return MMSYSERR_NOMEM
;
374 ash
->cbStruct
= sizeof(*ash
);
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");
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");
402 lpWaveHdrSrc
->reserved
= (DWORD_PTR
)ash
;
403 lpWaveHdrSrc
->dwFlags
= WHDR_PREPARED
;
405 return MMSYSERR_NOERROR
;
407 TRACE("=> (%d)\n", dwRet
);
408 HeapFree(GetProcessHeap(), 0, ash
);
412 static DWORD
wodUnprepare(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
414 PACMSTREAMHEADER ash
;
415 LPWAVEHDR lpWaveHdrDst
;
416 DWORD dwRet1
, dwRet2
;
418 TRACE("(%p %p %08x)\n", wom
, lpWaveHdrSrc
, dwParam2
);
420 if (!wom
->hAcmStream
) {
421 return waveOutUnprepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
423 ash
= (PACMSTREAMHEADER
)lpWaveHdrSrc
->reserved
;
424 dwRet1
= acmStreamUnprepareHeader(wom
->hAcmStream
, ash
, 0L);
426 lpWaveHdrDst
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
427 dwRet2
= waveOutUnprepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrDst
, sizeof(*lpWaveHdrDst
));
429 HeapFree(GetProcessHeap(), 0, ash
);
431 lpWaveHdrSrc
->dwFlags
&= ~WHDR_PREPARED
;
432 return (dwRet1
== MMSYSERR_NOERROR
) ? dwRet2
: dwRet1
;
435 static DWORD
wodGetPosition(WAVEMAPDATA
* wom
, LPMMTIME lpTime
, DWORD dwParam2
)
439 TRACE("(%p %p %08x)\n", wom
, lpTime
, dwParam2
);
443 /* For TIME_MS, we're going to recalculate using TIME_BYTES */
444 if (lpTime
->wType
== TIME_MS
)
445 timepos
.wType
= TIME_BYTES
;
447 /* This can change timepos.wType if the requested type is not supported */
448 val
= waveOutGetPosition(wom
->u
.out
.hInnerWave
, &timepos
, dwParam2
);
450 if (timepos
.wType
== TIME_BYTES
)
452 DWORD dwInnerSamplesPerOuter
= wom
->nSamplesPerSecInner
/ wom
->nSamplesPerSecOuter
;
453 if (dwInnerSamplesPerOuter
> 0)
455 DWORD dwInnerBytesPerSample
= wom
->avgSpeedInner
/ wom
->nSamplesPerSecInner
;
456 DWORD dwInnerBytesPerOuterSample
= dwInnerBytesPerSample
* dwInnerSamplesPerOuter
;
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.
472 remainder
= timepos
.u
.cb
% dwInnerBytesPerOuterSample
;
475 timepos
.u
.cb
-= remainder
;
476 timepos
.u
.cb
+= dwInnerBytesPerOuterSample
;
480 lpTime
->u
.cb
= MulDiv(timepos
.u
.cb
, wom
->avgSpeedOuter
, wom
->avgSpeedInner
);
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
);
486 lpTime
->wType
= TIME_BYTES
;
488 else if (lpTime
->wType
== TIME_SAMPLES
&& timepos
.wType
== TIME_SAMPLES
)
489 lpTime
->u
.sample
= MulDiv(timepos
.u
.sample
, wom
->nSamplesPerSecOuter
, wom
->nSamplesPerSecInner
);
491 /* other time types don't require conversion */
492 lpTime
->u
= timepos
.u
;
497 static DWORD
wodGetDevCaps(UINT wDevID
, WAVEMAPDATA
* wom
, LPWAVEOUTCAPSW lpWaveCaps
, DWORD dwParam2
)
499 static const WCHAR name
[] = {'W','i','n','e',' ','w','a','v','e',' ','o','u','t',' ','m','a','p','p','e','r',0};
501 TRACE("(%04x %p %p %08x)\n",wDevID
, wom
, lpWaveCaps
, dwParam2
);
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
;
511 /* otherwise, return caps of mapper itself */
512 if (wDevID
== (UINT
)-1 || wDevID
== (UINT16
)-1) {
516 woc
.vDriverVersion
= 0x0332;
517 lstrcpyW(woc
.szPname
, name
);
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
;
526 woc
.dwSupport
= WAVECAPS_VOLUME
| WAVECAPS_LRVOLUME
;
527 memcpy(lpWaveCaps
, &woc
, min(dwParam2
, sizeof(woc
)));
529 return MMSYSERR_NOERROR
;
531 ERR("This shouldn't happen\n");
532 return MMSYSERR_ERROR
;
535 static DWORD
wodGetVolume(UINT wDevID
, WAVEMAPDATA
* wom
, LPDWORD lpVol
)
537 TRACE("(%04x %p %p)\n",wDevID
, wom
, lpVol
);
539 if (WAVEMAP_IsData(wom
))
540 return waveOutGetVolume(wom
->u
.out
.hInnerWave
, lpVol
);
541 return MMSYSERR_NOERROR
;
544 static DWORD
wodSetVolume(UINT wDevID
, WAVEMAPDATA
* wom
, DWORD vol
)
546 TRACE("(%04x %p %08x)\n",wDevID
, wom
, vol
);
548 if (WAVEMAP_IsData(wom
))
549 return waveOutSetVolume(wom
->u
.out
.hInnerWave
, vol
);
550 return MMSYSERR_NOERROR
;
553 static DWORD
wodPause(WAVEMAPDATA
* wom
)
557 return waveOutPause(wom
->u
.out
.hInnerWave
);
560 static DWORD
wodRestart(WAVEMAPDATA
* wom
)
564 return waveOutRestart(wom
->u
.out
.hInnerWave
);
567 static DWORD
wodReset(WAVEMAPDATA
* wom
)
571 return waveOutReset(wom
->u
.out
.hInnerWave
);
574 static DWORD
wodBreakLoop(WAVEMAPDATA
* wom
)
578 return waveOutBreakLoop(wom
->u
.out
.hInnerWave
);
581 static DWORD
wodMapperStatus(WAVEMAPDATA
* wom
, DWORD flags
, LPVOID ptr
)
584 DWORD ret
= MMSYSERR_NOTSUPPORTED
;
586 TRACE("(%p %08x %p)\n",wom
, flags
, ptr
);
589 case WAVEOUT_MAPPER_STATUS_DEVICE
:
590 ret
= waveOutGetID(wom
->u
.out
.hInnerWave
, &id
);
593 case WAVEOUT_MAPPER_STATUS_MAPPED
:
594 FIXME("Unsupported flag=%d\n", flags
);
595 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
597 case WAVEOUT_MAPPER_STATUS_FORMAT
:
598 FIXME("Unsupported flag=%d\n", flags
);
599 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
603 FIXME("Unsupported flag=%d\n", flags
);
610 static DWORD
wodMapperReconfigure(WAVEMAPDATA
* wom
, DWORD dwParam1
, DWORD dwParam2
)
612 FIXME("(%p %08x %08x) stub!\n", wom
, dwParam1
, dwParam2
);
614 return MMSYSERR_NOERROR
;
617 /**************************************************************************
618 * wodMessage (MSACM.@)
620 DWORD WINAPI
WAVEMAP_wodMessage(UINT wDevID
, UINT wMsg
, DWORD_PTR dwUser
,
621 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
623 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
624 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
631 /* FIXME: Pretend this is supported */
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
;
658 FIXME("unknown message %d!\n", wMsg
);
660 return MMSYSERR_NOTSUPPORTED
;
663 /*======================================================================*
665 *======================================================================*/
667 static void CALLBACK
widCallback(HWAVEIN hWave
, UINT uMsg
, DWORD_PTR dwInstance
,
668 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
670 WAVEMAPDATA
* wim
= (WAVEMAPDATA
*)dwInstance
;
672 TRACE("(%p %u %lx %lx %lx);\n", hWave
, uMsg
, dwInstance
, dwParam1
, dwParam2
);
674 if (!WAVEMAP_IsData(wim
)) {
679 if (uMsg
!= WIM_OPEN
&& hWave
!= wim
->u
.in
.hInnerWave
)
680 ERR("Shouldn't happen (%p %p)\n", hWave
, wim
->u
.in
.hInnerWave
);
685 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
688 if (wim
->hAcmStream
) {
689 LPWAVEHDR lpWaveHdrSrc
= (LPWAVEHDR
)dwParam1
;
690 PACMSTREAMHEADER ash
= (PACMSTREAMHEADER
)((LPSTR
)lpWaveHdrSrc
- sizeof(ACMSTREAMHEADER
));
691 LPWAVEHDR lpWaveHdrDst
= (LPWAVEHDR
)ash
->dwUser
;
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");
698 TRACE("Converted %d bytes into %d\n", ash
->cbSrcLengthUsed
, ash
->cbDstLengthUsed
);
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
;
708 ERR("Unknown msg %u\n", uMsg
);
711 DriverCallback(wim
->dwCallback
, HIWORD(wim
->dwFlags
), (HDRVR
)wim
->u
.in
.hOuterWave
,
712 uMsg
, wim
->dwClientInstance
, dwParam1
, dwParam2
);
715 static DWORD
widOpenHelper(WAVEMAPDATA
* wim
, UINT idx
,
716 LPWAVEOPENDESC lpDesc
, LPWAVEFORMATEX lpwfx
,
721 TRACE("(%p %04x %p %p %08x)\n", wim
, idx
, lpDesc
, lpwfx
, dwFlags
);
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
);
729 ret
= acmStreamOpen(&wim
->hAcmStream
, 0, lpwfx
, lpDesc
->lpFormat
, NULL
, 0L, 0L, 0L);
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);
740 TRACE("ret = %08x\n", ret
);
744 static DWORD
widOpen(DWORD_PTR
*lpdwUser
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
748 WAVEMAPDATA
* wim
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA
));
751 TRACE("(%p %p %08x)\n", lpdwUser
, lpDesc
, dwFlags
);
755 return MMSYSERR_NOMEM
;
759 wim
->dwCallback
= lpDesc
->dwCallback
;
760 wim
->dwFlags
= dwFlags
;
761 wim
->dwClientInstance
= lpDesc
->dwInstance
;
762 wim
->u
.in
.hOuterWave
= (HWAVEIN
)lpDesc
->hWave
;
764 ndhi
= waveInGetNumDevs();
765 if (dwFlags
& WAVE_MAPPED
) {
766 if (lpDesc
->uMappedDeviceID
>= ndhi
) return MMSYSERR_INVALPARAM
;
767 ndlo
= lpDesc
->uMappedDeviceID
;
769 dwFlags
&= ~WAVE_MAPPED
;
774 wim
->avgSpeedOuter
= wim
->avgSpeedInner
= lpDesc
->lpFormat
->nAvgBytesPerSec
;
775 wim
->nSamplesPerSecOuter
= wim
->nSamplesPerSecInner
= lpDesc
->lpFormat
->nSamplesPerSec
;
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
) {
786 if ((dwFlags
& WAVE_FORMAT_DIRECT
) == 0)
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 */
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; \
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);
808 TRY(wfx
.nSamplesPerSec
, 16);
809 TRY(wfx
.nSamplesPerSec
, 8);
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
;
822 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
830 /* first try with same stereo/mono option as source */
831 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
838 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
849 HeapFree(GetProcessHeap(), 0, wim
);
850 WARN("ret = WAVERR_BADFORMAT\n");
851 return WAVERR_BADFORMAT
;
853 if (dwFlags
& WAVE_FORMAT_QUERY
) {
855 HeapFree(GetProcessHeap(), 0, wim
);
857 *lpdwUser
= (DWORD_PTR
)wim
;
858 TRACE("Ok (stream=%p)\n", wim
->hAcmStream
);
860 return MMSYSERR_NOERROR
;
862 HeapFree(GetProcessHeap(), 0, wim
);
863 if (res
==ACMERR_NOTPOSSIBLE
) {
864 WARN("ret = WAVERR_BADFORMAT\n");
865 return WAVERR_BADFORMAT
;
867 WARN("ret = 0x%08x\n", res
);
871 static DWORD
widClose(WAVEMAPDATA
* wim
)
875 TRACE("(%p)\n", wim
);
877 ret
= waveInClose(wim
->u
.in
.hInnerWave
);
878 if (ret
== MMSYSERR_NOERROR
) {
879 if (wim
->hAcmStream
) {
880 ret
= acmStreamClose(wim
->hAcmStream
, 0);
882 if (ret
== MMSYSERR_NOERROR
) {
883 HeapFree(GetProcessHeap(), 0, wim
);
889 static DWORD
widAddBuffer(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
891 PACMSTREAMHEADER ash
;
892 LPWAVEHDR lpWaveHdrSrc
;
894 TRACE("(%p %p %08x)\n", wim
, lpWaveHdrDst
, dwParam2
);
896 if (!wim
->hAcmStream
) {
897 return waveInAddBuffer(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
900 lpWaveHdrDst
->dwFlags
|= WHDR_INQUEUE
;
901 ash
= (PACMSTREAMHEADER
)lpWaveHdrDst
->reserved
;
903 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
904 return waveInAddBuffer(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
907 static DWORD
widPrepare(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
909 PACMSTREAMHEADER ash
;
912 LPWAVEHDR lpWaveHdrSrc
;
914 TRACE("(%p %p %08x)\n", wim
, lpWaveHdrDst
, dwParam2
);
916 if (!wim
->hAcmStream
) {
917 return waveInPrepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
919 if (acmStreamSize(wim
->hAcmStream
, lpWaveHdrDst
->dwBufferLength
, &size
,
920 ACM_STREAMSIZEF_DESTINATION
) != MMSYSERR_NOERROR
) {
921 WARN("acmStreamSize failed\n");
922 return MMSYSERR_ERROR
;
925 ash
= HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
) + size
);
928 return MMSYSERR_NOMEM
;
931 ash
->cbStruct
= sizeof(*ash
);
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");
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");
959 lpWaveHdrDst
->reserved
= (DWORD_PTR
)ash
;
960 lpWaveHdrDst
->dwFlags
= WHDR_PREPARED
;
962 return MMSYSERR_NOERROR
;
964 TRACE("=> (%d)\n", dwRet
);
965 HeapFree(GetProcessHeap(), 0, ash
);
969 static DWORD
widUnprepare(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
971 PACMSTREAMHEADER ash
;
972 LPWAVEHDR lpWaveHdrSrc
;
973 DWORD dwRet1
, dwRet2
;
975 TRACE("(%p %p %08x)\n", wim
, lpWaveHdrDst
, dwParam2
);
977 if (!wim
->hAcmStream
) {
978 return waveInUnprepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
980 ash
= (PACMSTREAMHEADER
)lpWaveHdrDst
->reserved
;
981 dwRet1
= acmStreamUnprepareHeader(wim
->hAcmStream
, ash
, 0L);
983 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
984 dwRet2
= waveInUnprepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
986 HeapFree(GetProcessHeap(), 0, ash
);
988 lpWaveHdrDst
->dwFlags
&= ~WHDR_PREPARED
;
989 return (dwRet1
== MMSYSERR_NOERROR
) ? dwRet2
: dwRet1
;
992 static DWORD
widGetPosition(WAVEMAPDATA
* wim
, LPMMTIME lpTime
, DWORD dwParam2
)
996 TRACE("(%p %p %08x)\n", wim
, lpTime
, dwParam2
);
1000 /* For TIME_MS, we're going to recalculate using TIME_BYTES */
1001 if (lpTime
->wType
== TIME_MS
)
1002 timepos
.wType
= TIME_BYTES
;
1004 /* This can change timepos.wType if the requested type is not supported */
1005 val
= waveInGetPosition(wim
->u
.in
.hInnerWave
, &timepos
, dwParam2
);
1007 if (timepos
.wType
== TIME_BYTES
)
1009 DWORD dwInnerSamplesPerOuter
= wim
->nSamplesPerSecInner
/ wim
->nSamplesPerSecOuter
;
1010 if (dwInnerSamplesPerOuter
> 0)
1012 DWORD dwInnerBytesPerSample
= wim
->avgSpeedInner
/ wim
->nSamplesPerSecInner
;
1013 DWORD dwInnerBytesPerOuterSample
= dwInnerBytesPerSample
* dwInnerSamplesPerOuter
;
1014 DWORD remainder
= 0;
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.
1029 remainder
= timepos
.u
.cb
% dwInnerBytesPerOuterSample
;
1032 timepos
.u
.cb
-= remainder
;
1033 timepos
.u
.cb
+= dwInnerBytesPerOuterSample
;
1037 lpTime
->u
.cb
= MulDiv(timepos
.u
.cb
, wim
->avgSpeedOuter
, wim
->avgSpeedInner
);
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
);
1043 lpTime
->wType
= TIME_BYTES
;
1045 else if (lpTime
->wType
== TIME_SAMPLES
&& timepos
.wType
== TIME_SAMPLES
)
1046 lpTime
->u
.sample
= MulDiv(timepos
.u
.sample
, wim
->nSamplesPerSecOuter
, wim
->nSamplesPerSecInner
);
1048 /* other time types don't require conversion */
1049 lpTime
->u
= timepos
.u
;
1054 static DWORD
widGetDevCaps(UINT wDevID
, WAVEMAPDATA
* wim
, LPWAVEINCAPSW lpWaveCaps
, DWORD dwParam2
)
1056 TRACE("(%04x, %p %p %08x)\n", wDevID
, wim
, lpWaveCaps
, dwParam2
);
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
;
1066 /* otherwise, return caps of mapper itself */
1067 if (wDevID
== (UINT
)-1 || wDevID
== (UINT16
)-1) {
1069 static const WCHAR init
[] = {'W','i','n','e',' ','w','a','v','e',' ','i','n',' ','m','a','p','p','e','r',0};
1072 wic
.vDriverVersion
= 0x0001;
1073 strcpyW(wic
.szPname
, init
);
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
;
1082 memcpy(lpWaveCaps
, &wic
, min(dwParam2
, sizeof(wic
)));
1084 return MMSYSERR_NOERROR
;
1086 ERR("This shouldn't happen\n");
1087 return MMSYSERR_ERROR
;
1090 static DWORD
widStop(WAVEMAPDATA
* wim
)
1092 TRACE("(%p)\n", wim
);
1094 return waveInStop(wim
->u
.in
.hInnerWave
);
1097 static DWORD
widStart(WAVEMAPDATA
* wim
)
1099 TRACE("(%p)\n", wim
);
1101 return waveInStart(wim
->u
.in
.hInnerWave
);
1104 static DWORD
widReset(WAVEMAPDATA
* wim
)
1106 TRACE("(%p)\n", wim
);
1108 return waveInReset(wim
->u
.in
.hInnerWave
);
1111 static DWORD
widMapperStatus(WAVEMAPDATA
* wim
, DWORD flags
, LPVOID ptr
)
1114 DWORD ret
= MMSYSERR_NOTSUPPORTED
;
1116 TRACE("(%p %08x %p)\n", wim
, flags
, ptr
);
1119 case WAVEIN_MAPPER_STATUS_DEVICE
:
1120 ret
= waveInGetID(wim
->u
.in
.hInnerWave
, &id
);
1123 case WAVEIN_MAPPER_STATUS_MAPPED
:
1124 FIXME("Unsupported yet flag=%d\n", flags
);
1125 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
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 ?? */
1133 FIXME("Unsupported flag=%d\n", flags
);
1140 static DWORD
widMapperReconfigure(WAVEMAPDATA
* wim
, DWORD dwParam1
, DWORD dwParam2
)
1142 FIXME("(%p %08x %08x) stub!\n", wim
, dwParam1
, dwParam2
);
1144 return MMSYSERR_NOERROR
;
1147 /**************************************************************************
1148 * widMessage (MSACM.@)
1150 DWORD WINAPI
WAVEMAP_widMessage(WORD wDevID
, WORD wMsg
, DWORD_PTR dwUser
,
1151 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
1153 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1154 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1161 /* FIXME: Pretend this is supported */
1164 case WIDM_OPEN
: return widOpen ((DWORD_PTR
*)dwUser
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
1165 case WIDM_CLOSE
: return widClose ((WAVEMAPDATA
*)dwUser
);
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
;
1183 FIXME("unknown message %u!\n", wMsg
);
1185 return MMSYSERR_NOTSUPPORTED
;
1188 /*======================================================================*
1190 *======================================================================*/
1192 static struct WINE_WAVEMAP
* oss
= NULL
;
1194 /**************************************************************************
1195 * WAVEMAP_drvOpen [internal]
1197 static LRESULT
WAVEMAP_drvOpen(LPSTR str
)
1199 TRACE("(%p)\n", str
);
1204 /* I know, this is ugly, but who cares... */
1205 oss
= (struct WINE_WAVEMAP
*)1;
1209 /**************************************************************************
1210 * WAVEMAP_drvClose [internal]
1212 static LRESULT
WAVEMAP_drvClose(DWORD_PTR dwDevID
)
1214 TRACE("(%08lx)\n", dwDevID
);
1223 /**************************************************************************
1224 * DriverProc (MSACM.@)
1226 LRESULT CALLBACK
WAVEMAP_DriverProc(DWORD_PTR dwDevID
, HDRVR hDriv
, UINT wMsg
,
1227 LPARAM dwParam1
, LPARAM dwParam2
)
1229 TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
1230 dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
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
;
1244 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);