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/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(wavemap
);
44 typedef struct tagWAVEMAPDATA
{
45 struct tagWAVEMAPDATA
* self
;
56 HACMSTREAM hAcmStream
;
57 /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */
59 DWORD_PTR dwClientInstance
;
61 /* ratio to compute position from a PCM playback to any format */
64 /* channel size of inner and outer */
65 DWORD nSamplesPerSecOuter
;
66 DWORD nSamplesPerSecInner
;
69 static BOOL
WAVEMAP_IsData(const WAVEMAPDATA
* wm
)
71 return (!IsBadReadPtr(wm
, sizeof(WAVEMAPDATA
)) && wm
->self
== wm
);
74 /*======================================================================*
76 *======================================================================*/
78 static void CALLBACK
wodCallback(HWAVEOUT hWave
, UINT uMsg
, DWORD_PTR dwInstance
,
79 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
81 WAVEMAPDATA
* wom
= (WAVEMAPDATA
*)dwInstance
;
83 TRACE("(%p %u %ld %lx %lx);\n", hWave
, uMsg
, dwInstance
, dwParam1
, dwParam2
);
85 if (!WAVEMAP_IsData(wom
)) {
90 if (uMsg
!= WOM_OPEN
&& hWave
!= wom
->u
.out
.hInnerWave
)
91 ERR("Shouldn't happen (%p %p)\n", hWave
, wom
->u
.out
.hInnerWave
);
96 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
99 if (wom
->hAcmStream
) {
100 LPWAVEHDR lpWaveHdrDst
= (LPWAVEHDR
)dwParam1
;
101 PACMSTREAMHEADER ash
= (PACMSTREAMHEADER
)((LPSTR
)lpWaveHdrDst
- sizeof(ACMSTREAMHEADER
));
102 LPWAVEHDR lpWaveHdrSrc
= (LPWAVEHDR
)ash
->dwUser
;
104 lpWaveHdrSrc
->dwFlags
&= ~WHDR_INQUEUE
;
105 lpWaveHdrSrc
->dwFlags
|= WHDR_DONE
;
106 dwParam1
= (DWORD_PTR
)lpWaveHdrSrc
;
110 ERR("Unknown msg %u\n", uMsg
);
113 DriverCallback(wom
->dwCallback
, HIWORD(wom
->dwFlags
), (HDRVR
)wom
->u
.out
.hOuterWave
,
114 uMsg
, wom
->dwClientInstance
, dwParam1
, dwParam2
);
117 /******************************************************************
122 static DWORD
wodOpenHelper(WAVEMAPDATA
* wom
, UINT idx
,
123 LPWAVEOPENDESC lpDesc
, LPWAVEFORMATEX lpwfx
,
128 TRACE("(%p %04x %p %p %08x)\n", wom
, idx
, lpDesc
, lpwfx
, dwFlags
);
130 /* destination is always PCM, so the formulas below apply */
131 lpwfx
->nBlockAlign
= (lpwfx
->nChannels
* lpwfx
->wBitsPerSample
) / 8;
132 lpwfx
->nAvgBytesPerSec
= lpwfx
->nSamplesPerSec
* lpwfx
->nBlockAlign
;
133 if (dwFlags
& WAVE_FORMAT_QUERY
) {
134 ret
= acmStreamOpen(NULL
, 0, lpDesc
->lpFormat
, lpwfx
, NULL
, 0L, 0L, ACM_STREAMOPENF_QUERY
);
136 ret
= acmStreamOpen(&wom
->hAcmStream
, 0, lpDesc
->lpFormat
, lpwfx
, NULL
, 0L, 0L, 0L);
138 if (ret
== MMSYSERR_NOERROR
) {
139 ret
= waveOutOpen(&wom
->u
.out
.hInnerWave
, idx
, lpwfx
,
140 (DWORD_PTR
)wodCallback
, (DWORD_PTR
)wom
,
141 (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
);
142 if (ret
!= MMSYSERR_NOERROR
&& !(dwFlags
& WAVE_FORMAT_QUERY
)) {
143 acmStreamClose(wom
->hAcmStream
, 0);
147 TRACE("ret = %08x\n", ret
);
151 static DWORD
wodOpen(DWORD_PTR
*lpdwUser
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
155 WAVEMAPDATA
* wom
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA
));
158 TRACE("(%p %p %08x)\n", lpdwUser
, lpDesc
, dwFlags
);
162 return MMSYSERR_NOMEM
;
165 ndhi
= waveOutGetNumDevs();
166 if (dwFlags
& WAVE_MAPPED
) {
167 if (lpDesc
->uMappedDeviceID
>= ndhi
) {
168 WARN("invalid parameter: dwFlags WAVE_MAPPED\n");
169 HeapFree(GetProcessHeap(), 0, wom
);
170 return MMSYSERR_INVALPARAM
;
172 ndlo
= lpDesc
->uMappedDeviceID
;
174 dwFlags
&= ~WAVE_MAPPED
;
179 wom
->dwCallback
= lpDesc
->dwCallback
;
180 wom
->dwFlags
= dwFlags
;
181 wom
->dwClientInstance
= lpDesc
->dwInstance
;
182 wom
->u
.out
.hOuterWave
= (HWAVEOUT
)lpDesc
->hWave
;
183 wom
->avgSpeedOuter
= wom
->avgSpeedInner
= lpDesc
->lpFormat
->nAvgBytesPerSec
;
184 wom
->nSamplesPerSecOuter
= wom
->nSamplesPerSecInner
= lpDesc
->lpFormat
->nSamplesPerSec
;
186 for (i
= ndlo
; i
< ndhi
; i
++) {
187 /* if no ACM stuff is involved, no need to handle callbacks at this
188 * level, this will be done transparently
190 if (waveOutOpen(&wom
->u
.out
.hInnerWave
, i
, lpDesc
->lpFormat
,
191 (DWORD_PTR
)wodCallback
, (DWORD_PTR
)wom
,
192 (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
| WAVE_FORMAT_DIRECT
) == MMSYSERR_NOERROR
) {
198 if ((dwFlags
& WAVE_FORMAT_DIRECT
) == 0) {
201 wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
202 wfx
.cbSize
= 0; /* normally, this field is not used for PCM format, just in case */
203 /* try some ACM stuff */
205 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
206 switch (res=wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
207 case MMSYSERR_NOERROR: wom->avgSpeedInner = wfx.nAvgBytesPerSec; wom->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \
208 case WAVERR_BADFORMAT: break; \
209 default: goto error; \
212 if (lpDesc
->lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
) {
213 /* Format changed so keep sample rate and number of channels
214 * the same and just change the bit depth
216 for (i
= ndlo
; i
< ndhi
; i
++) {
217 wfx
.nSamplesPerSec
=lpDesc
->lpFormat
->nSamplesPerSec
;
218 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
219 TRY(wfx
.nSamplesPerSec
, 16);
220 TRY(wfx
.nSamplesPerSec
, 8);
223 /* Our resampling algorithm is quite primitive so first try
224 * to just change the bit depth and number of channels
226 for (i
= ndlo
; i
< ndhi
; i
++) {
227 wfx
.nSamplesPerSec
=lpDesc
->lpFormat
->nSamplesPerSec
;
228 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
229 TRY(wfx
.nSamplesPerSec
, 16);
230 TRY(wfx
.nSamplesPerSec
, 8);
232 TRY(wfx
.nSamplesPerSec
, 16);
233 TRY(wfx
.nSamplesPerSec
, 8);
236 for (i
= ndlo
; i
< ndhi
; i
++) {
237 /* first try with same stereo/mono option as source */
238 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
245 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
253 /* first try with same stereo/mono option as source */
254 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
261 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
273 HeapFree(GetProcessHeap(), 0, wom
);
274 WARN("ret = WAVERR_BADFORMAT\n");
275 return WAVERR_BADFORMAT
;
278 if (dwFlags
& WAVE_FORMAT_QUERY
) {
280 HeapFree(GetProcessHeap(), 0, wom
);
282 *lpdwUser
= (DWORD_PTR
)wom
;
284 return MMSYSERR_NOERROR
;
286 HeapFree(GetProcessHeap(), 0, wom
);
287 if (res
==ACMERR_NOTPOSSIBLE
) {
288 WARN("ret = WAVERR_BADFORMAT\n");
289 return WAVERR_BADFORMAT
;
291 WARN("ret = 0x%08x\n", res
);
295 static DWORD
wodClose(WAVEMAPDATA
* wom
)
299 TRACE("(%p)\n", wom
);
301 ret
= waveOutClose(wom
->u
.out
.hInnerWave
);
302 if (ret
== MMSYSERR_NOERROR
) {
303 if (wom
->hAcmStream
) {
304 ret
= acmStreamClose(wom
->hAcmStream
, 0);
306 if (ret
== MMSYSERR_NOERROR
) {
307 HeapFree(GetProcessHeap(), 0, wom
);
313 static DWORD
wodWrite(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
315 PACMSTREAMHEADER ash
;
316 LPWAVEHDR lpWaveHdrDst
;
318 TRACE("(%p %p %08x)\n", wom
, lpWaveHdrSrc
, dwParam2
);
320 if (!wom
->hAcmStream
) {
321 return waveOutWrite(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
324 lpWaveHdrSrc
->dwFlags
|= WHDR_INQUEUE
;
325 ash
= (PACMSTREAMHEADER
)lpWaveHdrSrc
->reserved
;
326 /* acmStreamConvert will actually check that the new size is less than initial size */
327 ash
->cbSrcLength
= lpWaveHdrSrc
->dwBufferLength
;
328 if (acmStreamConvert(wom
->hAcmStream
, ash
, 0L) != MMSYSERR_NOERROR
) {
329 WARN("acmStreamConvert failed\n");
330 return MMSYSERR_ERROR
;
333 lpWaveHdrDst
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
334 if (ash
->cbSrcLength
> ash
->cbSrcLengthUsed
)
335 FIXME("Not all src buffer has been written, expect bogus sound\n");
336 else if (ash
->cbSrcLength
< ash
->cbSrcLengthUsed
)
337 ERR("Codec has read more data than it is allowed to\n");
339 if (ash
->cbDstLengthUsed
== 0) {
340 /* something went wrong in decoding */
341 FIXME("Got 0 length\n");
342 return MMSYSERR_ERROR
;
344 lpWaveHdrDst
->dwBufferLength
= ash
->cbDstLengthUsed
;
345 return waveOutWrite(wom
->u
.out
.hInnerWave
, lpWaveHdrDst
, sizeof(*lpWaveHdrDst
));
348 static DWORD
wodPrepare(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
350 PACMSTREAMHEADER ash
;
353 LPWAVEHDR lpWaveHdrDst
;
355 TRACE("(%p %p %08x)\n", wom
, lpWaveHdrSrc
, dwParam2
);
357 if (!wom
->hAcmStream
)
358 return waveOutPrepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
360 if (acmStreamSize(wom
->hAcmStream
, lpWaveHdrSrc
->dwBufferLength
, &size
, ACM_STREAMSIZEF_SOURCE
) != MMSYSERR_NOERROR
) {
361 WARN("acmStreamSize failed\n");
362 return MMSYSERR_ERROR
;
365 ash
= HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
) + size
);
368 return MMSYSERR_NOMEM
;
371 ash
->cbStruct
= sizeof(*ash
);
373 ash
->dwUser
= (DWORD_PTR
)lpWaveHdrSrc
;
374 ash
->pbSrc
= (LPBYTE
)lpWaveHdrSrc
->lpData
;
375 ash
->cbSrcLength
= lpWaveHdrSrc
->dwBufferLength
;
376 /* ash->cbSrcLengthUsed */
377 ash
->dwSrcUser
= lpWaveHdrSrc
->dwUser
; /* FIXME ? */
378 ash
->pbDst
= (LPBYTE
)ash
+ sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
);
379 ash
->cbDstLength
= size
;
380 /* ash->cbDstLengthUsed */
381 ash
->dwDstUser
= 0; /* FIXME ? */
382 dwRet
= acmStreamPrepareHeader(wom
->hAcmStream
, ash
, 0L);
383 if (dwRet
!= MMSYSERR_NOERROR
) {
384 WARN("acmStreamPrepareHeader failed\n");
388 lpWaveHdrDst
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
389 lpWaveHdrDst
->lpData
= (LPSTR
)ash
->pbDst
;
390 lpWaveHdrDst
->dwBufferLength
= size
; /* conversion is not done yet */
391 lpWaveHdrDst
->dwFlags
= 0;
392 lpWaveHdrDst
->dwLoops
= 0;
393 dwRet
= waveOutPrepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrDst
, sizeof(*lpWaveHdrDst
));
394 if (dwRet
!= MMSYSERR_NOERROR
) {
395 WARN("waveOutPrepareHeader failed\n");
399 lpWaveHdrSrc
->reserved
= (DWORD_PTR
)ash
;
400 lpWaveHdrSrc
->dwFlags
= WHDR_PREPARED
;
402 return MMSYSERR_NOERROR
;
404 TRACE("=> (%d)\n", dwRet
);
405 HeapFree(GetProcessHeap(), 0, ash
);
409 static DWORD
wodUnprepare(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
411 PACMSTREAMHEADER ash
;
412 LPWAVEHDR lpWaveHdrDst
;
413 DWORD dwRet1
, dwRet2
;
415 TRACE("(%p %p %08x)\n", wom
, lpWaveHdrSrc
, dwParam2
);
417 if (!wom
->hAcmStream
) {
418 return waveOutUnprepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
420 ash
= (PACMSTREAMHEADER
)lpWaveHdrSrc
->reserved
;
421 dwRet1
= acmStreamUnprepareHeader(wom
->hAcmStream
, ash
, 0L);
423 lpWaveHdrDst
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
424 dwRet2
= waveOutUnprepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrDst
, sizeof(*lpWaveHdrDst
));
426 HeapFree(GetProcessHeap(), 0, ash
);
428 lpWaveHdrSrc
->dwFlags
&= ~WHDR_PREPARED
;
429 return (dwRet1
== MMSYSERR_NOERROR
) ? dwRet2
: dwRet1
;
432 static DWORD
wodGetPosition(WAVEMAPDATA
* wom
, LPMMTIME lpTime
, DWORD dwParam2
)
436 TRACE("(%p %p %08x)\n", wom
, lpTime
, dwParam2
);
440 /* For TIME_MS, we're going to recalculate using TIME_BYTES */
441 if (lpTime
->wType
== TIME_MS
)
442 timepos
.wType
= TIME_BYTES
;
444 /* This can change timepos.wType if the requested type is not supported */
445 val
= waveOutGetPosition(wom
->u
.out
.hInnerWave
, &timepos
, dwParam2
);
447 if (timepos
.wType
== TIME_BYTES
)
449 DWORD dwInnerSamplesPerOuter
= wom
->nSamplesPerSecInner
/ wom
->nSamplesPerSecOuter
;
450 if (dwInnerSamplesPerOuter
> 0)
452 DWORD dwInnerBytesPerSample
= wom
->avgSpeedInner
/ wom
->nSamplesPerSecInner
;
453 DWORD dwInnerBytesPerOuterSample
= dwInnerBytesPerSample
* dwInnerSamplesPerOuter
;
456 /* If we are up sampling (going from lower sample rate to higher),
457 ** we need to make a special accommodation for times when we've
458 ** written a partial output sample. This happens frequently
459 ** to us because we use msacm to do our up sampling, and it
460 ** will up sample on an unaligned basis.
461 ** For example, if you convert a 2 byte wide 8,000 'outer'
462 ** buffer to a 2 byte wide 48,000 inner device, you would
463 ** expect 2 bytes of input to produce 12 bytes of output.
464 ** Instead, msacm will produce 8 bytes of output.
465 ** But reporting our position as 1 byte of output is
466 ** nonsensical; the output buffer position needs to be
467 ** aligned on outer sample size, and aggressively rounded up.
469 remainder
= timepos
.u
.cb
% dwInnerBytesPerOuterSample
;
472 timepos
.u
.cb
-= remainder
;
473 timepos
.u
.cb
+= dwInnerBytesPerOuterSample
;
477 lpTime
->u
.cb
= MulDiv(timepos
.u
.cb
, wom
->avgSpeedOuter
, wom
->avgSpeedInner
);
479 /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
480 if (lpTime
->wType
== TIME_MS
)
481 lpTime
->u
.ms
= MulDiv(lpTime
->u
.cb
, 1000, wom
->avgSpeedOuter
);
483 lpTime
->wType
= TIME_BYTES
;
485 else if (lpTime
->wType
== TIME_SAMPLES
&& timepos
.wType
== TIME_SAMPLES
)
486 lpTime
->u
.sample
= MulDiv(timepos
.u
.sample
, wom
->nSamplesPerSecOuter
, wom
->nSamplesPerSecInner
);
488 /* other time types don't require conversion */
489 lpTime
->u
= timepos
.u
;
494 static DWORD
wodGetDevCaps(UINT wDevID
, WAVEMAPDATA
* wom
, LPWAVEOUTCAPSW lpWaveCaps
, DWORD dwParam2
)
496 TRACE("(%04x %p %p %08x)\n",wDevID
, wom
, lpWaveCaps
, dwParam2
);
498 /* if opened low driver, forward message */
499 if (WAVEMAP_IsData(wom
))
500 return waveOutGetDevCapsW((UINT_PTR
)wom
->u
.out
.hInnerWave
, lpWaveCaps
, dwParam2
);
501 /* else if no drivers, nothing to map so return bad device */
502 if (waveOutGetNumDevs() == 0) {
503 WARN("bad device id\n");
504 return MMSYSERR_BADDEVICEID
;
506 /* otherwise, return caps of mapper itself */
507 if (wDevID
== (UINT
)-1 || wDevID
== (UINT16
)-1) {
511 woc
.vDriverVersion
= 0x0332;
512 lstrcpyW(woc
.szPname
, L
"Wine wave out mapper");
514 WAVE_FORMAT_96M08
| WAVE_FORMAT_96S08
| WAVE_FORMAT_96M16
| WAVE_FORMAT_96S16
|
515 WAVE_FORMAT_48M08
| WAVE_FORMAT_48S08
| WAVE_FORMAT_48M16
| WAVE_FORMAT_48S16
|
516 WAVE_FORMAT_4M08
| WAVE_FORMAT_4S08
| WAVE_FORMAT_4M16
| WAVE_FORMAT_4S16
|
517 WAVE_FORMAT_2M08
| WAVE_FORMAT_2S08
| WAVE_FORMAT_2M16
| WAVE_FORMAT_2S16
|
518 WAVE_FORMAT_1M08
| WAVE_FORMAT_1S08
| WAVE_FORMAT_1M16
| WAVE_FORMAT_1S16
;
521 woc
.dwSupport
= WAVECAPS_VOLUME
| WAVECAPS_LRVOLUME
;
522 memcpy(lpWaveCaps
, &woc
, min(dwParam2
, sizeof(woc
)));
524 return MMSYSERR_NOERROR
;
526 ERR("This shouldn't happen\n");
527 return MMSYSERR_ERROR
;
530 static DWORD
wodGetVolume(UINT wDevID
, WAVEMAPDATA
* wom
, LPDWORD lpVol
)
532 TRACE("(%04x %p %p)\n",wDevID
, wom
, lpVol
);
534 if (WAVEMAP_IsData(wom
))
535 return waveOutGetVolume(wom
->u
.out
.hInnerWave
, lpVol
);
536 return MMSYSERR_NOERROR
;
539 static DWORD
wodSetVolume(UINT wDevID
, WAVEMAPDATA
* wom
, DWORD vol
)
541 TRACE("(%04x %p %08x)\n",wDevID
, wom
, vol
);
543 if (WAVEMAP_IsData(wom
))
544 return waveOutSetVolume(wom
->u
.out
.hInnerWave
, vol
);
545 return MMSYSERR_NOERROR
;
548 static DWORD
wodPause(WAVEMAPDATA
* wom
)
552 return waveOutPause(wom
->u
.out
.hInnerWave
);
555 static DWORD
wodRestart(WAVEMAPDATA
* wom
)
559 return waveOutRestart(wom
->u
.out
.hInnerWave
);
562 static DWORD
wodReset(WAVEMAPDATA
* wom
)
566 return waveOutReset(wom
->u
.out
.hInnerWave
);
569 static DWORD
wodBreakLoop(WAVEMAPDATA
* wom
)
573 return waveOutBreakLoop(wom
->u
.out
.hInnerWave
);
576 static DWORD
wodMapperStatus(WAVEMAPDATA
* wom
, DWORD flags
, LPVOID ptr
)
579 DWORD ret
= MMSYSERR_NOTSUPPORTED
;
581 TRACE("(%p %08x %p)\n",wom
, flags
, ptr
);
584 case WAVEOUT_MAPPER_STATUS_DEVICE
:
585 ret
= waveOutGetID(wom
->u
.out
.hInnerWave
, &id
);
588 case WAVEOUT_MAPPER_STATUS_MAPPED
:
589 FIXME("Unsupported flag=%d\n", flags
);
590 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
592 case WAVEOUT_MAPPER_STATUS_FORMAT
:
593 FIXME("Unsupported flag=%d\n", flags
);
594 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
598 FIXME("Unsupported flag=%d\n", flags
);
605 static DWORD
wodMapperReconfigure(WAVEMAPDATA
* wom
, DWORD dwParam1
, DWORD dwParam2
)
607 FIXME("(%p %08x %08x) stub!\n", wom
, dwParam1
, dwParam2
);
609 return MMSYSERR_NOERROR
;
612 /**************************************************************************
613 * wodMessage (MSACM.@)
615 DWORD WINAPI
WAVEMAP_wodMessage(UINT wDevID
, UINT wMsg
, DWORD_PTR dwUser
,
616 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
618 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
619 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
626 /* FIXME: Pretend this is supported */
628 case WODM_OPEN
: return wodOpen ((DWORD_PTR
*)dwUser
, (LPWAVEOPENDESC
)dwParam1
,dwParam2
);
629 case WODM_CLOSE
: return wodClose ((WAVEMAPDATA
*)dwUser
);
630 case WODM_WRITE
: return wodWrite ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
631 case WODM_PAUSE
: return wodPause ((WAVEMAPDATA
*)dwUser
);
632 case WODM_GETPOS
: return wodGetPosition ((WAVEMAPDATA
*)dwUser
, (LPMMTIME
)dwParam1
, dwParam2
);
633 case WODM_BREAKLOOP
: return wodBreakLoop ((WAVEMAPDATA
*)dwUser
);
634 case WODM_PREPARE
: return wodPrepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
635 case WODM_UNPREPARE
: return wodUnprepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
636 case WODM_GETDEVCAPS
: return wodGetDevCaps (wDevID
, (WAVEMAPDATA
*)dwUser
, (LPWAVEOUTCAPSW
)dwParam1
,dwParam2
);
637 case WODM_GETNUMDEVS
: return 1;
638 case WODM_GETPITCH
: return MMSYSERR_NOTSUPPORTED
;
639 case WODM_SETPITCH
: return MMSYSERR_NOTSUPPORTED
;
640 case WODM_GETPLAYBACKRATE
: return MMSYSERR_NOTSUPPORTED
;
641 case WODM_SETPLAYBACKRATE
: return MMSYSERR_NOTSUPPORTED
;
642 case WODM_GETVOLUME
: return wodGetVolume (wDevID
, (WAVEMAPDATA
*)dwUser
, (LPDWORD
)dwParam1
);
643 case WODM_SETVOLUME
: return wodSetVolume (wDevID
, (WAVEMAPDATA
*)dwUser
, dwParam1
);
644 case WODM_RESTART
: return wodRestart ((WAVEMAPDATA
*)dwUser
);
645 case WODM_RESET
: return wodReset ((WAVEMAPDATA
*)dwUser
);
646 case WODM_MAPPER_STATUS
: return wodMapperStatus ((WAVEMAPDATA
*)dwUser
, dwParam1
, (LPVOID
)dwParam2
);
647 case DRVM_MAPPER_RECONFIGURE
: return wodMapperReconfigure((WAVEMAPDATA
*)dwUser
, dwParam1
, dwParam2
);
648 /* known but not supported */
649 case DRV_QUERYDEVICEINTERFACESIZE
:
650 case DRV_QUERYDEVICEINTERFACE
:
651 return MMSYSERR_NOTSUPPORTED
;
653 FIXME("unknown message %d!\n", wMsg
);
655 return MMSYSERR_NOTSUPPORTED
;
658 /*======================================================================*
660 *======================================================================*/
662 static void CALLBACK
widCallback(HWAVEIN hWave
, UINT uMsg
, DWORD_PTR dwInstance
,
663 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
665 WAVEMAPDATA
* wim
= (WAVEMAPDATA
*)dwInstance
;
667 TRACE("(%p %u %lx %lx %lx);\n", hWave
, uMsg
, dwInstance
, dwParam1
, dwParam2
);
669 if (!WAVEMAP_IsData(wim
)) {
674 if (uMsg
!= WIM_OPEN
&& hWave
!= wim
->u
.in
.hInnerWave
)
675 ERR("Shouldn't happen (%p %p)\n", hWave
, wim
->u
.in
.hInnerWave
);
680 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
683 if (wim
->hAcmStream
) {
684 LPWAVEHDR lpWaveHdrSrc
= (LPWAVEHDR
)dwParam1
;
685 PACMSTREAMHEADER ash
= (PACMSTREAMHEADER
)((LPSTR
)lpWaveHdrSrc
- sizeof(ACMSTREAMHEADER
));
686 LPWAVEHDR lpWaveHdrDst
= (LPWAVEHDR
)ash
->dwUser
;
688 /* convert data just gotten from waveIn into requested format */
689 if (acmStreamConvert(wim
->hAcmStream
, ash
, 0L) != MMSYSERR_NOERROR
) {
690 ERR("ACM conversion failed\n");
693 TRACE("Converted %d bytes into %d\n", ash
->cbSrcLengthUsed
, ash
->cbDstLengthUsed
);
695 /* and setup the wavehdr to return accordingly */
696 lpWaveHdrDst
->dwFlags
&= ~WHDR_INQUEUE
;
697 lpWaveHdrDst
->dwFlags
|= WHDR_DONE
;
698 lpWaveHdrDst
->dwBytesRecorded
= ash
->cbDstLengthUsed
;
699 dwParam1
= (DWORD_PTR
)lpWaveHdrDst
;
703 ERR("Unknown msg %u\n", uMsg
);
706 DriverCallback(wim
->dwCallback
, HIWORD(wim
->dwFlags
), (HDRVR
)wim
->u
.in
.hOuterWave
,
707 uMsg
, wim
->dwClientInstance
, dwParam1
, dwParam2
);
710 static DWORD
widOpenHelper(WAVEMAPDATA
* wim
, UINT idx
,
711 LPWAVEOPENDESC lpDesc
, LPWAVEFORMATEX lpwfx
,
716 TRACE("(%p %04x %p %p %08x)\n", wim
, idx
, lpDesc
, lpwfx
, dwFlags
);
718 /* source is always PCM, so the formulas below apply */
719 lpwfx
->nBlockAlign
= (lpwfx
->nChannels
* lpwfx
->wBitsPerSample
) / 8;
720 lpwfx
->nAvgBytesPerSec
= lpwfx
->nSamplesPerSec
* lpwfx
->nBlockAlign
;
721 if (dwFlags
& WAVE_FORMAT_QUERY
) {
722 ret
= acmStreamOpen(NULL
, 0, lpwfx
, lpDesc
->lpFormat
, NULL
, 0L, 0L, ACM_STREAMOPENF_QUERY
);
724 ret
= acmStreamOpen(&wim
->hAcmStream
, 0, lpwfx
, lpDesc
->lpFormat
, NULL
, 0L, 0L, 0L);
726 if (ret
== MMSYSERR_NOERROR
) {
727 ret
= waveInOpen(&wim
->u
.in
.hInnerWave
, idx
, lpwfx
,
728 (DWORD_PTR
)widCallback
, (DWORD_PTR
)wim
,
729 (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
);
730 if (ret
!= MMSYSERR_NOERROR
&& !(dwFlags
& WAVE_FORMAT_QUERY
)) {
731 acmStreamClose(wim
->hAcmStream
, 0);
735 TRACE("ret = %08x\n", ret
);
739 static DWORD
widOpen(DWORD_PTR
*lpdwUser
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
743 WAVEMAPDATA
* wim
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA
));
746 TRACE("(%p %p %08x)\n", lpdwUser
, lpDesc
, dwFlags
);
750 return MMSYSERR_NOMEM
;
754 wim
->dwCallback
= lpDesc
->dwCallback
;
755 wim
->dwFlags
= dwFlags
;
756 wim
->dwClientInstance
= lpDesc
->dwInstance
;
757 wim
->u
.in
.hOuterWave
= (HWAVEIN
)lpDesc
->hWave
;
759 ndhi
= waveInGetNumDevs();
760 if (dwFlags
& WAVE_MAPPED
) {
761 if (lpDesc
->uMappedDeviceID
>= ndhi
) return MMSYSERR_INVALPARAM
;
762 ndlo
= lpDesc
->uMappedDeviceID
;
764 dwFlags
&= ~WAVE_MAPPED
;
769 wim
->avgSpeedOuter
= wim
->avgSpeedInner
= lpDesc
->lpFormat
->nAvgBytesPerSec
;
770 wim
->nSamplesPerSecOuter
= wim
->nSamplesPerSecInner
= lpDesc
->lpFormat
->nSamplesPerSec
;
772 for (i
= ndlo
; i
< ndhi
; i
++) {
773 if (waveInOpen(&wim
->u
.in
.hInnerWave
, i
, lpDesc
->lpFormat
,
774 (DWORD_PTR
)widCallback
, (DWORD_PTR
)wim
,
775 (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
| WAVE_FORMAT_DIRECT
) == MMSYSERR_NOERROR
) {
781 if ((dwFlags
& WAVE_FORMAT_DIRECT
) == 0)
785 wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
786 wfx
.cbSize
= 0; /* normally, this field is not used for PCM format, just in case */
787 /* try some ACM stuff */
789 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
790 switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
791 case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; wim->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \
792 case WAVERR_BADFORMAT: break; \
793 default: goto error; \
796 for (i
= ndlo
; i
< ndhi
; i
++) {
797 wfx
.nSamplesPerSec
=lpDesc
->lpFormat
->nSamplesPerSec
;
798 /* first try with same stereo/mono option as source */
799 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
800 TRY(wfx
.nSamplesPerSec
, 16);
801 TRY(wfx
.nSamplesPerSec
, 8);
803 TRY(wfx
.nSamplesPerSec
, 16);
804 TRY(wfx
.nSamplesPerSec
, 8);
807 for (i
= ndlo
; i
< ndhi
; i
++) {
808 wfx
.nSamplesPerSec
=lpDesc
->lpFormat
->nSamplesPerSec
;
809 /* first try with same stereo/mono option as source */
810 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
817 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
825 /* first try with same stereo/mono option as source */
826 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
833 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
844 HeapFree(GetProcessHeap(), 0, wim
);
845 WARN("ret = WAVERR_BADFORMAT\n");
846 return WAVERR_BADFORMAT
;
848 if (dwFlags
& WAVE_FORMAT_QUERY
) {
850 HeapFree(GetProcessHeap(), 0, wim
);
852 *lpdwUser
= (DWORD_PTR
)wim
;
853 TRACE("Ok (stream=%p)\n", wim
->hAcmStream
);
855 return MMSYSERR_NOERROR
;
857 HeapFree(GetProcessHeap(), 0, wim
);
858 if (res
==ACMERR_NOTPOSSIBLE
) {
859 WARN("ret = WAVERR_BADFORMAT\n");
860 return WAVERR_BADFORMAT
;
862 WARN("ret = 0x%08x\n", res
);
866 static DWORD
widClose(WAVEMAPDATA
* wim
)
870 TRACE("(%p)\n", wim
);
872 ret
= waveInClose(wim
->u
.in
.hInnerWave
);
873 if (ret
== MMSYSERR_NOERROR
) {
874 if (wim
->hAcmStream
) {
875 ret
= acmStreamClose(wim
->hAcmStream
, 0);
877 if (ret
== MMSYSERR_NOERROR
) {
878 HeapFree(GetProcessHeap(), 0, wim
);
884 static DWORD
widAddBuffer(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
886 PACMSTREAMHEADER ash
;
887 LPWAVEHDR lpWaveHdrSrc
;
889 TRACE("(%p %p %08x)\n", wim
, lpWaveHdrDst
, dwParam2
);
891 if (!wim
->hAcmStream
) {
892 return waveInAddBuffer(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
895 lpWaveHdrDst
->dwFlags
|= WHDR_INQUEUE
;
896 ash
= (PACMSTREAMHEADER
)lpWaveHdrDst
->reserved
;
898 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
899 return waveInAddBuffer(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
902 static DWORD
widPrepare(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
904 PACMSTREAMHEADER ash
;
907 LPWAVEHDR lpWaveHdrSrc
;
909 TRACE("(%p %p %08x)\n", wim
, lpWaveHdrDst
, dwParam2
);
911 if (!wim
->hAcmStream
) {
912 return waveInPrepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
914 if (acmStreamSize(wim
->hAcmStream
, lpWaveHdrDst
->dwBufferLength
, &size
,
915 ACM_STREAMSIZEF_DESTINATION
) != MMSYSERR_NOERROR
) {
916 WARN("acmStreamSize failed\n");
917 return MMSYSERR_ERROR
;
920 ash
= HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
) + size
);
923 return MMSYSERR_NOMEM
;
926 ash
->cbStruct
= sizeof(*ash
);
928 ash
->dwUser
= (DWORD_PTR
)lpWaveHdrDst
;
929 ash
->pbSrc
= (LPBYTE
)ash
+ sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
);
930 ash
->cbSrcLength
= size
;
931 /* ash->cbSrcLengthUsed */
932 ash
->dwSrcUser
= 0L; /* FIXME ? */
933 ash
->pbDst
= (LPBYTE
)lpWaveHdrDst
->lpData
;
934 ash
->cbDstLength
= lpWaveHdrDst
->dwBufferLength
;
935 /* ash->cbDstLengthUsed */
936 ash
->dwDstUser
= lpWaveHdrDst
->dwUser
; /* FIXME ? */
937 dwRet
= acmStreamPrepareHeader(wim
->hAcmStream
, ash
, 0L);
938 if (dwRet
!= MMSYSERR_NOERROR
) {
939 WARN("acmStreamPrepareHeader failed\n");
943 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
944 lpWaveHdrSrc
->lpData
= (LPSTR
)ash
->pbSrc
;
945 lpWaveHdrSrc
->dwBufferLength
= size
; /* conversion is not done yet */
946 lpWaveHdrSrc
->dwFlags
= 0;
947 lpWaveHdrSrc
->dwLoops
= 0;
948 dwRet
= waveInPrepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
949 if (dwRet
!= MMSYSERR_NOERROR
) {
950 WARN("waveInPrepareHeader failed\n");
954 lpWaveHdrDst
->reserved
= (DWORD_PTR
)ash
;
955 lpWaveHdrDst
->dwFlags
= WHDR_PREPARED
;
957 return MMSYSERR_NOERROR
;
959 TRACE("=> (%d)\n", dwRet
);
960 HeapFree(GetProcessHeap(), 0, ash
);
964 static DWORD
widUnprepare(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
966 PACMSTREAMHEADER ash
;
967 LPWAVEHDR lpWaveHdrSrc
;
968 DWORD dwRet1
, dwRet2
;
970 TRACE("(%p %p %08x)\n", wim
, lpWaveHdrDst
, dwParam2
);
972 if (!wim
->hAcmStream
) {
973 return waveInUnprepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
975 ash
= (PACMSTREAMHEADER
)lpWaveHdrDst
->reserved
;
976 dwRet1
= acmStreamUnprepareHeader(wim
->hAcmStream
, ash
, 0L);
978 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
979 dwRet2
= waveInUnprepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
981 HeapFree(GetProcessHeap(), 0, ash
);
983 lpWaveHdrDst
->dwFlags
&= ~WHDR_PREPARED
;
984 return (dwRet1
== MMSYSERR_NOERROR
) ? dwRet2
: dwRet1
;
987 static DWORD
widGetPosition(WAVEMAPDATA
* wim
, LPMMTIME lpTime
, DWORD dwParam2
)
991 TRACE("(%p %p %08x)\n", wim
, lpTime
, dwParam2
);
995 /* For TIME_MS, we're going to recalculate using TIME_BYTES */
996 if (lpTime
->wType
== TIME_MS
)
997 timepos
.wType
= TIME_BYTES
;
999 /* This can change timepos.wType if the requested type is not supported */
1000 val
= waveInGetPosition(wim
->u
.in
.hInnerWave
, &timepos
, dwParam2
);
1002 if (timepos
.wType
== TIME_BYTES
)
1004 DWORD dwInnerSamplesPerOuter
= wim
->nSamplesPerSecInner
/ wim
->nSamplesPerSecOuter
;
1005 if (dwInnerSamplesPerOuter
> 0)
1007 DWORD dwInnerBytesPerSample
= wim
->avgSpeedInner
/ wim
->nSamplesPerSecInner
;
1008 DWORD dwInnerBytesPerOuterSample
= dwInnerBytesPerSample
* dwInnerSamplesPerOuter
;
1009 DWORD remainder
= 0;
1011 /* If we are up sampling (going from lower sample rate to higher),
1012 ** we need to make a special accommodation for times when we've
1013 ** written a partial output sample. This happens frequently
1014 ** to us because we use msacm to do our up sampling, and it
1015 ** will up sample on an unaligned basis.
1016 ** For example, if you convert a 2 byte wide 8,000 'outer'
1017 ** buffer to a 2 byte wide 48,000 inner device, you would
1018 ** expect 2 bytes of input to produce 12 bytes of output.
1019 ** Instead, msacm will produce 8 bytes of output.
1020 ** But reporting our position as 1 byte of output is
1021 ** nonsensical; the output buffer position needs to be
1022 ** aligned on outer sample size, and aggressively rounded up.
1024 remainder
= timepos
.u
.cb
% dwInnerBytesPerOuterSample
;
1027 timepos
.u
.cb
-= remainder
;
1028 timepos
.u
.cb
+= dwInnerBytesPerOuterSample
;
1032 lpTime
->u
.cb
= MulDiv(timepos
.u
.cb
, wim
->avgSpeedOuter
, wim
->avgSpeedInner
);
1034 /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
1035 if (lpTime
->wType
== TIME_MS
)
1036 lpTime
->u
.ms
= MulDiv(lpTime
->u
.cb
, 1000, wim
->avgSpeedOuter
);
1038 lpTime
->wType
= TIME_BYTES
;
1040 else if (lpTime
->wType
== TIME_SAMPLES
&& timepos
.wType
== TIME_SAMPLES
)
1041 lpTime
->u
.sample
= MulDiv(timepos
.u
.sample
, wim
->nSamplesPerSecOuter
, wim
->nSamplesPerSecInner
);
1043 /* other time types don't require conversion */
1044 lpTime
->u
= timepos
.u
;
1049 static DWORD
widGetDevCaps(UINT wDevID
, WAVEMAPDATA
* wim
, LPWAVEINCAPSW lpWaveCaps
, DWORD dwParam2
)
1051 TRACE("(%04x, %p %p %08x)\n", wDevID
, wim
, lpWaveCaps
, dwParam2
);
1053 /* if opened low driver, forward message */
1054 if (WAVEMAP_IsData(wim
))
1055 return waveInGetDevCapsW((UINT_PTR
)wim
->u
.in
.hInnerWave
, lpWaveCaps
, dwParam2
);
1056 /* else if no drivers, nothing to map so return bad device */
1057 if (waveInGetNumDevs() == 0) {
1058 WARN("bad device id\n");
1059 return MMSYSERR_BADDEVICEID
;
1061 /* otherwise, return caps of mapper itself */
1062 if (wDevID
== (UINT
)-1 || wDevID
== (UINT16
)-1) {
1066 wic
.vDriverVersion
= 0x0001;
1067 lstrcpyW(wic
.szPname
, L
"Wine wave in mapper");
1069 WAVE_FORMAT_96M08
| WAVE_FORMAT_96S08
| WAVE_FORMAT_96M16
| WAVE_FORMAT_96S16
|
1070 WAVE_FORMAT_48M08
| WAVE_FORMAT_48S08
| WAVE_FORMAT_48M16
| WAVE_FORMAT_48S16
|
1071 WAVE_FORMAT_4M08
| WAVE_FORMAT_4S08
| WAVE_FORMAT_4M16
| WAVE_FORMAT_4S16
|
1072 WAVE_FORMAT_2M08
| WAVE_FORMAT_2S08
| WAVE_FORMAT_2M16
| WAVE_FORMAT_2S16
|
1073 WAVE_FORMAT_1M08
| WAVE_FORMAT_1S08
| WAVE_FORMAT_1M16
| WAVE_FORMAT_1S16
;
1076 memcpy(lpWaveCaps
, &wic
, min(dwParam2
, sizeof(wic
)));
1078 return MMSYSERR_NOERROR
;
1080 ERR("This shouldn't happen\n");
1081 return MMSYSERR_ERROR
;
1084 static DWORD
widStop(WAVEMAPDATA
* wim
)
1086 TRACE("(%p)\n", wim
);
1088 return waveInStop(wim
->u
.in
.hInnerWave
);
1091 static DWORD
widStart(WAVEMAPDATA
* wim
)
1093 TRACE("(%p)\n", wim
);
1095 return waveInStart(wim
->u
.in
.hInnerWave
);
1098 static DWORD
widReset(WAVEMAPDATA
* wim
)
1100 TRACE("(%p)\n", wim
);
1102 return waveInReset(wim
->u
.in
.hInnerWave
);
1105 static DWORD
widMapperStatus(WAVEMAPDATA
* wim
, DWORD flags
, LPVOID ptr
)
1108 DWORD ret
= MMSYSERR_NOTSUPPORTED
;
1110 TRACE("(%p %08x %p)\n", wim
, flags
, ptr
);
1113 case WAVEIN_MAPPER_STATUS_DEVICE
:
1114 ret
= waveInGetID(wim
->u
.in
.hInnerWave
, &id
);
1117 case WAVEIN_MAPPER_STATUS_MAPPED
:
1118 FIXME("Unsupported yet flag=%d\n", flags
);
1119 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
1121 case WAVEIN_MAPPER_STATUS_FORMAT
:
1122 FIXME("Unsupported flag=%d\n", flags
);
1123 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
1124 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
1127 FIXME("Unsupported flag=%d\n", flags
);
1134 static DWORD
widMapperReconfigure(WAVEMAPDATA
* wim
, DWORD dwParam1
, DWORD dwParam2
)
1136 FIXME("(%p %08x %08x) stub!\n", wim
, dwParam1
, dwParam2
);
1138 return MMSYSERR_NOERROR
;
1141 /**************************************************************************
1142 * widMessage (MSACM.@)
1144 DWORD WINAPI
WAVEMAP_widMessage(WORD wDevID
, WORD wMsg
, DWORD_PTR dwUser
,
1145 DWORD_PTR dwParam1
, DWORD_PTR dwParam2
)
1147 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1148 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1155 /* FIXME: Pretend this is supported */
1158 case WIDM_OPEN
: return widOpen ((DWORD_PTR
*)dwUser
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
1159 case WIDM_CLOSE
: return widClose ((WAVEMAPDATA
*)dwUser
);
1161 case WIDM_ADDBUFFER
: return widAddBuffer ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1162 case WIDM_PREPARE
: return widPrepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1163 case WIDM_UNPREPARE
: return widUnprepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1164 case WIDM_GETDEVCAPS
: return widGetDevCaps (wDevID
, (WAVEMAPDATA
*)dwUser
, (LPWAVEINCAPSW
)dwParam1
, dwParam2
);
1165 case WIDM_GETNUMDEVS
: return 1;
1166 case WIDM_GETPOS
: return widGetPosition ((WAVEMAPDATA
*)dwUser
, (LPMMTIME
)dwParam1
, dwParam2
);
1167 case WIDM_RESET
: return widReset ((WAVEMAPDATA
*)dwUser
);
1168 case WIDM_START
: return widStart ((WAVEMAPDATA
*)dwUser
);
1169 case WIDM_STOP
: return widStop ((WAVEMAPDATA
*)dwUser
);
1170 case WIDM_MAPPER_STATUS
: return widMapperStatus ((WAVEMAPDATA
*)dwUser
, dwParam1
, (LPVOID
)dwParam2
);
1171 case DRVM_MAPPER_RECONFIGURE
: return widMapperReconfigure((WAVEMAPDATA
*)dwUser
, dwParam1
, dwParam2
);
1172 /* known but not supported */
1173 case DRV_QUERYDEVICEINTERFACESIZE
:
1174 case DRV_QUERYDEVICEINTERFACE
:
1175 return MMSYSERR_NOTSUPPORTED
;
1177 FIXME("unknown message %u!\n", wMsg
);
1179 return MMSYSERR_NOTSUPPORTED
;
1182 /*======================================================================*
1184 *======================================================================*/
1186 static struct WINE_WAVEMAP
* oss
= NULL
;
1188 /**************************************************************************
1189 * WAVEMAP_drvOpen [internal]
1191 static LRESULT
WAVEMAP_drvOpen(LPSTR str
)
1193 TRACE("(%p)\n", str
);
1198 /* I know, this is ugly, but who cares... */
1199 oss
= (struct WINE_WAVEMAP
*)1;
1203 /**************************************************************************
1204 * WAVEMAP_drvClose [internal]
1206 static LRESULT
WAVEMAP_drvClose(DWORD_PTR dwDevID
)
1208 TRACE("(%08lx)\n", dwDevID
);
1217 /**************************************************************************
1218 * DriverProc (MSACM.@)
1220 LRESULT CALLBACK
WAVEMAP_DriverProc(DWORD_PTR dwDevID
, HDRVR hDriv
, UINT wMsg
,
1221 LPARAM dwParam1
, LPARAM dwParam2
)
1223 TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
1224 dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1227 case DRV_LOAD
: return 1;
1228 case DRV_FREE
: return 1;
1229 case DRV_OPEN
: return WAVEMAP_drvOpen((LPSTR
)dwParam1
);
1230 case DRV_CLOSE
: return WAVEMAP_drvClose(dwDevID
);
1231 case DRV_ENABLE
: return 1;
1232 case DRV_DISABLE
: return 1;
1233 case DRV_QUERYCONFIGURE
: return 1;
1234 case DRV_CONFIGURE
: MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK
); return 1;
1235 case DRV_INSTALL
: return DRVCNF_RESTART
;
1236 case DRV_REMOVE
: return DRVCNF_RESTART
;
1238 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);