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_PTR dwInstance
,
80 LPARAM dwParam1
, LPARAM 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) {
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 if (lpDesc
->lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
) {
212 /* Format changed so keep sample rate and number of channels
213 * the same and just change the bit depth
215 for (i
= ndlo
; i
< ndhi
; i
++) {
216 wfx
.nSamplesPerSec
=lpDesc
->lpFormat
->nSamplesPerSec
;
217 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
218 TRY(wfx
.nSamplesPerSec
, 16);
219 TRY(wfx
.nSamplesPerSec
, 8);
222 /* Our resampling algorithm is quite primitive so first try
223 * to just change the bit depth and number of channels
225 for (i
= ndlo
; i
< ndhi
; i
++) {
226 wfx
.nSamplesPerSec
=lpDesc
->lpFormat
->nSamplesPerSec
;
227 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
228 TRY(wfx
.nSamplesPerSec
, 16);
229 TRY(wfx
.nSamplesPerSec
, 8);
231 TRY(wfx
.nSamplesPerSec
, 16);
232 TRY(wfx
.nSamplesPerSec
, 8);
235 for (i
= ndlo
; i
< ndhi
; i
++) {
236 /* first try with same stereo/mono option as source */
237 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
244 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
252 /* first try with same stereo/mono option as source */
253 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
260 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
272 HeapFree(GetProcessHeap(), 0, wom
);
273 WARN("ret = WAVERR_BADFORMAT\n");
274 return WAVERR_BADFORMAT
;
277 if (dwFlags
& WAVE_FORMAT_QUERY
) {
279 HeapFree(GetProcessHeap(), 0, wom
);
281 *lpdwUser
= (DWORD
)wom
;
283 return MMSYSERR_NOERROR
;
285 HeapFree(GetProcessHeap(), 0, wom
);
286 if (res
==ACMERR_NOTPOSSIBLE
) {
287 WARN("ret = WAVERR_BADFORMAT\n");
288 return WAVERR_BADFORMAT
;
290 WARN("ret = 0x%08lx\n", res
);
294 static DWORD
wodClose(WAVEMAPDATA
* wom
)
298 TRACE("(%p)\n", wom
);
300 ret
= waveOutClose(wom
->u
.out
.hInnerWave
);
301 if (ret
== MMSYSERR_NOERROR
) {
302 if (wom
->hAcmStream
) {
303 ret
= acmStreamClose(wom
->hAcmStream
, 0);
305 if (ret
== MMSYSERR_NOERROR
) {
306 HeapFree(GetProcessHeap(), 0, wom
);
312 static DWORD
wodWrite(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
314 PACMSTREAMHEADER ash
;
315 LPWAVEHDR lpWaveHdrDst
;
317 TRACE("(%p %p %08lx)\n", wom
, lpWaveHdrSrc
, dwParam2
);
319 if (!wom
->hAcmStream
) {
320 return waveOutWrite(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
323 lpWaveHdrSrc
->dwFlags
|= WHDR_INQUEUE
;
324 ash
= (PACMSTREAMHEADER
)lpWaveHdrSrc
->reserved
;
325 /* acmStreamConvert will actually check that the new size is less than initial size */
326 ash
->cbSrcLength
= lpWaveHdrSrc
->dwBufferLength
;
327 if (acmStreamConvert(wom
->hAcmStream
, ash
, 0L) != MMSYSERR_NOERROR
) {
328 WARN("acmStreamConvert failed\n");
329 return MMSYSERR_ERROR
;
332 lpWaveHdrDst
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
333 if (ash
->cbSrcLength
> ash
->cbSrcLengthUsed
)
334 FIXME("Not all src buffer has been written, expect bogus sound\n");
335 else if (ash
->cbSrcLength
< ash
->cbSrcLengthUsed
)
336 ERR("CoDec has read more data than it is allowed to\n");
338 if (ash
->cbDstLengthUsed
== 0) {
339 /* something went wrong in decoding */
340 FIXME("Got 0 length\n");
341 return MMSYSERR_ERROR
;
343 lpWaveHdrDst
->dwBufferLength
= ash
->cbDstLengthUsed
;
344 return waveOutWrite(wom
->u
.out
.hInnerWave
, lpWaveHdrDst
, sizeof(*lpWaveHdrDst
));
347 static DWORD
wodPrepare(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
349 PACMSTREAMHEADER ash
;
352 LPWAVEHDR lpWaveHdrDst
;
354 TRACE("(%p %p %08lx)\n", wom
, lpWaveHdrSrc
, dwParam2
);
356 if (!wom
->hAcmStream
)
357 return waveOutPrepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
359 if (acmStreamSize(wom
->hAcmStream
, lpWaveHdrSrc
->dwBufferLength
, &size
, ACM_STREAMSIZEF_SOURCE
) != MMSYSERR_NOERROR
) {
360 WARN("acmStreamSize failed\n");
361 return MMSYSERR_ERROR
;
364 ash
= HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
) + size
);
367 return MMSYSERR_NOMEM
;
370 ash
->cbStruct
= sizeof(*ash
);
372 ash
->dwUser
= (DWORD
)lpWaveHdrSrc
;
373 ash
->pbSrc
= (LPBYTE
)lpWaveHdrSrc
->lpData
;
374 ash
->cbSrcLength
= lpWaveHdrSrc
->dwBufferLength
;
375 /* ash->cbSrcLengthUsed */
376 ash
->dwSrcUser
= lpWaveHdrSrc
->dwUser
; /* FIXME ? */
377 ash
->pbDst
= (LPBYTE
)ash
+ sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
);
378 ash
->cbDstLength
= size
;
379 /* ash->cbDstLengthUsed */
380 ash
->dwDstUser
= 0; /* FIXME ? */
381 dwRet
= acmStreamPrepareHeader(wom
->hAcmStream
, ash
, 0L);
382 if (dwRet
!= MMSYSERR_NOERROR
) {
383 WARN("acmStreamPrepareHeader failed\n");
387 lpWaveHdrDst
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
388 lpWaveHdrDst
->lpData
= (LPSTR
)ash
->pbDst
;
389 lpWaveHdrDst
->dwBufferLength
= size
; /* conversion is not done yet */
390 lpWaveHdrDst
->dwFlags
= 0;
391 lpWaveHdrDst
->dwLoops
= 0;
392 dwRet
= waveOutPrepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrDst
, sizeof(*lpWaveHdrDst
));
393 if (dwRet
!= MMSYSERR_NOERROR
) {
394 WARN("waveOutPrepareHeader failed\n");
398 lpWaveHdrSrc
->reserved
= (DWORD
)ash
;
399 lpWaveHdrSrc
->dwFlags
= WHDR_PREPARED
;
401 return MMSYSERR_NOERROR
;
403 TRACE("=> (%ld)\n", dwRet
);
404 HeapFree(GetProcessHeap(), 0, ash
);
408 static DWORD
wodUnprepare(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
410 PACMSTREAMHEADER ash
;
411 LPWAVEHDR lpWaveHdrDst
;
412 DWORD dwRet1
, dwRet2
;
414 TRACE("(%p %p %08lx)\n", wom
, lpWaveHdrSrc
, dwParam2
);
416 if (!wom
->hAcmStream
) {
417 return waveOutUnprepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
419 ash
= (PACMSTREAMHEADER
)lpWaveHdrSrc
->reserved
;
420 dwRet1
= acmStreamUnprepareHeader(wom
->hAcmStream
, ash
, 0L);
422 lpWaveHdrDst
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
423 dwRet2
= waveOutUnprepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrDst
, sizeof(*lpWaveHdrDst
));
425 HeapFree(GetProcessHeap(), 0, ash
);
427 lpWaveHdrSrc
->dwFlags
&= ~WHDR_PREPARED
;
428 return (dwRet1
== MMSYSERR_NOERROR
) ? dwRet2
: dwRet1
;
431 static DWORD
wodGetPosition(WAVEMAPDATA
* wom
, LPMMTIME lpTime
, DWORD dwParam2
)
435 TRACE("(%p %p %08lx)\n", wom
, lpTime
, dwParam2
);
437 memcpy(&timepos
, lpTime
, sizeof(timepos
));
439 /* For TIME_MS, we're going to recalculate using TIME_BYTES */
440 if (lpTime
->wType
== TIME_MS
)
441 timepos
.wType
= TIME_BYTES
;
443 /* This can change timepos.wType if the requested type is not supported */
444 val
= waveOutGetPosition(wom
->u
.out
.hInnerWave
, &timepos
, dwParam2
);
446 if (timepos
.wType
== TIME_BYTES
)
448 DWORD dwInnerSamplesPerOuter
= wom
->nSamplesPerSecInner
/ wom
->nSamplesPerSecOuter
;
449 if (dwInnerSamplesPerOuter
> 0)
451 DWORD dwInnerBytesPerSample
= wom
->avgSpeedInner
/ wom
->nSamplesPerSecInner
;
452 DWORD dwInnerBytesPerOuterSample
= dwInnerBytesPerSample
* dwInnerSamplesPerOuter
;
455 /* If we are up sampling (going from lower sample rate to higher),
456 ** we need to make a special accommodation for times when we've
457 ** written a partial output sample. This happens frequently
458 ** to us because we use msacm to do our up sampling, and it
459 ** will up sample on an unaligned basis.
460 ** For example, if you convert a 2 byte wide 8,000 'outer'
461 ** buffer to a 2 byte wide 48,000 inner device, you would
462 ** expect 2 bytes of input to produce 12 bytes of output.
463 ** Instead, msacm will produce 8 bytes of output.
464 ** But reporting our position as 1 byte of output is
465 ** nonsensical; the output buffer position needs to be
466 ** aligned on outer sample size, and aggressively rounded up.
468 remainder
= timepos
.u
.cb
% dwInnerBytesPerOuterSample
;
471 timepos
.u
.cb
-= remainder
;
472 timepos
.u
.cb
+= dwInnerBytesPerOuterSample
;
476 lpTime
->u
.cb
= MulDiv(timepos
.u
.cb
, wom
->avgSpeedOuter
, wom
->avgSpeedInner
);
478 /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
479 if (lpTime
->wType
== TIME_MS
)
480 lpTime
->u
.ms
= MulDiv(lpTime
->u
.cb
, 1000, wom
->avgSpeedOuter
);
482 lpTime
->wType
= TIME_BYTES
;
484 else if (lpTime
->wType
== TIME_SAMPLES
&& timepos
.wType
== TIME_SAMPLES
)
485 lpTime
->u
.sample
= MulDiv(timepos
.u
.sample
, wom
->nSamplesPerSecOuter
, wom
->nSamplesPerSecInner
);
487 /* other time types don't require conversion */
488 lpTime
->u
= timepos
.u
;
493 static DWORD
wodGetDevCaps(UINT wDevID
, WAVEMAPDATA
* wom
, LPWAVEOUTCAPSW lpWaveCaps
, DWORD dwParam2
)
495 static const WCHAR name
[] = {'W','i','n','e',' ','w','a','v','e',' ','o','u','t',' ','m','a','p','p','e','r',0};
497 TRACE("(%04x %p %p %08lx)\n",wDevID
, wom
, lpWaveCaps
, dwParam2
);
499 /* if opened low driver, forward message */
500 if (WAVEMAP_IsData(wom
))
501 return waveOutGetDevCapsW((UINT
)wom
->u
.out
.hInnerWave
, lpWaveCaps
, dwParam2
);
502 /* else if no drivers, nothing to map so return bad device */
503 if (waveOutGetNumDevs() == 0) {
504 WARN("bad device id\n");
505 return MMSYSERR_BADDEVICEID
;
507 /* otherwise, return caps of mapper itself */
508 if (wDevID
== (UINT
)-1 || wDevID
== (UINT16
)-1) {
512 woc
.vDriverVersion
= 0x0100;
513 lstrcpyW(woc
.szPname
, name
);
515 WAVE_FORMAT_96M08
| WAVE_FORMAT_96S08
| WAVE_FORMAT_96M16
| WAVE_FORMAT_96S16
|
516 WAVE_FORMAT_48M08
| WAVE_FORMAT_48S08
| WAVE_FORMAT_48M16
| WAVE_FORMAT_48S16
|
517 WAVE_FORMAT_4M08
| WAVE_FORMAT_4S08
| WAVE_FORMAT_4M16
| WAVE_FORMAT_4S16
|
518 WAVE_FORMAT_2M08
| WAVE_FORMAT_2S08
| WAVE_FORMAT_2M16
| WAVE_FORMAT_2S16
|
519 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 %08lx)\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 %08lx %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=%ld\n", flags
);
590 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
592 case WAVEOUT_MAPPER_STATUS_FORMAT
:
593 FIXME("Unsupported flag=%ld\n", flags
);
594 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
598 FIXME("Unsupported flag=%ld\n", flags
);
605 static DWORD
wodMapperReconfigure(WAVEMAPDATA
* wom
, DWORD dwParam1
, DWORD dwParam2
)
607 FIXME("(%p %08lx %08lx) stub!\n", wom
, dwParam1
, dwParam2
);
609 return MMSYSERR_NOERROR
;
612 /**************************************************************************
613 * wodMessage (MSACM.@)
615 DWORD WINAPI
WAVEMAP_wodMessage(UINT wDevID
, UINT wMsg
, DWORD dwUser
,
616 DWORD dwParam1
, DWORD 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 ((LPDWORD
)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 dwInstance
,
663 DWORD dwParam1
, DWORD dwParam2
)
665 WAVEMAPDATA
* wim
= (WAVEMAPDATA
*)dwInstance
;
667 TRACE("(%p %u %ld %lx %lx);\n", hWave
, uMsg
, dwInstance
, dwParam1
, dwParam2
);
669 if (!WAVEMAP_IsData(wim
)) {
674 if (hWave
!= wim
->u
.in
.hInnerWave
&& uMsg
!= WIM_OPEN
)
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 %ld bytes into %ld\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
)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 %08lx)\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
, (DWORD
)widCallback
,
728 (DWORD
)wim
, (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
);
729 if (ret
!= MMSYSERR_NOERROR
&& !(dwFlags
& WAVE_FORMAT_QUERY
)) {
730 acmStreamClose(wim
->hAcmStream
, 0);
734 TRACE("ret = %08lx\n", ret
);
738 static DWORD
widOpen(LPDWORD lpdwUser
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
742 WAVEMAPDATA
* wim
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA
));
745 TRACE("(%p %p %08lx)\n", lpdwUser
, lpDesc
, dwFlags
);
749 return MMSYSERR_NOMEM
;
753 wim
->dwCallback
= lpDesc
->dwCallback
;
754 wim
->dwFlags
= dwFlags
;
755 wim
->dwClientInstance
= lpDesc
->dwInstance
;
756 wim
->u
.in
.hOuterWave
= (HWAVEIN
)lpDesc
->hWave
;
758 ndhi
= waveInGetNumDevs();
759 if (dwFlags
& WAVE_MAPPED
) {
760 if (lpDesc
->uMappedDeviceID
>= ndhi
) return MMSYSERR_INVALPARAM
;
761 ndlo
= lpDesc
->uMappedDeviceID
;
763 dwFlags
&= ~WAVE_MAPPED
;
768 wim
->avgSpeedOuter
= wim
->avgSpeedInner
= lpDesc
->lpFormat
->nAvgBytesPerSec
;
769 wim
->nSamplesPerSecOuter
= wim
->nSamplesPerSecInner
= lpDesc
->lpFormat
->nSamplesPerSec
;
771 for (i
= ndlo
; i
< ndhi
; i
++) {
772 if (waveInOpen(&wim
->u
.in
.hInnerWave
, i
, lpDesc
->lpFormat
, (DWORD
)widCallback
,
773 (DWORD
)wim
, (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
| WAVE_FORMAT_DIRECT
) == MMSYSERR_NOERROR
) {
779 if ((dwFlags
& WAVE_FORMAT_DIRECT
) == 0)
783 wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
784 wfx
.cbSize
= 0; /* normally, this field is not used for PCM format, just in case */
785 /* try some ACM stuff */
787 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
788 switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
789 case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; wim->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \
790 case WAVERR_BADFORMAT: break; \
791 default: goto error; \
794 for (i
= ndlo
; i
< ndhi
; i
++) {
795 wfx
.nSamplesPerSec
=lpDesc
->lpFormat
->nSamplesPerSec
;
796 /* first try with same stereo/mono option as source */
797 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
798 TRY(wfx
.nSamplesPerSec
, 16);
799 TRY(wfx
.nSamplesPerSec
, 8);
801 TRY(wfx
.nSamplesPerSec
, 16);
802 TRY(wfx
.nSamplesPerSec
, 8);
805 for (i
= ndlo
; i
< ndhi
; i
++) {
806 wfx
.nSamplesPerSec
=lpDesc
->lpFormat
->nSamplesPerSec
;
807 /* first try with same stereo/mono option as source */
808 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
815 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
823 /* first try with same stereo/mono option as source */
824 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
831 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
842 HeapFree(GetProcessHeap(), 0, wim
);
843 WARN("ret = WAVERR_BADFORMAT\n");
844 return WAVERR_BADFORMAT
;
846 if (dwFlags
& WAVE_FORMAT_QUERY
) {
848 HeapFree(GetProcessHeap(), 0, wim
);
850 *lpdwUser
= (DWORD
)wim
;
852 TRACE("Ok (stream=%08lx)\n", (DWORD
)wim
->hAcmStream
);
853 return MMSYSERR_NOERROR
;
855 HeapFree(GetProcessHeap(), 0, wim
);
856 if (res
==ACMERR_NOTPOSSIBLE
) {
857 WARN("ret = WAVERR_BADFORMAT\n");
858 return WAVERR_BADFORMAT
;
860 WARN("ret = 0x%08lx\n", res
);
864 static DWORD
widClose(WAVEMAPDATA
* wim
)
868 TRACE("(%p)\n", wim
);
870 ret
= waveInClose(wim
->u
.in
.hInnerWave
);
871 if (ret
== MMSYSERR_NOERROR
) {
872 if (wim
->hAcmStream
) {
873 ret
= acmStreamClose(wim
->hAcmStream
, 0);
875 if (ret
== MMSYSERR_NOERROR
) {
876 HeapFree(GetProcessHeap(), 0, wim
);
882 static DWORD
widAddBuffer(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
884 PACMSTREAMHEADER ash
;
885 LPWAVEHDR lpWaveHdrSrc
;
887 TRACE("(%p %p %08lx)\n", wim
, lpWaveHdrDst
, dwParam2
);
889 if (!wim
->hAcmStream
) {
890 return waveInAddBuffer(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
893 lpWaveHdrDst
->dwFlags
|= WHDR_INQUEUE
;
894 ash
= (PACMSTREAMHEADER
)lpWaveHdrDst
->reserved
;
896 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
897 return waveInAddBuffer(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
900 static DWORD
widPrepare(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
902 PACMSTREAMHEADER ash
;
905 LPWAVEHDR lpWaveHdrSrc
;
907 TRACE("(%p %p %08lx)\n", wim
, lpWaveHdrDst
, dwParam2
);
909 if (!wim
->hAcmStream
) {
910 return waveInPrepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
912 if (acmStreamSize(wim
->hAcmStream
, lpWaveHdrDst
->dwBufferLength
, &size
,
913 ACM_STREAMSIZEF_DESTINATION
) != MMSYSERR_NOERROR
) {
914 WARN("acmStreamSize failed\n");
915 return MMSYSERR_ERROR
;
918 ash
= HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
) + size
);
921 return MMSYSERR_NOMEM
;
924 ash
->cbStruct
= sizeof(*ash
);
926 ash
->dwUser
= (DWORD
)lpWaveHdrDst
;
927 ash
->pbSrc
= (LPBYTE
)ash
+ sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
);
928 ash
->cbSrcLength
= size
;
929 /* ash->cbSrcLengthUsed */
930 ash
->dwSrcUser
= 0L; /* FIXME ? */
931 ash
->pbDst
= (LPBYTE
)lpWaveHdrDst
->lpData
;
932 ash
->cbDstLength
= lpWaveHdrDst
->dwBufferLength
;
933 /* ash->cbDstLengthUsed */
934 ash
->dwDstUser
= lpWaveHdrDst
->dwUser
; /* FIXME ? */
935 dwRet
= acmStreamPrepareHeader(wim
->hAcmStream
, ash
, 0L);
936 if (dwRet
!= MMSYSERR_NOERROR
) {
937 WARN("acmStreamPrepareHeader failed\n");
941 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
942 lpWaveHdrSrc
->lpData
= (LPSTR
)ash
->pbSrc
;
943 lpWaveHdrSrc
->dwBufferLength
= size
; /* conversion is not done yet */
944 lpWaveHdrSrc
->dwFlags
= 0;
945 lpWaveHdrSrc
->dwLoops
= 0;
946 dwRet
= waveInPrepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
947 if (dwRet
!= MMSYSERR_NOERROR
) {
948 WARN("waveInPrepareHeader failed\n");
952 lpWaveHdrDst
->reserved
= (DWORD
)ash
;
953 lpWaveHdrDst
->dwFlags
= WHDR_PREPARED
;
955 return MMSYSERR_NOERROR
;
957 TRACE("=> (%ld)\n", dwRet
);
958 HeapFree(GetProcessHeap(), 0, ash
);
962 static DWORD
widUnprepare(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
964 PACMSTREAMHEADER ash
;
965 LPWAVEHDR lpWaveHdrSrc
;
966 DWORD dwRet1
, dwRet2
;
968 TRACE("(%p %p %08lx)\n", wim
, lpWaveHdrDst
, dwParam2
);
970 if (!wim
->hAcmStream
) {
971 return waveInUnprepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
973 ash
= (PACMSTREAMHEADER
)lpWaveHdrDst
->reserved
;
974 dwRet1
= acmStreamUnprepareHeader(wim
->hAcmStream
, ash
, 0L);
976 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
977 dwRet2
= waveInUnprepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
979 HeapFree(GetProcessHeap(), 0, ash
);
981 lpWaveHdrDst
->dwFlags
&= ~WHDR_PREPARED
;
982 return (dwRet1
== MMSYSERR_NOERROR
) ? dwRet2
: dwRet1
;
985 static DWORD
widGetPosition(WAVEMAPDATA
* wim
, LPMMTIME lpTime
, DWORD dwParam2
)
989 TRACE("(%p %p %08lx)\n", wim
, lpTime
, dwParam2
);
991 memcpy(&timepos
, lpTime
, sizeof(timepos
));
993 /* For TIME_MS, we're going to recalculate using TIME_BYTES */
994 if (lpTime
->wType
== TIME_MS
)
995 timepos
.wType
= TIME_BYTES
;
997 /* This can change timepos.wType if the requested type is not supported */
998 val
= waveInGetPosition(wim
->u
.in
.hInnerWave
, &timepos
, dwParam2
);
1000 if (timepos
.wType
== TIME_BYTES
)
1002 DWORD dwInnerSamplesPerOuter
= wim
->nSamplesPerSecInner
/ wim
->nSamplesPerSecOuter
;
1003 if (dwInnerSamplesPerOuter
> 0)
1005 DWORD dwInnerBytesPerSample
= wim
->avgSpeedInner
/ wim
->nSamplesPerSecInner
;
1006 DWORD dwInnerBytesPerOuterSample
= dwInnerBytesPerSample
* dwInnerSamplesPerOuter
;
1007 DWORD remainder
= 0;
1009 /* If we are up sampling (going from lower sample rate to higher),
1010 ** we need to make a special accommodation for times when we've
1011 ** written a partial output sample. This happens frequently
1012 ** to us because we use msacm to do our up sampling, and it
1013 ** will up sample on an unaligned basis.
1014 ** For example, if you convert a 2 byte wide 8,000 'outer'
1015 ** buffer to a 2 byte wide 48,000 inner device, you would
1016 ** expect 2 bytes of input to produce 12 bytes of output.
1017 ** Instead, msacm will produce 8 bytes of output.
1018 ** But reporting our position as 1 byte of output is
1019 ** nonsensical; the output buffer position needs to be
1020 ** aligned on outer sample size, and aggressively rounded up.
1022 remainder
= timepos
.u
.cb
% dwInnerBytesPerOuterSample
;
1025 timepos
.u
.cb
-= remainder
;
1026 timepos
.u
.cb
+= dwInnerBytesPerOuterSample
;
1030 lpTime
->u
.cb
= MulDiv(timepos
.u
.cb
, wim
->avgSpeedOuter
, wim
->avgSpeedInner
);
1032 /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
1033 if (lpTime
->wType
== TIME_MS
)
1034 lpTime
->u
.ms
= MulDiv(lpTime
->u
.cb
, 1000, wim
->avgSpeedOuter
);
1036 lpTime
->wType
= TIME_BYTES
;
1038 else if (lpTime
->wType
== TIME_SAMPLES
&& timepos
.wType
== TIME_SAMPLES
)
1039 lpTime
->u
.sample
= MulDiv(timepos
.u
.sample
, wim
->nSamplesPerSecOuter
, wim
->nSamplesPerSecInner
);
1041 /* other time types don't require conversion */
1042 lpTime
->u
= timepos
.u
;
1047 static DWORD
widGetDevCaps(UINT wDevID
, WAVEMAPDATA
* wim
, LPWAVEINCAPSW lpWaveCaps
, DWORD dwParam2
)
1049 TRACE("(%04x, %p %p %08lx)\n", wDevID
, wim
, lpWaveCaps
, dwParam2
);
1051 /* if opened low driver, forward message */
1052 if (WAVEMAP_IsData(wim
))
1053 return waveInGetDevCapsW((UINT
)wim
->u
.in
.hInnerWave
, lpWaveCaps
, dwParam2
);
1054 /* else if no drivers, nothing to map so return bad device */
1055 if (waveInGetNumDevs() == 0) {
1056 WARN("bad device id\n");
1057 return MMSYSERR_BADDEVICEID
;
1059 /* otherwise, return caps of mapper itself */
1060 if (wDevID
== (UINT
)-1 || wDevID
== (UINT16
)-1) {
1062 static const WCHAR init
[] = {'W','i','n','e',' ','w','a','v','e',' ','i','n',' ','m','a','p','p','e','r',0};
1065 wic
.vDriverVersion
= 0x0001;
1066 strcpyW(wic
.szPname
, init
);
1068 WAVE_FORMAT_96M08
| WAVE_FORMAT_96S08
| WAVE_FORMAT_96M16
| WAVE_FORMAT_96S16
|
1069 WAVE_FORMAT_48M08
| WAVE_FORMAT_48S08
| WAVE_FORMAT_48M16
| WAVE_FORMAT_48S16
|
1070 WAVE_FORMAT_4M08
| WAVE_FORMAT_4S08
| WAVE_FORMAT_4M16
| WAVE_FORMAT_4S16
|
1071 WAVE_FORMAT_2M08
| WAVE_FORMAT_2S08
| WAVE_FORMAT_2M16
| WAVE_FORMAT_2S16
|
1072 WAVE_FORMAT_1M08
| WAVE_FORMAT_1S08
| WAVE_FORMAT_1M16
| WAVE_FORMAT_1S16
;
1074 memcpy(lpWaveCaps
, &wic
, min(dwParam2
, sizeof(wic
)));
1076 return MMSYSERR_NOERROR
;
1078 ERR("This shouldn't happen\n");
1079 return MMSYSERR_ERROR
;
1082 static DWORD
widStop(WAVEMAPDATA
* wim
)
1084 TRACE("(%p)\n", wim
);
1086 return waveInStop(wim
->u
.in
.hInnerWave
);
1089 static DWORD
widStart(WAVEMAPDATA
* wim
)
1091 TRACE("(%p)\n", wim
);
1093 return waveInStart(wim
->u
.in
.hInnerWave
);
1096 static DWORD
widReset(WAVEMAPDATA
* wim
)
1098 TRACE("(%p)\n", wim
);
1100 return waveInReset(wim
->u
.in
.hInnerWave
);
1103 static DWORD
widMapperStatus(WAVEMAPDATA
* wim
, DWORD flags
, LPVOID ptr
)
1106 DWORD ret
= MMSYSERR_NOTSUPPORTED
;
1108 TRACE("(%p %08lx %p)\n", wim
, flags
, ptr
);
1111 case WAVEIN_MAPPER_STATUS_DEVICE
:
1112 ret
= waveInGetID(wim
->u
.in
.hInnerWave
, &id
);
1115 case WAVEIN_MAPPER_STATUS_MAPPED
:
1116 FIXME("Unsupported yet flag=%ld\n", flags
);
1117 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
1119 case WAVEIN_MAPPER_STATUS_FORMAT
:
1120 FIXME("Unsupported flag=%ld\n", flags
);
1121 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
1122 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
1125 FIXME("Unsupported flag=%ld\n", flags
);
1132 static DWORD
widMapperReconfigure(WAVEMAPDATA
* wim
, DWORD dwParam1
, DWORD dwParam2
)
1134 FIXME("(%p %08lx %08lx) stub!\n", wim
, dwParam1
, dwParam2
);
1136 return MMSYSERR_NOERROR
;
1139 /**************************************************************************
1140 * widMessage (MSACM.@)
1142 DWORD WINAPI
WAVEMAP_widMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1143 DWORD dwParam1
, DWORD dwParam2
)
1145 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1146 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1153 /* FIXME: Pretend this is supported */
1156 case WIDM_OPEN
: return widOpen ((LPDWORD
)dwUser
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
1157 case WIDM_CLOSE
: return widClose ((WAVEMAPDATA
*)dwUser
);
1159 case WIDM_ADDBUFFER
: return widAddBuffer ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1160 case WIDM_PREPARE
: return widPrepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1161 case WIDM_UNPREPARE
: return widUnprepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1162 case WIDM_GETDEVCAPS
: return widGetDevCaps (wDevID
, (WAVEMAPDATA
*)dwUser
, (LPWAVEINCAPSW
)dwParam1
, dwParam2
);
1163 case WIDM_GETNUMDEVS
: return 1;
1164 case WIDM_GETPOS
: return widGetPosition ((WAVEMAPDATA
*)dwUser
, (LPMMTIME
)dwParam1
, dwParam2
);
1165 case WIDM_RESET
: return widReset ((WAVEMAPDATA
*)dwUser
);
1166 case WIDM_START
: return widStart ((WAVEMAPDATA
*)dwUser
);
1167 case WIDM_STOP
: return widStop ((WAVEMAPDATA
*)dwUser
);
1168 case WIDM_MAPPER_STATUS
: return widMapperStatus ((WAVEMAPDATA
*)dwUser
, dwParam1
, (LPVOID
)dwParam2
);
1169 case DRVM_MAPPER_RECONFIGURE
: return widMapperReconfigure((WAVEMAPDATA
*)dwUser
, dwParam1
, dwParam2
);
1170 /* known but not supported */
1171 case DRV_QUERYDEVICEINTERFACESIZE
:
1172 case DRV_QUERYDEVICEINTERFACE
:
1173 return MMSYSERR_NOTSUPPORTED
;
1175 FIXME("unknown message %u!\n", wMsg
);
1177 return MMSYSERR_NOTSUPPORTED
;
1180 /*======================================================================*
1182 *======================================================================*/
1184 static struct WINE_WAVEMAP
* oss
= NULL
;
1186 /**************************************************************************
1187 * WAVEMAP_drvOpen [internal]
1189 static LRESULT
WAVEMAP_drvOpen(LPSTR str
)
1191 TRACE("(%p)\n", str
);
1196 /* I know, this is ugly, but who cares... */
1197 oss
= (struct WINE_WAVEMAP
*)1;
1201 /**************************************************************************
1202 * WAVEMAP_drvClose [internal]
1204 static LRESULT
WAVEMAP_drvClose(DWORD_PTR dwDevID
)
1206 TRACE("(%08lx)\n", dwDevID
);
1215 /**************************************************************************
1216 * DriverProc (MSACM.@)
1218 LRESULT CALLBACK
WAVEMAP_DriverProc(DWORD_PTR dwDevID
, HDRVR hDriv
, UINT wMsg
,
1219 LPARAM dwParam1
, LPARAM dwParam2
)
1221 TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
1222 dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1225 case DRV_LOAD
: return 1;
1226 case DRV_FREE
: return 1;
1227 case DRV_OPEN
: return WAVEMAP_drvOpen((LPSTR
)dwParam1
);
1228 case DRV_CLOSE
: return WAVEMAP_drvClose(dwDevID
);
1229 case DRV_ENABLE
: return 1;
1230 case DRV_DISABLE
: return 1;
1231 case DRV_QUERYCONFIGURE
: return 1;
1232 case DRV_CONFIGURE
: MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK
); return 1;
1233 case DRV_INSTALL
: return DRVCNF_RESTART
;
1234 case DRV_REMOVE
: return DRVCNF_RESTART
;
1236 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);