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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * + better protection against evilish dwUser parameters
24 * + use asynchronous ACM conversion
25 * + don't use callback functions when none is required in open
26 * + the buffer sizes may not be accurate, so there may be some
27 * remaining bytes in src and dst buffers after ACM conversions...
28 * those should be taken care of...
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(wavemap
);
45 typedef struct tagWAVEMAPDATA
{
46 struct tagWAVEMAPDATA
* self
;
57 HACMSTREAM hAcmStream
;
58 /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */
60 DWORD dwClientInstance
;
62 /* ratio to compute position from a PCM playback to any format */
65 /* channel size of inner and outer */
66 DWORD nSamplesPerSecOuter
;
67 DWORD nSamplesPerSecInner
;
70 static BOOL
WAVEMAP_IsData(WAVEMAPDATA
* wm
)
72 return (!IsBadReadPtr(wm
, sizeof(WAVEMAPDATA
)) && wm
->self
== wm
);
75 /*======================================================================*
77 *======================================================================*/
79 static void CALLBACK
wodCallback(HWAVEOUT hWave
, UINT uMsg
, DWORD dwInstance
,
80 DWORD dwParam1
, DWORD dwParam2
)
82 WAVEMAPDATA
* wom
= (WAVEMAPDATA
*)dwInstance
;
84 TRACE("(%p %u %ld %lx %lx);\n", hWave
, uMsg
, dwInstance
, dwParam1
, dwParam2
);
86 if (!WAVEMAP_IsData(wom
)) {
91 if (hWave
!= wom
->u
.out
.hInnerWave
&& uMsg
!= WOM_OPEN
)
92 ERR("Shouldn't happen (%p %p)\n", hWave
, wom
->u
.out
.hInnerWave
);
97 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
100 if (wom
->hAcmStream
) {
101 LPWAVEHDR lpWaveHdrDst
= (LPWAVEHDR
)dwParam1
;
102 PACMSTREAMHEADER ash
= (PACMSTREAMHEADER
)((LPSTR
)lpWaveHdrDst
- sizeof(ACMSTREAMHEADER
));
103 LPWAVEHDR lpWaveHdrSrc
= (LPWAVEHDR
)ash
->dwUser
;
105 lpWaveHdrSrc
->dwFlags
&= ~WHDR_INQUEUE
;
106 lpWaveHdrSrc
->dwFlags
|= WHDR_DONE
;
107 dwParam1
= (DWORD
)lpWaveHdrSrc
;
111 ERR("Unknown msg %u\n", uMsg
);
114 DriverCallback(wom
->dwCallback
, HIWORD(wom
->dwFlags
), (HDRVR
)wom
->u
.out
.hOuterWave
,
115 uMsg
, wom
->dwClientInstance
, dwParam1
, dwParam2
);
118 /******************************************************************
123 static DWORD
wodOpenHelper(WAVEMAPDATA
* wom
, UINT idx
,
124 LPWAVEOPENDESC lpDesc
, LPWAVEFORMATEX lpwfx
,
129 TRACE("(%p %04x %p %p %08lx)\n", wom
, idx
, lpDesc
, lpwfx
, dwFlags
);
131 /* destination is always PCM, so the formulas below apply */
132 lpwfx
->nBlockAlign
= (lpwfx
->nChannels
* lpwfx
->wBitsPerSample
) / 8;
133 lpwfx
->nAvgBytesPerSec
= lpwfx
->nSamplesPerSec
* lpwfx
->nBlockAlign
;
134 if (dwFlags
& WAVE_FORMAT_QUERY
) {
135 ret
= acmStreamOpen(NULL
, 0, lpDesc
->lpFormat
, lpwfx
, NULL
, 0L, 0L, ACM_STREAMOPENF_QUERY
);
137 ret
= acmStreamOpen(&wom
->hAcmStream
, 0, lpDesc
->lpFormat
, lpwfx
, NULL
, 0L, 0L, 0L);
139 if (ret
== MMSYSERR_NOERROR
) {
140 ret
= waveOutOpen(&wom
->u
.out
.hInnerWave
, idx
, lpwfx
, (DWORD
)wodCallback
,
141 (DWORD
)wom
, (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
);
142 if (ret
!= MMSYSERR_NOERROR
&& !(dwFlags
& WAVE_FORMAT_QUERY
)) {
143 acmStreamClose(wom
->hAcmStream
, 0);
147 TRACE("ret = %08lx\n", ret
);
151 static DWORD
wodOpen(LPDWORD lpdwUser
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
155 WAVEMAPDATA
* wom
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA
));
158 TRACE("(%p %p %08lx)\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
, (DWORD
)wodCallback
,
191 (DWORD
)wom
, (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
| WAVE_FORMAT_DIRECT
) == MMSYSERR_NOERROR
) {
197 if ((dwFlags
& WAVE_FORMAT_DIRECT
) == 0 && lpDesc
->lpFormat
->wFormatTag
== WAVE_FORMAT_PCM
) {
200 wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
201 wfx
.cbSize
= 0; /* normally, this field is not used for PCM format, just in case */
202 /* try some ACM stuff */
204 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
205 switch (res=wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
206 case MMSYSERR_NOERROR: wom->avgSpeedInner = wfx.nAvgBytesPerSec; wom->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \
207 case WAVERR_BADFORMAT: break; \
208 default: goto error; \
211 /* Our resampling algorithm is quite primitive so first try
212 * to just change the bit depth and number of channels
214 for (i
= ndlo
; i
< ndhi
; i
++) {
215 wfx
.nSamplesPerSec
=lpDesc
->lpFormat
->nSamplesPerSec
;
216 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
217 TRY(wfx
.nSamplesPerSec
, 16);
218 TRY(wfx
.nSamplesPerSec
, 8);
220 TRY(wfx
.nSamplesPerSec
, 16);
221 TRY(wfx
.nSamplesPerSec
, 8);
224 for (i
= ndlo
; i
< ndhi
; i
++) {
225 /* first try with same stereo/mono option as source */
226 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
233 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
241 /* first try with same stereo/mono option as source */
242 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
249 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
260 HeapFree(GetProcessHeap(), 0, wom
);
261 WARN("ret = WAVERR_BADFORMAT\n");
262 return WAVERR_BADFORMAT
;
265 if (dwFlags
& WAVE_FORMAT_QUERY
) {
267 HeapFree(GetProcessHeap(), 0, wom
);
269 *lpdwUser
= (DWORD
)wom
;
271 return MMSYSERR_NOERROR
;
273 HeapFree(GetProcessHeap(), 0, wom
);
274 if (res
==ACMERR_NOTPOSSIBLE
) {
275 WARN("ret = WAVERR_BADFORMAT\n");
276 return WAVERR_BADFORMAT
;
278 WARN("ret = 0x%08lx\n", res
);
282 static DWORD
wodClose(WAVEMAPDATA
* wom
)
286 TRACE("(%p)\n", wom
);
288 ret
= waveOutClose(wom
->u
.out
.hInnerWave
);
289 if (ret
== MMSYSERR_NOERROR
) {
290 if (wom
->hAcmStream
) {
291 ret
= acmStreamClose(wom
->hAcmStream
, 0);
293 if (ret
== MMSYSERR_NOERROR
) {
294 HeapFree(GetProcessHeap(), 0, wom
);
300 static DWORD
wodWrite(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
302 PACMSTREAMHEADER ash
;
303 LPWAVEHDR lpWaveHdrDst
;
305 TRACE("(%p %p %08lx)\n", wom
, lpWaveHdrSrc
, dwParam2
);
307 if (!wom
->hAcmStream
) {
308 return waveOutWrite(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
311 lpWaveHdrSrc
->dwFlags
|= WHDR_INQUEUE
;
312 ash
= (PACMSTREAMHEADER
)lpWaveHdrSrc
->reserved
;
313 /* acmStreamConvert will actually check that the new size is less than initial size */
314 ash
->cbSrcLength
= lpWaveHdrSrc
->dwBufferLength
;
315 if (acmStreamConvert(wom
->hAcmStream
, ash
, 0L) != MMSYSERR_NOERROR
) {
316 WARN("acmStreamConvert failed\n");
317 return MMSYSERR_ERROR
;
320 lpWaveHdrDst
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
321 if (ash
->cbSrcLength
> ash
->cbSrcLengthUsed
)
322 FIXME("Not all src buffer has been written, expect bogus sound\n");
323 else if (ash
->cbSrcLength
< ash
->cbSrcLengthUsed
)
324 ERR("CoDec has read more data than it is allowed to\n");
326 if (ash
->cbDstLengthUsed
== 0) {
327 /* something went wrong in decoding */
328 FIXME("Got 0 length\n");
329 return MMSYSERR_ERROR
;
331 lpWaveHdrDst
->dwBufferLength
= ash
->cbDstLengthUsed
;
332 return waveOutWrite(wom
->u
.out
.hInnerWave
, lpWaveHdrDst
, sizeof(*lpWaveHdrDst
));
335 static DWORD
wodPrepare(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
337 PACMSTREAMHEADER ash
;
340 LPWAVEHDR lpWaveHdrDst
;
342 TRACE("(%p %p %08lx)\n", wom
, lpWaveHdrSrc
, dwParam2
);
344 if (!wom
->hAcmStream
)
345 return waveOutPrepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
347 if (acmStreamSize(wom
->hAcmStream
, lpWaveHdrSrc
->dwBufferLength
, &size
, ACM_STREAMSIZEF_SOURCE
) != MMSYSERR_NOERROR
) {
348 WARN("acmStreamSize failed\n");
349 return MMSYSERR_ERROR
;
352 ash
= HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
) + size
);
355 return MMSYSERR_NOMEM
;
358 ash
->cbStruct
= sizeof(*ash
);
360 ash
->dwUser
= (DWORD
)lpWaveHdrSrc
;
361 ash
->pbSrc
= (LPBYTE
)lpWaveHdrSrc
->lpData
;
362 ash
->cbSrcLength
= lpWaveHdrSrc
->dwBufferLength
;
363 /* ash->cbSrcLengthUsed */
364 ash
->dwSrcUser
= lpWaveHdrSrc
->dwUser
; /* FIXME ? */
365 ash
->pbDst
= (LPBYTE
)ash
+ sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
);
366 ash
->cbDstLength
= size
;
367 /* ash->cbDstLengthUsed */
368 ash
->dwDstUser
= 0; /* FIXME ? */
369 dwRet
= acmStreamPrepareHeader(wom
->hAcmStream
, ash
, 0L);
370 if (dwRet
!= MMSYSERR_NOERROR
) {
371 WARN("acmStreamPrepareHeader failed\n");
375 lpWaveHdrDst
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
376 lpWaveHdrDst
->lpData
= (LPSTR
)ash
->pbDst
;
377 lpWaveHdrDst
->dwBufferLength
= size
; /* conversion is not done yet */
378 lpWaveHdrDst
->dwFlags
= 0;
379 lpWaveHdrDst
->dwLoops
= 0;
380 dwRet
= waveOutPrepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrDst
, sizeof(*lpWaveHdrDst
));
381 if (dwRet
!= MMSYSERR_NOERROR
) {
382 WARN("waveOutPrepareHeader failed\n");
386 lpWaveHdrSrc
->reserved
= (DWORD
)ash
;
387 lpWaveHdrSrc
->dwFlags
= WHDR_PREPARED
;
389 return MMSYSERR_NOERROR
;
391 TRACE("=> (%ld)\n", dwRet
);
392 HeapFree(GetProcessHeap(), 0, ash
);
396 static DWORD
wodUnprepare(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
398 PACMSTREAMHEADER ash
;
399 LPWAVEHDR lpWaveHdrDst
;
400 DWORD dwRet1
, dwRet2
;
402 TRACE("(%p %p %08lx)\n", wom
, lpWaveHdrSrc
, dwParam2
);
404 if (!wom
->hAcmStream
) {
405 return waveOutUnprepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
407 ash
= (PACMSTREAMHEADER
)lpWaveHdrSrc
->reserved
;
408 dwRet1
= acmStreamUnprepareHeader(wom
->hAcmStream
, ash
, 0L);
410 lpWaveHdrDst
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
411 dwRet2
= waveOutUnprepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrDst
, sizeof(*lpWaveHdrDst
));
413 HeapFree(GetProcessHeap(), 0, ash
);
415 lpWaveHdrSrc
->dwFlags
&= ~WHDR_PREPARED
;
416 return (dwRet1
== MMSYSERR_NOERROR
) ? dwRet2
: dwRet1
;
419 static DWORD
wodGetPosition(WAVEMAPDATA
* wom
, LPMMTIME lpTime
, DWORD dwParam2
)
423 TRACE("(%p %p %08lx)\n", wom
, lpTime
, dwParam2
);
425 memcpy(&timepos
, lpTime
, sizeof(timepos
));
427 /* For TIME_MS, we're going to recalculate using TIME_BYTES */
428 if (lpTime
->wType
== TIME_MS
)
429 timepos
.wType
= TIME_BYTES
;
431 /* This can change timepos.wType if the requested type is not supported */
432 val
= waveOutGetPosition(wom
->u
.out
.hInnerWave
, &timepos
, dwParam2
);
434 if (timepos
.wType
== TIME_BYTES
)
436 DWORD dwInnerSamplesPerOuter
= wom
->nSamplesPerSecInner
/ wom
->nSamplesPerSecOuter
;
437 if (dwInnerSamplesPerOuter
> 0)
439 DWORD dwInnerBytesPerSample
= wom
->avgSpeedInner
/ wom
->nSamplesPerSecInner
;
440 DWORD dwInnerBytesPerOuterSample
= dwInnerBytesPerSample
* dwInnerSamplesPerOuter
;
443 /* If we are up sampling (going from lower sample rate to higher),
444 ** we need to make a special accomodation for times when we've
445 ** written a partial output sample. This happens frequently
446 ** to us because we use msacm to do our up sampling, and it
447 ** will up sample on an unaligned basis.
448 ** For example, if you convert a 2 byte wide 8,000 'outer'
449 ** buffer to a 2 byte wide 48,000 inner device, you would
450 ** expect 2 bytes of input to produce 12 bytes of output.
451 ** Instead, msacm will produce 8 bytes of output.
452 ** But reporting our position as 1 byte of output is
453 ** nonsensical; the output buffer position needs to be
454 ** aligned on outer sample size, and aggressively rounded up.
456 remainder
= timepos
.u
.cb
% dwInnerBytesPerOuterSample
;
459 timepos
.u
.cb
-= remainder
;
460 timepos
.u
.cb
+= dwInnerBytesPerOuterSample
;
464 lpTime
->u
.cb
= MulDiv(timepos
.u
.cb
, wom
->avgSpeedOuter
, wom
->avgSpeedInner
);
466 /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
467 if (lpTime
->wType
== TIME_MS
)
468 lpTime
->u
.ms
= MulDiv(lpTime
->u
.cb
, 1000, wom
->avgSpeedOuter
);
470 lpTime
->wType
= TIME_BYTES
;
472 else if (lpTime
->wType
== TIME_SAMPLES
&& timepos
.wType
== TIME_SAMPLES
)
473 lpTime
->u
.sample
= MulDiv(timepos
.u
.sample
, wom
->nSamplesPerSecOuter
, wom
->nSamplesPerSecInner
);
475 /* other time types don't require conversion */
476 lpTime
->u
= timepos
.u
;
481 static DWORD
wodGetDevCaps(UINT wDevID
, WAVEMAPDATA
* wom
, LPWAVEOUTCAPSW lpWaveCaps
, DWORD dwParam2
)
483 static const WCHAR name
[] = {'W','i','n','e',' ','w','a','v','e',' ','o','u','t',' ','m','a','p','p','e','r',0};
485 TRACE("(%04x %p %p %08lx)\n",wDevID
, wom
, lpWaveCaps
, dwParam2
);
487 /* if opened low driver, forward message */
488 if (WAVEMAP_IsData(wom
))
489 return waveOutGetDevCapsW((UINT
)wom
->u
.out
.hInnerWave
, lpWaveCaps
, dwParam2
);
490 /* else if no drivers, nothing to map so return bad device */
491 if (waveOutGetNumDevs() == 0) {
492 WARN("bad device id\n");
493 return MMSYSERR_BADDEVICEID
;
495 /* otherwise, return caps of mapper itself */
496 if (wDevID
== (UINT
)-1 || wDevID
== (UINT16
)-1) {
500 woc
.vDriverVersion
= 0x0100;
501 lstrcpyW(woc
.szPname
, name
);
503 WAVE_FORMAT_96M08
| WAVE_FORMAT_96S08
| WAVE_FORMAT_96M16
| WAVE_FORMAT_96S16
|
504 WAVE_FORMAT_48M08
| WAVE_FORMAT_48S08
| WAVE_FORMAT_48M16
| WAVE_FORMAT_48S16
|
505 WAVE_FORMAT_4M08
| WAVE_FORMAT_4S08
| WAVE_FORMAT_4M16
| WAVE_FORMAT_4S16
|
506 WAVE_FORMAT_2M08
| WAVE_FORMAT_2S08
| WAVE_FORMAT_2M16
| WAVE_FORMAT_2S16
|
507 WAVE_FORMAT_1M08
| WAVE_FORMAT_1S08
| WAVE_FORMAT_1M16
| WAVE_FORMAT_1S16
;
509 woc
.dwSupport
= WAVECAPS_VOLUME
| WAVECAPS_LRVOLUME
;
510 memcpy(lpWaveCaps
, &woc
, min(dwParam2
, sizeof(woc
)));
512 return MMSYSERR_NOERROR
;
514 ERR("This shouldn't happen\n");
515 return MMSYSERR_ERROR
;
518 static DWORD
wodGetVolume(UINT wDevID
, WAVEMAPDATA
* wom
, LPDWORD lpVol
)
520 TRACE("(%04x %p %p)\n",wDevID
, wom
, lpVol
);
522 if (WAVEMAP_IsData(wom
))
523 return waveOutGetVolume(wom
->u
.out
.hInnerWave
, lpVol
);
524 return MMSYSERR_NOERROR
;
527 static DWORD
wodSetVolume(UINT wDevID
, WAVEMAPDATA
* wom
, DWORD vol
)
529 TRACE("(%04x %p %08lx)\n",wDevID
, wom
, vol
);
531 if (WAVEMAP_IsData(wom
))
532 return waveOutSetVolume(wom
->u
.out
.hInnerWave
, vol
);
533 return MMSYSERR_NOERROR
;
536 static DWORD
wodPause(WAVEMAPDATA
* wom
)
540 return waveOutPause(wom
->u
.out
.hInnerWave
);
543 static DWORD
wodRestart(WAVEMAPDATA
* wom
)
547 return waveOutRestart(wom
->u
.out
.hInnerWave
);
550 static DWORD
wodReset(WAVEMAPDATA
* wom
)
554 return waveOutReset(wom
->u
.out
.hInnerWave
);
557 static DWORD
wodBreakLoop(WAVEMAPDATA
* wom
)
561 return waveOutBreakLoop(wom
->u
.out
.hInnerWave
);
564 static DWORD
wodMapperStatus(WAVEMAPDATA
* wom
, DWORD flags
, LPVOID ptr
)
567 DWORD ret
= MMSYSERR_NOTSUPPORTED
;
569 TRACE("(%p %08lx %p)\n",wom
, flags
, ptr
);
572 case WAVEOUT_MAPPER_STATUS_DEVICE
:
573 ret
= waveOutGetID(wom
->u
.out
.hInnerWave
, &id
);
576 case WAVEOUT_MAPPER_STATUS_MAPPED
:
577 FIXME("Unsupported flag=%ld\n", flags
);
578 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
580 case WAVEOUT_MAPPER_STATUS_FORMAT
:
581 FIXME("Unsupported flag=%ld\n", flags
);
582 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
586 FIXME("Unsupported flag=%ld\n", flags
);
593 static DWORD
wodMapperReconfigure(WAVEMAPDATA
* wom
, DWORD dwParam1
, DWORD dwParam2
)
595 FIXME("(%p %08lx %08lx) stub!\n", wom
, dwParam1
, dwParam2
);
597 return MMSYSERR_NOERROR
;
600 /**************************************************************************
601 * wodMessage (MSACM.@)
603 DWORD WINAPI
WAVEMAP_wodMessage(UINT wDevID
, UINT wMsg
, DWORD dwUser
,
604 DWORD dwParam1
, DWORD dwParam2
)
606 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
607 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
614 /* FIXME: Pretend this is supported */
616 case WODM_OPEN
: return wodOpen ((LPDWORD
)dwUser
, (LPWAVEOPENDESC
)dwParam1
,dwParam2
);
617 case WODM_CLOSE
: return wodClose ((WAVEMAPDATA
*)dwUser
);
618 case WODM_WRITE
: return wodWrite ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
619 case WODM_PAUSE
: return wodPause ((WAVEMAPDATA
*)dwUser
);
620 case WODM_GETPOS
: return wodGetPosition ((WAVEMAPDATA
*)dwUser
, (LPMMTIME
)dwParam1
, dwParam2
);
621 case WODM_BREAKLOOP
: return wodBreakLoop ((WAVEMAPDATA
*)dwUser
);
622 case WODM_PREPARE
: return wodPrepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
623 case WODM_UNPREPARE
: return wodUnprepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
624 case WODM_GETDEVCAPS
: return wodGetDevCaps (wDevID
, (WAVEMAPDATA
*)dwUser
, (LPWAVEOUTCAPSW
)dwParam1
,dwParam2
);
625 case WODM_GETNUMDEVS
: return 1;
626 case WODM_GETPITCH
: return MMSYSERR_NOTSUPPORTED
;
627 case WODM_SETPITCH
: return MMSYSERR_NOTSUPPORTED
;
628 case WODM_GETPLAYBACKRATE
: return MMSYSERR_NOTSUPPORTED
;
629 case WODM_SETPLAYBACKRATE
: return MMSYSERR_NOTSUPPORTED
;
630 case WODM_GETVOLUME
: return wodGetVolume (wDevID
, (WAVEMAPDATA
*)dwUser
, (LPDWORD
)dwParam1
);
631 case WODM_SETVOLUME
: return wodSetVolume (wDevID
, (WAVEMAPDATA
*)dwUser
, dwParam1
);
632 case WODM_RESTART
: return wodRestart ((WAVEMAPDATA
*)dwUser
);
633 case WODM_RESET
: return wodReset ((WAVEMAPDATA
*)dwUser
);
634 case WODM_MAPPER_STATUS
: return wodMapperStatus ((WAVEMAPDATA
*)dwUser
, dwParam1
, (LPVOID
)dwParam2
);
635 case DRVM_MAPPER_RECONFIGURE
: return wodMapperReconfigure((WAVEMAPDATA
*)dwUser
, dwParam1
, dwParam2
);
636 /* known but not supported */
637 case DRV_QUERYDEVICEINTERFACESIZE
:
638 case DRV_QUERYDEVICEINTERFACE
:
639 return MMSYSERR_NOTSUPPORTED
;
641 FIXME("unknown message %d!\n", wMsg
);
643 return MMSYSERR_NOTSUPPORTED
;
646 /*======================================================================*
648 *======================================================================*/
650 static void CALLBACK
widCallback(HWAVEIN hWave
, UINT uMsg
, DWORD dwInstance
,
651 DWORD dwParam1
, DWORD dwParam2
)
653 WAVEMAPDATA
* wim
= (WAVEMAPDATA
*)dwInstance
;
655 TRACE("(%p %u %ld %lx %lx);\n", hWave
, uMsg
, dwInstance
, dwParam1
, dwParam2
);
657 if (!WAVEMAP_IsData(wim
)) {
662 if (hWave
!= wim
->u
.in
.hInnerWave
&& uMsg
!= WIM_OPEN
)
663 ERR("Shouldn't happen (%p %p)\n", hWave
, wim
->u
.in
.hInnerWave
);
668 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
671 if (wim
->hAcmStream
) {
672 LPWAVEHDR lpWaveHdrSrc
= (LPWAVEHDR
)dwParam1
;
673 PACMSTREAMHEADER ash
= (PACMSTREAMHEADER
)((LPSTR
)lpWaveHdrSrc
- sizeof(ACMSTREAMHEADER
));
674 LPWAVEHDR lpWaveHdrDst
= (LPWAVEHDR
)ash
->dwUser
;
676 /* convert data just gotten from waveIn into requested format */
677 if (acmStreamConvert(wim
->hAcmStream
, ash
, 0L) != MMSYSERR_NOERROR
) {
678 ERR("ACM conversion failed\n");
681 TRACE("Converted %ld bytes into %ld\n", ash
->cbSrcLengthUsed
, ash
->cbDstLengthUsed
);
683 /* and setup the wavehdr to return accordingly */
684 lpWaveHdrDst
->dwFlags
&= ~WHDR_INQUEUE
;
685 lpWaveHdrDst
->dwFlags
|= WHDR_DONE
;
686 lpWaveHdrDst
->dwBytesRecorded
= ash
->cbDstLengthUsed
;
687 dwParam1
= (DWORD
)lpWaveHdrDst
;
691 ERR("Unknown msg %u\n", uMsg
);
694 DriverCallback(wim
->dwCallback
, HIWORD(wim
->dwFlags
), (HDRVR
)wim
->u
.in
.hOuterWave
,
695 uMsg
, wim
->dwClientInstance
, dwParam1
, dwParam2
);
698 static DWORD
widOpenHelper(WAVEMAPDATA
* wim
, UINT idx
,
699 LPWAVEOPENDESC lpDesc
, LPWAVEFORMATEX lpwfx
,
704 TRACE("(%p %04x %p %p %08lx)\n", wim
, idx
, lpDesc
, lpwfx
, dwFlags
);
706 /* source is always PCM, so the formulas below apply */
707 lpwfx
->nBlockAlign
= (lpwfx
->nChannels
* lpwfx
->wBitsPerSample
) / 8;
708 lpwfx
->nAvgBytesPerSec
= lpwfx
->nSamplesPerSec
* lpwfx
->nBlockAlign
;
709 if (dwFlags
& WAVE_FORMAT_QUERY
) {
710 ret
= acmStreamOpen(NULL
, 0, lpwfx
, lpDesc
->lpFormat
, NULL
, 0L, 0L, ACM_STREAMOPENF_QUERY
);
712 ret
= acmStreamOpen(&wim
->hAcmStream
, 0, lpwfx
, lpDesc
->lpFormat
, NULL
, 0L, 0L, 0L);
714 if (ret
== MMSYSERR_NOERROR
) {
715 ret
= waveInOpen(&wim
->u
.in
.hInnerWave
, idx
, lpwfx
, (DWORD
)widCallback
,
716 (DWORD
)wim
, (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
);
717 if (ret
!= MMSYSERR_NOERROR
&& !(dwFlags
& WAVE_FORMAT_QUERY
)) {
718 acmStreamClose(wim
->hAcmStream
, 0);
722 TRACE("ret = %08lx\n", ret
);
726 static DWORD
widOpen(LPDWORD lpdwUser
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
730 WAVEMAPDATA
* wim
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA
));
733 TRACE("(%p %p %08lx)\n", lpdwUser
, lpDesc
, dwFlags
);
737 return MMSYSERR_NOMEM
;
741 wim
->dwCallback
= lpDesc
->dwCallback
;
742 wim
->dwFlags
= dwFlags
;
743 wim
->dwClientInstance
= lpDesc
->dwInstance
;
744 wim
->u
.in
.hOuterWave
= (HWAVEIN
)lpDesc
->hWave
;
746 ndhi
= waveInGetNumDevs();
747 if (dwFlags
& WAVE_MAPPED
) {
748 if (lpDesc
->uMappedDeviceID
>= ndhi
) return MMSYSERR_INVALPARAM
;
749 ndlo
= lpDesc
->uMappedDeviceID
;
751 dwFlags
&= ~WAVE_MAPPED
;
756 wim
->avgSpeedOuter
= wim
->avgSpeedInner
= lpDesc
->lpFormat
->nAvgBytesPerSec
;
757 wim
->nSamplesPerSecOuter
= wim
->nSamplesPerSecInner
= lpDesc
->lpFormat
->nSamplesPerSec
;
759 for (i
= ndlo
; i
< ndhi
; i
++) {
760 if (waveInOpen(&wim
->u
.in
.hInnerWave
, i
, lpDesc
->lpFormat
, (DWORD
)widCallback
,
761 (DWORD
)wim
, (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
| WAVE_FORMAT_DIRECT
) == MMSYSERR_NOERROR
) {
767 if ((dwFlags
& WAVE_FORMAT_DIRECT
) == 0)
771 wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
772 wfx
.cbSize
= 0; /* normally, this field is not used for PCM format, just in case */
773 /* try some ACM stuff */
775 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
776 switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
777 case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; wim->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \
778 case WAVERR_BADFORMAT: break; \
779 default: goto error; \
782 for (i
= ndlo
; i
< ndhi
; i
++) {
783 wfx
.nSamplesPerSec
=lpDesc
->lpFormat
->nSamplesPerSec
;
784 /* first try with same stereo/mono option as source */
785 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
786 TRY(wfx
.nSamplesPerSec
, 16);
787 TRY(wfx
.nSamplesPerSec
, 8);
789 TRY(wfx
.nSamplesPerSec
, 16);
790 TRY(wfx
.nSamplesPerSec
, 8);
793 for (i
= ndlo
; i
< ndhi
; i
++) {
794 wfx
.nSamplesPerSec
=lpDesc
->lpFormat
->nSamplesPerSec
;
795 /* first try with same stereo/mono option as source */
796 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
803 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
811 /* first try with same stereo/mono option as source */
812 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
819 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
830 HeapFree(GetProcessHeap(), 0, wim
);
831 WARN("ret = WAVERR_BADFORMAT\n");
832 return WAVERR_BADFORMAT
;
834 if (dwFlags
& WAVE_FORMAT_QUERY
) {
836 HeapFree(GetProcessHeap(), 0, wim
);
838 *lpdwUser
= (DWORD
)wim
;
840 TRACE("Ok (stream=%08lx)\n", (DWORD
)wim
->hAcmStream
);
841 return MMSYSERR_NOERROR
;
843 HeapFree(GetProcessHeap(), 0, wim
);
844 if (res
==ACMERR_NOTPOSSIBLE
) {
845 WARN("ret = WAVERR_BADFORMAT\n");
846 return WAVERR_BADFORMAT
;
848 WARN("ret = 0x%08lx\n", res
);
852 static DWORD
widClose(WAVEMAPDATA
* wim
)
856 TRACE("(%p)\n", wim
);
858 ret
= waveInClose(wim
->u
.in
.hInnerWave
);
859 if (ret
== MMSYSERR_NOERROR
) {
860 if (wim
->hAcmStream
) {
861 ret
= acmStreamClose(wim
->hAcmStream
, 0);
863 if (ret
== MMSYSERR_NOERROR
) {
864 HeapFree(GetProcessHeap(), 0, wim
);
870 static DWORD
widAddBuffer(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
872 PACMSTREAMHEADER ash
;
873 LPWAVEHDR lpWaveHdrSrc
;
875 TRACE("(%p %p %08lx)\n", wim
, lpWaveHdrDst
, dwParam2
);
877 if (!wim
->hAcmStream
) {
878 return waveInAddBuffer(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
881 lpWaveHdrDst
->dwFlags
|= WHDR_INQUEUE
;
882 ash
= (PACMSTREAMHEADER
)lpWaveHdrDst
->reserved
;
884 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
885 return waveInAddBuffer(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
888 static DWORD
widPrepare(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
890 PACMSTREAMHEADER ash
;
893 LPWAVEHDR lpWaveHdrSrc
;
895 TRACE("(%p %p %08lx)\n", wim
, lpWaveHdrDst
, dwParam2
);
897 if (!wim
->hAcmStream
) {
898 return waveInPrepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
900 if (acmStreamSize(wim
->hAcmStream
, lpWaveHdrDst
->dwBufferLength
, &size
,
901 ACM_STREAMSIZEF_DESTINATION
) != MMSYSERR_NOERROR
) {
902 WARN("acmStreamSize failed\n");
903 return MMSYSERR_ERROR
;
906 ash
= HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
) + size
);
909 return MMSYSERR_NOMEM
;
912 ash
->cbStruct
= sizeof(*ash
);
914 ash
->dwUser
= (DWORD
)lpWaveHdrDst
;
915 ash
->pbSrc
= (LPBYTE
)ash
+ sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
);
916 ash
->cbSrcLength
= size
;
917 /* ash->cbSrcLengthUsed */
918 ash
->dwSrcUser
= 0L; /* FIXME ? */
919 ash
->pbDst
= (LPBYTE
)lpWaveHdrDst
->lpData
;
920 ash
->cbDstLength
= lpWaveHdrDst
->dwBufferLength
;
921 /* ash->cbDstLengthUsed */
922 ash
->dwDstUser
= lpWaveHdrDst
->dwUser
; /* FIXME ? */
923 dwRet
= acmStreamPrepareHeader(wim
->hAcmStream
, ash
, 0L);
924 if (dwRet
!= MMSYSERR_NOERROR
) {
925 WARN("acmStreamPrepareHeader failed\n");
929 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
930 lpWaveHdrSrc
->lpData
= (LPSTR
)ash
->pbSrc
;
931 lpWaveHdrSrc
->dwBufferLength
= size
; /* conversion is not done yet */
932 lpWaveHdrSrc
->dwFlags
= 0;
933 lpWaveHdrSrc
->dwLoops
= 0;
934 dwRet
= waveInPrepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
935 if (dwRet
!= MMSYSERR_NOERROR
) {
936 WARN("waveInPrepareHeader failed\n");
940 lpWaveHdrDst
->reserved
= (DWORD
)ash
;
941 lpWaveHdrDst
->dwFlags
= WHDR_PREPARED
;
943 return MMSYSERR_NOERROR
;
945 TRACE("=> (%ld)\n", dwRet
);
946 HeapFree(GetProcessHeap(), 0, ash
);
950 static DWORD
widUnprepare(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
952 PACMSTREAMHEADER ash
;
953 LPWAVEHDR lpWaveHdrSrc
;
954 DWORD dwRet1
, dwRet2
;
956 TRACE("(%p %p %08lx)\n", wim
, lpWaveHdrDst
, dwParam2
);
958 if (!wim
->hAcmStream
) {
959 return waveInUnprepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
961 ash
= (PACMSTREAMHEADER
)lpWaveHdrDst
->reserved
;
962 dwRet1
= acmStreamUnprepareHeader(wim
->hAcmStream
, ash
, 0L);
964 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
965 dwRet2
= waveInUnprepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
967 HeapFree(GetProcessHeap(), 0, ash
);
969 lpWaveHdrDst
->dwFlags
&= ~WHDR_PREPARED
;
970 return (dwRet1
== MMSYSERR_NOERROR
) ? dwRet2
: dwRet1
;
973 static DWORD
widGetPosition(WAVEMAPDATA
* wim
, LPMMTIME lpTime
, DWORD dwParam2
)
977 TRACE("(%p %p %08lx)\n", wim
, lpTime
, dwParam2
);
979 memcpy(&timepos
, lpTime
, sizeof(timepos
));
981 /* For TIME_MS, we're going to recalculate using TIME_BYTES */
982 if (lpTime
->wType
== TIME_MS
)
983 timepos
.wType
= TIME_BYTES
;
985 /* This can change timepos.wType if the requested type is not supported */
986 val
= waveInGetPosition(wim
->u
.in
.hInnerWave
, &timepos
, dwParam2
);
988 if (timepos
.wType
== TIME_BYTES
)
990 DWORD dwInnerSamplesPerOuter
= wim
->nSamplesPerSecInner
/ wim
->nSamplesPerSecOuter
;
991 if (dwInnerSamplesPerOuter
> 0)
993 DWORD dwInnerBytesPerSample
= wim
->avgSpeedInner
/ wim
->nSamplesPerSecInner
;
994 DWORD dwInnerBytesPerOuterSample
= dwInnerBytesPerSample
* dwInnerSamplesPerOuter
;
997 /* If we are up sampling (going from lower sample rate to higher),
998 ** we need to make a special accomodation for times when we've
999 ** written a partial output sample. This happens frequently
1000 ** to us because we use msacm to do our up sampling, and it
1001 ** will up sample on an unaligned basis.
1002 ** For example, if you convert a 2 byte wide 8,000 'outer'
1003 ** buffer to a 2 byte wide 48,000 inner device, you would
1004 ** expect 2 bytes of input to produce 12 bytes of output.
1005 ** Instead, msacm will produce 8 bytes of output.
1006 ** But reporting our position as 1 byte of output is
1007 ** nonsensical; the output buffer position needs to be
1008 ** aligned on outer sample size, and aggressively rounded up.
1010 remainder
= timepos
.u
.cb
% dwInnerBytesPerOuterSample
;
1013 timepos
.u
.cb
-= remainder
;
1014 timepos
.u
.cb
+= dwInnerBytesPerOuterSample
;
1018 lpTime
->u
.cb
= MulDiv(timepos
.u
.cb
, wim
->avgSpeedOuter
, wim
->avgSpeedInner
);
1020 /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
1021 if (lpTime
->wType
== TIME_MS
)
1022 lpTime
->u
.ms
= MulDiv(lpTime
->u
.cb
, 1000, wim
->avgSpeedOuter
);
1024 lpTime
->wType
= TIME_BYTES
;
1026 else if (lpTime
->wType
== TIME_SAMPLES
&& timepos
.wType
== TIME_SAMPLES
)
1027 lpTime
->u
.sample
= MulDiv(timepos
.u
.sample
, wim
->nSamplesPerSecOuter
, wim
->nSamplesPerSecInner
);
1029 /* other time types don't require conversion */
1030 lpTime
->u
= timepos
.u
;
1035 static DWORD
widGetDevCaps(UINT wDevID
, WAVEMAPDATA
* wim
, LPWAVEINCAPSW lpWaveCaps
, DWORD dwParam2
)
1037 TRACE("(%04x, %p %p %08lx)\n", wDevID
, wim
, lpWaveCaps
, dwParam2
);
1039 /* if opened low driver, forward message */
1040 if (WAVEMAP_IsData(wim
))
1041 return waveInGetDevCapsW((UINT
)wim
->u
.in
.hInnerWave
, lpWaveCaps
, dwParam2
);
1042 /* else if no drivers, nothing to map so return bad device */
1043 if (waveInGetNumDevs() == 0) {
1044 WARN("bad device id\n");
1045 return MMSYSERR_BADDEVICEID
;
1047 /* otherwise, return caps of mapper itself */
1048 if (wDevID
== (UINT
)-1 || wDevID
== (UINT16
)-1) {
1050 static const WCHAR init
[] = {'W','i','n','e',' ','w','a','v','e',' ','i','n',' ','m','a','p','p','e','r',0};
1053 wic
.vDriverVersion
= 0x0001;
1054 strcpyW(wic
.szPname
, init
);
1056 WAVE_FORMAT_96M08
| WAVE_FORMAT_96S08
| WAVE_FORMAT_96M16
| WAVE_FORMAT_96S16
|
1057 WAVE_FORMAT_48M08
| WAVE_FORMAT_48S08
| WAVE_FORMAT_48M16
| WAVE_FORMAT_48S16
|
1058 WAVE_FORMAT_4M08
| WAVE_FORMAT_4S08
| WAVE_FORMAT_4M16
| WAVE_FORMAT_4S16
|
1059 WAVE_FORMAT_2M08
| WAVE_FORMAT_2S08
| WAVE_FORMAT_2M16
| WAVE_FORMAT_2S16
|
1060 WAVE_FORMAT_1M08
| WAVE_FORMAT_1S08
| WAVE_FORMAT_1M16
| WAVE_FORMAT_1S16
;
1062 memcpy(lpWaveCaps
, &wic
, min(dwParam2
, sizeof(wic
)));
1064 return MMSYSERR_NOERROR
;
1066 ERR("This shouldn't happen\n");
1067 return MMSYSERR_ERROR
;
1070 static DWORD
widStop(WAVEMAPDATA
* wim
)
1072 TRACE("(%p)\n", wim
);
1074 return waveInStop(wim
->u
.in
.hInnerWave
);
1077 static DWORD
widStart(WAVEMAPDATA
* wim
)
1079 TRACE("(%p)\n", wim
);
1081 return waveInStart(wim
->u
.in
.hInnerWave
);
1084 static DWORD
widReset(WAVEMAPDATA
* wim
)
1086 TRACE("(%p)\n", wim
);
1088 return waveInReset(wim
->u
.in
.hInnerWave
);
1091 static DWORD
widMapperStatus(WAVEMAPDATA
* wim
, DWORD flags
, LPVOID ptr
)
1094 DWORD ret
= MMSYSERR_NOTSUPPORTED
;
1096 TRACE("(%p %08lx %p)\n", wim
, flags
, ptr
);
1099 case WAVEIN_MAPPER_STATUS_DEVICE
:
1100 ret
= waveInGetID(wim
->u
.in
.hInnerWave
, &id
);
1103 case WAVEIN_MAPPER_STATUS_MAPPED
:
1104 FIXME("Unsupported yet flag=%ld\n", flags
);
1105 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
1107 case WAVEIN_MAPPER_STATUS_FORMAT
:
1108 FIXME("Unsupported flag=%ld\n", flags
);
1109 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
1110 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
1113 FIXME("Unsupported flag=%ld\n", flags
);
1120 static DWORD
widMapperReconfigure(WAVEMAPDATA
* wim
, DWORD dwParam1
, DWORD dwParam2
)
1122 FIXME("(%p %08lx %08lx) stub!\n", wim
, dwParam1
, dwParam2
);
1124 return MMSYSERR_NOERROR
;
1127 /**************************************************************************
1128 * widMessage (MSACM.@)
1130 DWORD WINAPI
WAVEMAP_widMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1131 DWORD dwParam1
, DWORD dwParam2
)
1133 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1134 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1141 /* FIXME: Pretend this is supported */
1144 case WIDM_OPEN
: return widOpen ((LPDWORD
)dwUser
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
1145 case WIDM_CLOSE
: return widClose ((WAVEMAPDATA
*)dwUser
);
1147 case WIDM_ADDBUFFER
: return widAddBuffer ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1148 case WIDM_PREPARE
: return widPrepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1149 case WIDM_UNPREPARE
: return widUnprepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1150 case WIDM_GETDEVCAPS
: return widGetDevCaps (wDevID
, (WAVEMAPDATA
*)dwUser
, (LPWAVEINCAPSW
)dwParam1
, dwParam2
);
1151 case WIDM_GETNUMDEVS
: return 1;
1152 case WIDM_GETPOS
: return widGetPosition ((WAVEMAPDATA
*)dwUser
, (LPMMTIME
)dwParam1
, dwParam2
);
1153 case WIDM_RESET
: return widReset ((WAVEMAPDATA
*)dwUser
);
1154 case WIDM_START
: return widStart ((WAVEMAPDATA
*)dwUser
);
1155 case WIDM_STOP
: return widStop ((WAVEMAPDATA
*)dwUser
);
1156 case WIDM_MAPPER_STATUS
: return widMapperStatus ((WAVEMAPDATA
*)dwUser
, dwParam1
, (LPVOID
)dwParam2
);
1157 case DRVM_MAPPER_RECONFIGURE
: return widMapperReconfigure((WAVEMAPDATA
*)dwUser
, dwParam1
, dwParam2
);
1158 /* known but not supported */
1159 case DRV_QUERYDEVICEINTERFACESIZE
:
1160 case DRV_QUERYDEVICEINTERFACE
:
1161 return MMSYSERR_NOTSUPPORTED
;
1163 FIXME("unknown message %u!\n", wMsg
);
1165 return MMSYSERR_NOTSUPPORTED
;
1168 /*======================================================================*
1170 *======================================================================*/
1172 static struct WINE_WAVEMAP
* oss
= NULL
;
1174 /**************************************************************************
1175 * WAVEMAP_drvOpen [internal]
1177 static DWORD
WAVEMAP_drvOpen(LPSTR str
)
1179 TRACE("(%p)\n", str
);
1184 /* I know, this is ugly, but who cares... */
1185 oss
= (struct WINE_WAVEMAP
*)1;
1189 /**************************************************************************
1190 * WAVEMAP_drvClose [internal]
1192 static DWORD
WAVEMAP_drvClose(DWORD dwDevID
)
1194 TRACE("(%08lx)\n", dwDevID
);
1203 /**************************************************************************
1204 * DriverProc (MSACM.@)
1206 LONG CALLBACK
WAVEMAP_DriverProc(DWORD dwDevID
, HDRVR hDriv
, DWORD wMsg
,
1207 DWORD dwParam1
, DWORD dwParam2
)
1209 TRACE("(%08lX, %p, %08lX, %08lX, %08lX)\n",
1210 dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1213 case DRV_LOAD
: return 1;
1214 case DRV_FREE
: return 1;
1215 case DRV_OPEN
: return WAVEMAP_drvOpen((LPSTR
)dwParam1
);
1216 case DRV_CLOSE
: return WAVEMAP_drvClose(dwDevID
);
1217 case DRV_ENABLE
: return 1;
1218 case DRV_DISABLE
: return 1;
1219 case DRV_QUERYCONFIGURE
: return 1;
1220 case DRV_CONFIGURE
: MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK
); return 1;
1221 case DRV_INSTALL
: return DRVCNF_RESTART
;
1222 case DRV_REMOVE
: return DRVCNF_RESTART
;
1224 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);