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
;
525 woc
.dwSupport
= WAVECAPS_VOLUME
| WAVECAPS_LRVOLUME
;
526 memcpy(lpWaveCaps
, &woc
, min(dwParam2
, sizeof(woc
)));
528 return MMSYSERR_NOERROR
;
530 ERR("This shouldn't happen\n");
531 return MMSYSERR_ERROR
;
534 static DWORD
wodGetVolume(UINT wDevID
, WAVEMAPDATA
* wom
, LPDWORD lpVol
)
536 TRACE("(%04x %p %p)\n",wDevID
, wom
, lpVol
);
538 if (WAVEMAP_IsData(wom
))
539 return waveOutGetVolume(wom
->u
.out
.hInnerWave
, lpVol
);
540 return MMSYSERR_NOERROR
;
543 static DWORD
wodSetVolume(UINT wDevID
, WAVEMAPDATA
* wom
, DWORD vol
)
545 TRACE("(%04x %p %08x)\n",wDevID
, wom
, vol
);
547 if (WAVEMAP_IsData(wom
))
548 return waveOutSetVolume(wom
->u
.out
.hInnerWave
, vol
);
549 return MMSYSERR_NOERROR
;
552 static DWORD
wodPause(WAVEMAPDATA
* wom
)
556 return waveOutPause(wom
->u
.out
.hInnerWave
);
559 static DWORD
wodRestart(WAVEMAPDATA
* wom
)
563 return waveOutRestart(wom
->u
.out
.hInnerWave
);
566 static DWORD
wodReset(WAVEMAPDATA
* wom
)
570 return waveOutReset(wom
->u
.out
.hInnerWave
);
573 static DWORD
wodBreakLoop(WAVEMAPDATA
* wom
)
577 return waveOutBreakLoop(wom
->u
.out
.hInnerWave
);
580 static DWORD
wodMapperStatus(WAVEMAPDATA
* wom
, DWORD flags
, LPVOID ptr
)
583 DWORD ret
= MMSYSERR_NOTSUPPORTED
;
585 TRACE("(%p %08x %p)\n",wom
, flags
, ptr
);
588 case WAVEOUT_MAPPER_STATUS_DEVICE
:
589 ret
= waveOutGetID(wom
->u
.out
.hInnerWave
, &id
);
592 case WAVEOUT_MAPPER_STATUS_MAPPED
:
593 FIXME("Unsupported flag=%d\n", flags
);
594 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
596 case WAVEOUT_MAPPER_STATUS_FORMAT
:
597 FIXME("Unsupported flag=%d\n", flags
);
598 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
602 FIXME("Unsupported flag=%d\n", flags
);
609 static DWORD
wodMapperReconfigure(WAVEMAPDATA
* wom
, DWORD dwParam1
, DWORD dwParam2
)
611 FIXME("(%p %08x %08x) stub!\n", wom
, dwParam1
, dwParam2
);
613 return MMSYSERR_NOERROR
;
616 /**************************************************************************
617 * wodMessage (MSACM.@)
619 DWORD WINAPI
WAVEMAP_wodMessage(UINT wDevID
, UINT wMsg
, DWORD_PTR dwUser
,
620 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
622 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
623 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
630 /* FIXME: Pretend this is supported */
632 case WODM_OPEN
: return wodOpen ((DWORD_PTR
*)dwUser
, (LPWAVEOPENDESC
)dwParam1
,dwParam2
);
633 case WODM_CLOSE
: return wodClose ((WAVEMAPDATA
*)dwUser
);
634 case WODM_WRITE
: return wodWrite ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
635 case WODM_PAUSE
: return wodPause ((WAVEMAPDATA
*)dwUser
);
636 case WODM_GETPOS
: return wodGetPosition ((WAVEMAPDATA
*)dwUser
, (LPMMTIME
)dwParam1
, dwParam2
);
637 case WODM_BREAKLOOP
: return wodBreakLoop ((WAVEMAPDATA
*)dwUser
);
638 case WODM_PREPARE
: return wodPrepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
639 case WODM_UNPREPARE
: return wodUnprepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
640 case WODM_GETDEVCAPS
: return wodGetDevCaps (wDevID
, (WAVEMAPDATA
*)dwUser
, (LPWAVEOUTCAPSW
)dwParam1
,dwParam2
);
641 case WODM_GETNUMDEVS
: return 1;
642 case WODM_GETPITCH
: return MMSYSERR_NOTSUPPORTED
;
643 case WODM_SETPITCH
: return MMSYSERR_NOTSUPPORTED
;
644 case WODM_GETPLAYBACKRATE
: return MMSYSERR_NOTSUPPORTED
;
645 case WODM_SETPLAYBACKRATE
: return MMSYSERR_NOTSUPPORTED
;
646 case WODM_GETVOLUME
: return wodGetVolume (wDevID
, (WAVEMAPDATA
*)dwUser
, (LPDWORD
)dwParam1
);
647 case WODM_SETVOLUME
: return wodSetVolume (wDevID
, (WAVEMAPDATA
*)dwUser
, dwParam1
);
648 case WODM_RESTART
: return wodRestart ((WAVEMAPDATA
*)dwUser
);
649 case WODM_RESET
: return wodReset ((WAVEMAPDATA
*)dwUser
);
650 case WODM_MAPPER_STATUS
: return wodMapperStatus ((WAVEMAPDATA
*)dwUser
, dwParam1
, (LPVOID
)dwParam2
);
651 case DRVM_MAPPER_RECONFIGURE
: return wodMapperReconfigure((WAVEMAPDATA
*)dwUser
, dwParam1
, dwParam2
);
652 /* known but not supported */
653 case DRV_QUERYDEVICEINTERFACESIZE
:
654 case DRV_QUERYDEVICEINTERFACE
:
655 return MMSYSERR_NOTSUPPORTED
;
657 FIXME("unknown message %d!\n", wMsg
);
659 return MMSYSERR_NOTSUPPORTED
;
662 /*======================================================================*
664 *======================================================================*/
666 static void CALLBACK
widCallback(HWAVEIN hWave
, UINT uMsg
, DWORD_PTR dwInstance
,
667 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
669 WAVEMAPDATA
* wim
= (WAVEMAPDATA
*)dwInstance
;
671 TRACE("(%p %u %lx %lx %lx);\n", hWave
, uMsg
, dwInstance
, dwParam1
, dwParam2
);
673 if (!WAVEMAP_IsData(wim
)) {
678 if (uMsg
!= WIM_OPEN
&& hWave
!= wim
->u
.in
.hInnerWave
)
679 ERR("Shouldn't happen (%p %p)\n", hWave
, wim
->u
.in
.hInnerWave
);
684 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
687 if (wim
->hAcmStream
) {
688 LPWAVEHDR lpWaveHdrSrc
= (LPWAVEHDR
)dwParam1
;
689 PACMSTREAMHEADER ash
= (PACMSTREAMHEADER
)((LPSTR
)lpWaveHdrSrc
- sizeof(ACMSTREAMHEADER
));
690 LPWAVEHDR lpWaveHdrDst
= (LPWAVEHDR
)ash
->dwUser
;
692 /* convert data just gotten from waveIn into requested format */
693 if (acmStreamConvert(wim
->hAcmStream
, ash
, 0L) != MMSYSERR_NOERROR
) {
694 ERR("ACM conversion failed\n");
697 TRACE("Converted %d bytes into %d\n", ash
->cbSrcLengthUsed
, ash
->cbDstLengthUsed
);
699 /* and setup the wavehdr to return accordingly */
700 lpWaveHdrDst
->dwFlags
&= ~WHDR_INQUEUE
;
701 lpWaveHdrDst
->dwFlags
|= WHDR_DONE
;
702 lpWaveHdrDst
->dwBytesRecorded
= ash
->cbDstLengthUsed
;
703 dwParam1
= (DWORD_PTR
)lpWaveHdrDst
;
707 ERR("Unknown msg %u\n", uMsg
);
710 DriverCallback(wim
->dwCallback
, HIWORD(wim
->dwFlags
), (HDRVR
)wim
->u
.in
.hOuterWave
,
711 uMsg
, wim
->dwClientInstance
, dwParam1
, dwParam2
);
714 static DWORD
widOpenHelper(WAVEMAPDATA
* wim
, UINT idx
,
715 LPWAVEOPENDESC lpDesc
, LPWAVEFORMATEX lpwfx
,
720 TRACE("(%p %04x %p %p %08x)\n", wim
, idx
, lpDesc
, lpwfx
, dwFlags
);
722 /* source is always PCM, so the formulas below apply */
723 lpwfx
->nBlockAlign
= (lpwfx
->nChannels
* lpwfx
->wBitsPerSample
) / 8;
724 lpwfx
->nAvgBytesPerSec
= lpwfx
->nSamplesPerSec
* lpwfx
->nBlockAlign
;
725 if (dwFlags
& WAVE_FORMAT_QUERY
) {
726 ret
= acmStreamOpen(NULL
, 0, lpwfx
, lpDesc
->lpFormat
, NULL
, 0L, 0L, ACM_STREAMOPENF_QUERY
);
728 ret
= acmStreamOpen(&wim
->hAcmStream
, 0, lpwfx
, lpDesc
->lpFormat
, NULL
, 0L, 0L, 0L);
730 if (ret
== MMSYSERR_NOERROR
) {
731 ret
= waveInOpen(&wim
->u
.in
.hInnerWave
, idx
, lpwfx
,
732 (DWORD_PTR
)widCallback
, (DWORD_PTR
)wim
,
733 (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
);
734 if (ret
!= MMSYSERR_NOERROR
&& !(dwFlags
& WAVE_FORMAT_QUERY
)) {
735 acmStreamClose(wim
->hAcmStream
, 0);
739 TRACE("ret = %08x\n", ret
);
743 static DWORD
widOpen(DWORD_PTR
*lpdwUser
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
747 WAVEMAPDATA
* wim
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA
));
750 TRACE("(%p %p %08x)\n", lpdwUser
, lpDesc
, dwFlags
);
754 return MMSYSERR_NOMEM
;
758 wim
->dwCallback
= lpDesc
->dwCallback
;
759 wim
->dwFlags
= dwFlags
;
760 wim
->dwClientInstance
= lpDesc
->dwInstance
;
761 wim
->u
.in
.hOuterWave
= (HWAVEIN
)lpDesc
->hWave
;
763 ndhi
= waveInGetNumDevs();
764 if (dwFlags
& WAVE_MAPPED
) {
765 if (lpDesc
->uMappedDeviceID
>= ndhi
) return MMSYSERR_INVALPARAM
;
766 ndlo
= lpDesc
->uMappedDeviceID
;
768 dwFlags
&= ~WAVE_MAPPED
;
773 wim
->avgSpeedOuter
= wim
->avgSpeedInner
= lpDesc
->lpFormat
->nAvgBytesPerSec
;
774 wim
->nSamplesPerSecOuter
= wim
->nSamplesPerSecInner
= lpDesc
->lpFormat
->nSamplesPerSec
;
776 for (i
= ndlo
; i
< ndhi
; i
++) {
777 if (waveInOpen(&wim
->u
.in
.hInnerWave
, i
, lpDesc
->lpFormat
,
778 (DWORD_PTR
)widCallback
, (DWORD_PTR
)wim
,
779 (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
| WAVE_FORMAT_DIRECT
) == MMSYSERR_NOERROR
) {
785 if ((dwFlags
& WAVE_FORMAT_DIRECT
) == 0)
789 wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
790 wfx
.cbSize
= 0; /* normally, this field is not used for PCM format, just in case */
791 /* try some ACM stuff */
793 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
794 switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
795 case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; wim->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \
796 case WAVERR_BADFORMAT: break; \
797 default: goto error; \
800 for (i
= ndlo
; i
< ndhi
; i
++) {
801 wfx
.nSamplesPerSec
=lpDesc
->lpFormat
->nSamplesPerSec
;
802 /* first try with same stereo/mono option as source */
803 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
804 TRY(wfx
.nSamplesPerSec
, 16);
805 TRY(wfx
.nSamplesPerSec
, 8);
807 TRY(wfx
.nSamplesPerSec
, 16);
808 TRY(wfx
.nSamplesPerSec
, 8);
811 for (i
= ndlo
; i
< ndhi
; i
++) {
812 wfx
.nSamplesPerSec
=lpDesc
->lpFormat
->nSamplesPerSec
;
813 /* first try with same stereo/mono option as source */
814 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
821 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
829 /* first try with same stereo/mono option as source */
830 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
837 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
848 HeapFree(GetProcessHeap(), 0, wim
);
849 WARN("ret = WAVERR_BADFORMAT\n");
850 return WAVERR_BADFORMAT
;
852 if (dwFlags
& WAVE_FORMAT_QUERY
) {
854 HeapFree(GetProcessHeap(), 0, wim
);
856 *lpdwUser
= (DWORD_PTR
)wim
;
858 TRACE("Ok (stream=%p)\n", wim
->hAcmStream
);
859 return MMSYSERR_NOERROR
;
861 HeapFree(GetProcessHeap(), 0, wim
);
862 if (res
==ACMERR_NOTPOSSIBLE
) {
863 WARN("ret = WAVERR_BADFORMAT\n");
864 return WAVERR_BADFORMAT
;
866 WARN("ret = 0x%08x\n", res
);
870 static DWORD
widClose(WAVEMAPDATA
* wim
)
874 TRACE("(%p)\n", wim
);
876 ret
= waveInClose(wim
->u
.in
.hInnerWave
);
877 if (ret
== MMSYSERR_NOERROR
) {
878 if (wim
->hAcmStream
) {
879 ret
= acmStreamClose(wim
->hAcmStream
, 0);
881 if (ret
== MMSYSERR_NOERROR
) {
882 HeapFree(GetProcessHeap(), 0, wim
);
888 static DWORD
widAddBuffer(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
890 PACMSTREAMHEADER ash
;
891 LPWAVEHDR lpWaveHdrSrc
;
893 TRACE("(%p %p %08x)\n", wim
, lpWaveHdrDst
, dwParam2
);
895 if (!wim
->hAcmStream
) {
896 return waveInAddBuffer(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
899 lpWaveHdrDst
->dwFlags
|= WHDR_INQUEUE
;
900 ash
= (PACMSTREAMHEADER
)lpWaveHdrDst
->reserved
;
902 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
903 return waveInAddBuffer(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
906 static DWORD
widPrepare(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
908 PACMSTREAMHEADER ash
;
911 LPWAVEHDR lpWaveHdrSrc
;
913 TRACE("(%p %p %08x)\n", wim
, lpWaveHdrDst
, dwParam2
);
915 if (!wim
->hAcmStream
) {
916 return waveInPrepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
918 if (acmStreamSize(wim
->hAcmStream
, lpWaveHdrDst
->dwBufferLength
, &size
,
919 ACM_STREAMSIZEF_DESTINATION
) != MMSYSERR_NOERROR
) {
920 WARN("acmStreamSize failed\n");
921 return MMSYSERR_ERROR
;
924 ash
= HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
) + size
);
927 return MMSYSERR_NOMEM
;
930 ash
->cbStruct
= sizeof(*ash
);
932 ash
->dwUser
= (DWORD_PTR
)lpWaveHdrDst
;
933 ash
->pbSrc
= (LPBYTE
)ash
+ sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
);
934 ash
->cbSrcLength
= size
;
935 /* ash->cbSrcLengthUsed */
936 ash
->dwSrcUser
= 0L; /* FIXME ? */
937 ash
->pbDst
= (LPBYTE
)lpWaveHdrDst
->lpData
;
938 ash
->cbDstLength
= lpWaveHdrDst
->dwBufferLength
;
939 /* ash->cbDstLengthUsed */
940 ash
->dwDstUser
= lpWaveHdrDst
->dwUser
; /* FIXME ? */
941 dwRet
= acmStreamPrepareHeader(wim
->hAcmStream
, ash
, 0L);
942 if (dwRet
!= MMSYSERR_NOERROR
) {
943 WARN("acmStreamPrepareHeader failed\n");
947 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
948 lpWaveHdrSrc
->lpData
= (LPSTR
)ash
->pbSrc
;
949 lpWaveHdrSrc
->dwBufferLength
= size
; /* conversion is not done yet */
950 lpWaveHdrSrc
->dwFlags
= 0;
951 lpWaveHdrSrc
->dwLoops
= 0;
952 dwRet
= waveInPrepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
953 if (dwRet
!= MMSYSERR_NOERROR
) {
954 WARN("waveInPrepareHeader failed\n");
958 lpWaveHdrDst
->reserved
= (DWORD_PTR
)ash
;
959 lpWaveHdrDst
->dwFlags
= WHDR_PREPARED
;
961 return MMSYSERR_NOERROR
;
963 TRACE("=> (%d)\n", dwRet
);
964 HeapFree(GetProcessHeap(), 0, ash
);
968 static DWORD
widUnprepare(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
970 PACMSTREAMHEADER ash
;
971 LPWAVEHDR lpWaveHdrSrc
;
972 DWORD dwRet1
, dwRet2
;
974 TRACE("(%p %p %08x)\n", wim
, lpWaveHdrDst
, dwParam2
);
976 if (!wim
->hAcmStream
) {
977 return waveInUnprepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
979 ash
= (PACMSTREAMHEADER
)lpWaveHdrDst
->reserved
;
980 dwRet1
= acmStreamUnprepareHeader(wim
->hAcmStream
, ash
, 0L);
982 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
983 dwRet2
= waveInUnprepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
985 HeapFree(GetProcessHeap(), 0, ash
);
987 lpWaveHdrDst
->dwFlags
&= ~WHDR_PREPARED
;
988 return (dwRet1
== MMSYSERR_NOERROR
) ? dwRet2
: dwRet1
;
991 static DWORD
widGetPosition(WAVEMAPDATA
* wim
, LPMMTIME lpTime
, DWORD dwParam2
)
995 TRACE("(%p %p %08x)\n", wim
, lpTime
, dwParam2
);
999 /* For TIME_MS, we're going to recalculate using TIME_BYTES */
1000 if (lpTime
->wType
== TIME_MS
)
1001 timepos
.wType
= TIME_BYTES
;
1003 /* This can change timepos.wType if the requested type is not supported */
1004 val
= waveInGetPosition(wim
->u
.in
.hInnerWave
, &timepos
, dwParam2
);
1006 if (timepos
.wType
== TIME_BYTES
)
1008 DWORD dwInnerSamplesPerOuter
= wim
->nSamplesPerSecInner
/ wim
->nSamplesPerSecOuter
;
1009 if (dwInnerSamplesPerOuter
> 0)
1011 DWORD dwInnerBytesPerSample
= wim
->avgSpeedInner
/ wim
->nSamplesPerSecInner
;
1012 DWORD dwInnerBytesPerOuterSample
= dwInnerBytesPerSample
* dwInnerSamplesPerOuter
;
1013 DWORD remainder
= 0;
1015 /* If we are up sampling (going from lower sample rate to higher),
1016 ** we need to make a special accommodation for times when we've
1017 ** written a partial output sample. This happens frequently
1018 ** to us because we use msacm to do our up sampling, and it
1019 ** will up sample on an unaligned basis.
1020 ** For example, if you convert a 2 byte wide 8,000 'outer'
1021 ** buffer to a 2 byte wide 48,000 inner device, you would
1022 ** expect 2 bytes of input to produce 12 bytes of output.
1023 ** Instead, msacm will produce 8 bytes of output.
1024 ** But reporting our position as 1 byte of output is
1025 ** nonsensical; the output buffer position needs to be
1026 ** aligned on outer sample size, and aggressively rounded up.
1028 remainder
= timepos
.u
.cb
% dwInnerBytesPerOuterSample
;
1031 timepos
.u
.cb
-= remainder
;
1032 timepos
.u
.cb
+= dwInnerBytesPerOuterSample
;
1036 lpTime
->u
.cb
= MulDiv(timepos
.u
.cb
, wim
->avgSpeedOuter
, wim
->avgSpeedInner
);
1038 /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
1039 if (lpTime
->wType
== TIME_MS
)
1040 lpTime
->u
.ms
= MulDiv(lpTime
->u
.cb
, 1000, wim
->avgSpeedOuter
);
1042 lpTime
->wType
= TIME_BYTES
;
1044 else if (lpTime
->wType
== TIME_SAMPLES
&& timepos
.wType
== TIME_SAMPLES
)
1045 lpTime
->u
.sample
= MulDiv(timepos
.u
.sample
, wim
->nSamplesPerSecOuter
, wim
->nSamplesPerSecInner
);
1047 /* other time types don't require conversion */
1048 lpTime
->u
= timepos
.u
;
1053 static DWORD
widGetDevCaps(UINT wDevID
, WAVEMAPDATA
* wim
, LPWAVEINCAPSW lpWaveCaps
, DWORD dwParam2
)
1055 TRACE("(%04x, %p %p %08x)\n", wDevID
, wim
, lpWaveCaps
, dwParam2
);
1057 /* if opened low driver, forward message */
1058 if (WAVEMAP_IsData(wim
))
1059 return waveInGetDevCapsW((UINT_PTR
)wim
->u
.in
.hInnerWave
, lpWaveCaps
, dwParam2
);
1060 /* else if no drivers, nothing to map so return bad device */
1061 if (waveInGetNumDevs() == 0) {
1062 WARN("bad device id\n");
1063 return MMSYSERR_BADDEVICEID
;
1065 /* otherwise, return caps of mapper itself */
1066 if (wDevID
== (UINT
)-1 || wDevID
== (UINT16
)-1) {
1068 static const WCHAR init
[] = {'W','i','n','e',' ','w','a','v','e',' ','i','n',' ','m','a','p','p','e','r',0};
1071 wic
.vDriverVersion
= 0x0001;
1072 strcpyW(wic
.szPname
, init
);
1074 WAVE_FORMAT_96M08
| WAVE_FORMAT_96S08
| WAVE_FORMAT_96M16
| WAVE_FORMAT_96S16
|
1075 WAVE_FORMAT_48M08
| WAVE_FORMAT_48S08
| WAVE_FORMAT_48M16
| WAVE_FORMAT_48S16
|
1076 WAVE_FORMAT_4M08
| WAVE_FORMAT_4S08
| WAVE_FORMAT_4M16
| WAVE_FORMAT_4S16
|
1077 WAVE_FORMAT_2M08
| WAVE_FORMAT_2S08
| WAVE_FORMAT_2M16
| WAVE_FORMAT_2S16
|
1078 WAVE_FORMAT_1M08
| WAVE_FORMAT_1S08
| WAVE_FORMAT_1M16
| WAVE_FORMAT_1S16
;
1080 memcpy(lpWaveCaps
, &wic
, min(dwParam2
, sizeof(wic
)));
1082 return MMSYSERR_NOERROR
;
1084 ERR("This shouldn't happen\n");
1085 return MMSYSERR_ERROR
;
1088 static DWORD
widStop(WAVEMAPDATA
* wim
)
1090 TRACE("(%p)\n", wim
);
1092 return waveInStop(wim
->u
.in
.hInnerWave
);
1095 static DWORD
widStart(WAVEMAPDATA
* wim
)
1097 TRACE("(%p)\n", wim
);
1099 return waveInStart(wim
->u
.in
.hInnerWave
);
1102 static DWORD
widReset(WAVEMAPDATA
* wim
)
1104 TRACE("(%p)\n", wim
);
1106 return waveInReset(wim
->u
.in
.hInnerWave
);
1109 static DWORD
widMapperStatus(WAVEMAPDATA
* wim
, DWORD flags
, LPVOID ptr
)
1112 DWORD ret
= MMSYSERR_NOTSUPPORTED
;
1114 TRACE("(%p %08x %p)\n", wim
, flags
, ptr
);
1117 case WAVEIN_MAPPER_STATUS_DEVICE
:
1118 ret
= waveInGetID(wim
->u
.in
.hInnerWave
, &id
);
1121 case WAVEIN_MAPPER_STATUS_MAPPED
:
1122 FIXME("Unsupported yet flag=%d\n", flags
);
1123 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
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 ?? */
1131 FIXME("Unsupported flag=%d\n", flags
);
1138 static DWORD
widMapperReconfigure(WAVEMAPDATA
* wim
, DWORD dwParam1
, DWORD dwParam2
)
1140 FIXME("(%p %08x %08x) stub!\n", wim
, dwParam1
, dwParam2
);
1142 return MMSYSERR_NOERROR
;
1145 /**************************************************************************
1146 * widMessage (MSACM.@)
1148 DWORD WINAPI
WAVEMAP_widMessage(WORD wDevID
, WORD wMsg
, DWORD_PTR dwUser
,
1149 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
1151 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1152 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1159 /* FIXME: Pretend this is supported */
1162 case WIDM_OPEN
: return widOpen ((DWORD_PTR
*)dwUser
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
1163 case WIDM_CLOSE
: return widClose ((WAVEMAPDATA
*)dwUser
);
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
;
1181 FIXME("unknown message %u!\n", wMsg
);
1183 return MMSYSERR_NOTSUPPORTED
;
1186 /*======================================================================*
1188 *======================================================================*/
1190 static struct WINE_WAVEMAP
* oss
= NULL
;
1192 /**************************************************************************
1193 * WAVEMAP_drvOpen [internal]
1195 static LRESULT
WAVEMAP_drvOpen(LPSTR str
)
1197 TRACE("(%p)\n", str
);
1202 /* I know, this is ugly, but who cares... */
1203 oss
= (struct WINE_WAVEMAP
*)1;
1207 /**************************************************************************
1208 * WAVEMAP_drvClose [internal]
1210 static LRESULT
WAVEMAP_drvClose(DWORD_PTR dwDevID
)
1212 TRACE("(%08lx)\n", dwDevID
);
1221 /**************************************************************************
1222 * DriverProc (MSACM.@)
1224 LRESULT CALLBACK
WAVEMAP_DriverProc(DWORD_PTR dwDevID
, HDRVR hDriv
, UINT wMsg
,
1225 LPARAM dwParam1
, LPARAM dwParam2
)
1227 TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
1228 dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
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
;
1242 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);