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...
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msacm
);
42 typedef struct tagWAVEMAPDATA
{
43 struct tagWAVEMAPDATA
* self
;
54 HACMSTREAM hAcmStream
;
55 /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */
57 DWORD dwClientInstance
;
59 /* ratio to compute position from a PCM playback to any format */
64 static BOOL
WAVEMAP_IsData(WAVEMAPDATA
* wm
)
66 return (!IsBadReadPtr(wm
, sizeof(WAVEMAPDATA
)) && wm
->self
== wm
);
69 /*======================================================================*
71 *======================================================================*/
73 static void CALLBACK
wodCallback(HWAVEOUT hWave
, UINT uMsg
, DWORD dwInstance
,
74 DWORD dwParam1
, DWORD dwParam2
)
76 WAVEMAPDATA
* wom
= (WAVEMAPDATA
*)dwInstance
;
78 TRACE("(%p %u %ld %lx %lx);\n", hWave
, uMsg
, dwInstance
, dwParam1
, dwParam2
);
80 if (!WAVEMAP_IsData(wom
)) {
85 if (hWave
!= wom
->u
.out
.hInnerWave
&& uMsg
!= WOM_OPEN
)
86 ERR("Shouldn't happen (%p %p)\n", hWave
, wom
->u
.out
.hInnerWave
);
91 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
94 if (wom
->hAcmStream
) {
95 LPWAVEHDR lpWaveHdrDst
= (LPWAVEHDR
)dwParam1
;
96 PACMSTREAMHEADER ash
= (PACMSTREAMHEADER
)((LPSTR
)lpWaveHdrDst
- sizeof(ACMSTREAMHEADER
));
97 LPWAVEHDR lpWaveHdrSrc
= (LPWAVEHDR
)ash
->dwUser
;
99 lpWaveHdrSrc
->dwFlags
&= ~WHDR_INQUEUE
;
100 lpWaveHdrSrc
->dwFlags
|= WHDR_DONE
;
101 dwParam1
= (DWORD
)lpWaveHdrSrc
;
105 ERR("Unknown msg %u\n", uMsg
);
108 DriverCallback(wom
->dwCallback
, HIWORD(wom
->dwFlags
), (HDRVR
)wom
->u
.out
.hOuterWave
,
109 uMsg
, wom
->dwClientInstance
, dwParam1
, dwParam2
);
112 /******************************************************************
117 static DWORD
wodOpenHelper(WAVEMAPDATA
* wom
, UINT idx
,
118 LPWAVEOPENDESC lpDesc
, LPWAVEFORMATEX lpwfx
,
123 /* destination is always PCM, so the formulas below apply */
124 lpwfx
->nBlockAlign
= (lpwfx
->nChannels
* lpwfx
->wBitsPerSample
) / 8;
125 lpwfx
->nAvgBytesPerSec
= lpwfx
->nSamplesPerSec
* lpwfx
->nBlockAlign
;
126 if (dwFlags
& WAVE_FORMAT_QUERY
) {
127 ret
= acmStreamOpen(NULL
, 0, lpDesc
->lpFormat
, lpwfx
, NULL
, 0L, 0L, ACM_STREAMOPENF_QUERY
);
129 ret
= acmStreamOpen(&wom
->hAcmStream
, 0, lpDesc
->lpFormat
, lpwfx
, NULL
, 0L, 0L, 0L);
131 if (ret
== MMSYSERR_NOERROR
) {
132 ret
= waveOutOpen(&wom
->u
.out
.hInnerWave
, idx
, lpwfx
, (DWORD
)wodCallback
,
133 (DWORD
)wom
, (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
);
134 if (ret
!= MMSYSERR_NOERROR
&& !(dwFlags
& WAVE_FORMAT_QUERY
)) {
135 acmStreamClose(wom
->hAcmStream
, 0);
142 static DWORD
wodOpen(LPDWORD lpdwUser
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
146 WAVEMAPDATA
* wom
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA
));
148 TRACE("(%p %p %08lx\n", lpdwUser
, lpDesc
, dwFlags
);
151 return MMSYSERR_NOMEM
;
153 ndhi
= waveOutGetNumDevs();
154 if (dwFlags
& WAVE_MAPPED
) {
155 if (lpDesc
->uMappedDeviceID
>= ndhi
) return MMSYSERR_INVALPARAM
;
156 ndlo
= lpDesc
->uMappedDeviceID
;
158 dwFlags
&= ~WAVE_MAPPED
;
163 wom
->dwCallback
= lpDesc
->dwCallback
;
164 wom
->dwFlags
= dwFlags
;
165 wom
->dwClientInstance
= lpDesc
->dwInstance
;
166 wom
->u
.out
.hOuterWave
= (HWAVEOUT
)lpDesc
->hWave
;
167 wom
->avgSpeedOuter
= wom
->avgSpeedInner
= lpDesc
->lpFormat
->nAvgBytesPerSec
;
169 for (i
= ndlo
; i
< ndhi
; i
++) {
170 /* if no ACM stuff is involved, no need to handle callbacks at this
171 * level, this will be done transparently
173 if (waveOutOpen(&wom
->u
.out
.hInnerWave
, i
, lpDesc
->lpFormat
, (DWORD
)wodCallback
,
174 (DWORD
)wom
, (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
| WAVE_FORMAT_DIRECT
) == MMSYSERR_NOERROR
) {
180 if ((dwFlags
& WAVE_FORMAT_DIRECT
) == 0) {
183 wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
184 wfx
.cbSize
= 0; /* normally, this field is not used for PCM format, just in case */
185 /* try some ACM stuff */
187 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
188 if (wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) \
189 {wom->avgSpeedInner = wfx.nAvgBytesPerSec; goto found;}
191 /* Our resampling algorithm is quite primitive so first try
192 * to just change the bit depth and number of channels
194 for (i
= ndlo
; i
< ndhi
; i
++) {
195 wfx
.nSamplesPerSec
=lpDesc
->lpFormat
->nSamplesPerSec
;
196 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
197 TRY(wfx
.nSamplesPerSec
, 16);
198 TRY(wfx
.nSamplesPerSec
, 8);
200 TRY(wfx
.nSamplesPerSec
, 16);
201 TRY(wfx
.nSamplesPerSec
, 8);
204 for (i
= ndlo
; i
< ndhi
; i
++) {
205 /* first try with same stereo/mono option as source */
206 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
213 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
221 /* first try with same stereo/mono option as source */
222 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
229 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
240 HeapFree(GetProcessHeap(), 0, wom
);
241 return WAVERR_BADFORMAT
;
244 if (dwFlags
& WAVE_FORMAT_QUERY
) {
246 HeapFree(GetProcessHeap(), 0, wom
);
248 *lpdwUser
= (DWORD
)wom
;
250 return MMSYSERR_NOERROR
;
253 static DWORD
wodClose(WAVEMAPDATA
* wom
)
255 DWORD ret
= waveOutClose(wom
->u
.out
.hInnerWave
);
257 if (ret
== MMSYSERR_NOERROR
) {
258 if (wom
->hAcmStream
) {
259 ret
= acmStreamClose(wom
->hAcmStream
, 0);
261 if (ret
== MMSYSERR_NOERROR
) {
262 HeapFree(GetProcessHeap(), 0, wom
);
268 static DWORD
wodWrite(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
270 PACMSTREAMHEADER ash
;
271 LPWAVEHDR lpWaveHdrDst
;
273 if (!wom
->hAcmStream
) {
274 return waveOutWrite(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
277 lpWaveHdrSrc
->dwFlags
|= WHDR_INQUEUE
;
278 ash
= (PACMSTREAMHEADER
)lpWaveHdrSrc
->reserved
;
279 /* acmStreamConvert will actually check that the new size is less than initial size */
280 ash
->cbSrcLength
= lpWaveHdrSrc
->dwBufferLength
;
281 if (acmStreamConvert(wom
->hAcmStream
, ash
, 0L) != MMSYSERR_NOERROR
)
282 return MMSYSERR_ERROR
;
284 lpWaveHdrDst
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
285 if (ash
->cbSrcLength
> ash
->cbSrcLengthUsed
)
286 FIXME("Not all src buffer has been written, expect bogus sound\n");
287 else if (ash
->cbSrcLength
< ash
->cbSrcLengthUsed
)
288 ERR("CoDec has read more data than it is allowed to\n");
290 if (ash
->cbDstLengthUsed
== 0)
292 /* something went wrong in decoding */
293 FIXME("Got 0 length\n");
294 return MMSYSERR_ERROR
;
296 lpWaveHdrDst
->dwBufferLength
= ash
->cbDstLengthUsed
;
297 return waveOutWrite(wom
->u
.out
.hInnerWave
, lpWaveHdrDst
, sizeof(*lpWaveHdrDst
));
300 static DWORD
wodPrepare(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
302 PACMSTREAMHEADER ash
;
305 LPWAVEHDR lpWaveHdrDst
;
307 if (!wom
->hAcmStream
) {
308 return waveOutPrepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
310 if (acmStreamSize(wom
->hAcmStream
, lpWaveHdrSrc
->dwBufferLength
, &size
, ACM_STREAMSIZEF_SOURCE
) != MMSYSERR_NOERROR
)
311 return MMSYSERR_ERROR
;
313 ash
= HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
) + size
);
315 return MMSYSERR_NOMEM
;
317 ash
->cbStruct
= sizeof(*ash
);
319 ash
->dwUser
= (DWORD
)lpWaveHdrSrc
;
320 ash
->pbSrc
= lpWaveHdrSrc
->lpData
;
321 ash
->cbSrcLength
= lpWaveHdrSrc
->dwBufferLength
;
322 /* ash->cbSrcLengthUsed */
323 ash
->dwSrcUser
= lpWaveHdrSrc
->dwUser
; /* FIXME ? */
324 ash
->pbDst
= (LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
);
325 ash
->cbDstLength
= size
;
326 /* ash->cbDstLengthUsed */
327 ash
->dwDstUser
= 0; /* FIXME ? */
328 dwRet
= acmStreamPrepareHeader(wom
->hAcmStream
, ash
, 0L);
329 if (dwRet
!= MMSYSERR_NOERROR
)
332 lpWaveHdrDst
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
333 lpWaveHdrDst
->lpData
= ash
->pbDst
;
334 lpWaveHdrDst
->dwBufferLength
= size
; /* conversion is not done yet */
335 lpWaveHdrDst
->dwFlags
= 0;
336 lpWaveHdrDst
->dwLoops
= 0;
337 dwRet
= waveOutPrepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrDst
, sizeof(*lpWaveHdrDst
));
338 if (dwRet
!= MMSYSERR_NOERROR
)
341 lpWaveHdrSrc
->reserved
= (DWORD
)ash
;
342 lpWaveHdrSrc
->dwFlags
= WHDR_PREPARED
;
344 return MMSYSERR_NOERROR
;
346 TRACE("=> (%ld)\n", dwRet
);
347 HeapFree(GetProcessHeap(), 0, ash
);
351 static DWORD
wodUnprepare(WAVEMAPDATA
* wom
, LPWAVEHDR lpWaveHdrSrc
, DWORD dwParam2
)
353 PACMSTREAMHEADER ash
;
354 LPWAVEHDR lpWaveHdrDst
;
355 DWORD dwRet1
, dwRet2
;
357 if (!wom
->hAcmStream
) {
358 return waveOutUnprepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrSrc
, dwParam2
);
360 ash
= (PACMSTREAMHEADER
)lpWaveHdrSrc
->reserved
;
361 dwRet1
= acmStreamUnprepareHeader(wom
->hAcmStream
, ash
, 0L);
363 lpWaveHdrDst
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
364 dwRet2
= waveOutUnprepareHeader(wom
->u
.out
.hInnerWave
, lpWaveHdrDst
, sizeof(*lpWaveHdrDst
));
366 HeapFree(GetProcessHeap(), 0, ash
);
368 lpWaveHdrSrc
->dwFlags
&= ~WHDR_PREPARED
;
369 return (dwRet1
== MMSYSERR_NOERROR
) ? dwRet2
: dwRet1
;
372 static DWORD
wodGetPosition(WAVEMAPDATA
* wom
, LPMMTIME lpTime
, DWORD dwParam2
)
374 DWORD val
= waveOutGetPosition(wom
->u
.out
.hInnerWave
, lpTime
, dwParam2
);
375 if (lpTime
->wType
== TIME_BYTES
)
376 val
= MulDiv(val
, wom
->avgSpeedOuter
, wom
->avgSpeedInner
);
377 /* other time types don't require conversion */
381 static DWORD
wodGetDevCaps(UINT wDevID
, WAVEMAPDATA
* wom
, LPWAVEOUTCAPSA lpWaveCaps
, DWORD dwParam2
)
383 /* if opened low driver, forward message */
384 if (WAVEMAP_IsData(wom
))
385 return waveOutGetDevCapsA((UINT
)wom
->u
.out
.hInnerWave
, lpWaveCaps
, dwParam2
);
386 /* otherwise, return caps of mapper itself */
387 if (wDevID
== (UINT
)-1 || wDevID
== (UINT16
)-1) {
388 lpWaveCaps
->wMid
= 0x00FF;
389 lpWaveCaps
->wPid
= 0x0001;
390 lpWaveCaps
->vDriverVersion
= 0x0100;
391 strcpy(lpWaveCaps
->szPname
, "Wine wave out mapper");
392 lpWaveCaps
->dwFormats
=
393 WAVE_FORMAT_4M08
| WAVE_FORMAT_4S08
| WAVE_FORMAT_4M16
| WAVE_FORMAT_4S16
|
394 WAVE_FORMAT_2M08
| WAVE_FORMAT_2S08
| WAVE_FORMAT_2M16
| WAVE_FORMAT_2S16
|
395 WAVE_FORMAT_1M08
| WAVE_FORMAT_1S08
| WAVE_FORMAT_1M16
| WAVE_FORMAT_1S16
;
396 lpWaveCaps
->wChannels
= 2;
397 lpWaveCaps
->dwSupport
= WAVECAPS_VOLUME
| WAVECAPS_LRVOLUME
;
399 return MMSYSERR_NOERROR
;
401 ERR("This shouldn't happen\n");
402 return MMSYSERR_ERROR
;
405 static DWORD
wodGetVolume(UINT wDevID
, WAVEMAPDATA
* wom
, LPDWORD lpVol
)
407 if (WAVEMAP_IsData(wom
))
408 return waveOutGetVolume((UINT
)wom
->u
.out
.hInnerWave
, lpVol
);
409 return MMSYSERR_NOERROR
;
412 static DWORD
wodSetVolume(UINT wDevID
, WAVEMAPDATA
* wom
, DWORD vol
)
414 if (WAVEMAP_IsData(wom
))
415 return waveOutSetVolume((UINT
)wom
->u
.out
.hInnerWave
, vol
);
416 return MMSYSERR_NOERROR
;
419 static DWORD
wodPause(WAVEMAPDATA
* wom
)
421 return waveOutPause(wom
->u
.out
.hInnerWave
);
424 static DWORD
wodRestart(WAVEMAPDATA
* wom
)
426 return waveOutRestart(wom
->u
.out
.hInnerWave
);
429 static DWORD
wodReset(WAVEMAPDATA
* wom
)
431 return waveOutReset(wom
->u
.out
.hInnerWave
);
434 static DWORD
wodBreakLoop(WAVEMAPDATA
* wom
)
436 return waveOutBreakLoop(wom
->u
.out
.hInnerWave
);
439 static DWORD
wodMapperStatus(WAVEMAPDATA
* wom
, DWORD flags
, LPVOID ptr
)
442 DWORD ret
= MMSYSERR_NOTSUPPORTED
;
445 case WAVEOUT_MAPPER_STATUS_DEVICE
:
446 ret
= waveOutGetID(wom
->u
.out
.hInnerWave
, &id
);
449 case WAVEOUT_MAPPER_STATUS_MAPPED
:
450 FIXME("Unsupported flag=%ld\n", flags
);
451 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
453 case WAVEOUT_MAPPER_STATUS_FORMAT
:
454 FIXME("Unsupported flag=%ld\n", flags
);
455 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
459 FIXME("Unsupported flag=%ld\n", flags
);
466 /**************************************************************************
467 * wodMessage (MSACM.@)
469 DWORD WINAPI
WAVEMAP_wodMessage(UINT wDevID
, UINT wMsg
, DWORD dwUser
,
470 DWORD dwParam1
, DWORD dwParam2
)
472 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
473 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
480 /* FIXME: Pretend this is supported */
482 case WODM_OPEN
: return wodOpen ((LPDWORD
)dwUser
, (LPWAVEOPENDESC
)dwParam1
,dwParam2
);
483 case WODM_CLOSE
: return wodClose ((WAVEMAPDATA
*)dwUser
);
484 case WODM_WRITE
: return wodWrite ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
485 case WODM_PAUSE
: return wodPause ((WAVEMAPDATA
*)dwUser
);
486 case WODM_GETPOS
: return wodGetPosition ((WAVEMAPDATA
*)dwUser
, (LPMMTIME
)dwParam1
, dwParam2
);
487 case WODM_BREAKLOOP
: return wodBreakLoop ((WAVEMAPDATA
*)dwUser
);
488 case WODM_PREPARE
: return wodPrepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
489 case WODM_UNPREPARE
: return wodUnprepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
490 case WODM_GETDEVCAPS
: return wodGetDevCaps (wDevID
, (WAVEMAPDATA
*)dwUser
, (LPWAVEOUTCAPSA
)dwParam1
,dwParam2
);
491 case WODM_GETNUMDEVS
: return 1;
492 case WODM_GETPITCH
: return MMSYSERR_NOTSUPPORTED
;
493 case WODM_SETPITCH
: return MMSYSERR_NOTSUPPORTED
;
494 case WODM_GETPLAYBACKRATE
: return MMSYSERR_NOTSUPPORTED
;
495 case WODM_SETPLAYBACKRATE
: return MMSYSERR_NOTSUPPORTED
;
496 case WODM_GETVOLUME
: return wodGetVolume (wDevID
, (WAVEMAPDATA
*)dwUser
, (LPDWORD
)dwParam1
);
497 case WODM_SETVOLUME
: return wodSetVolume (wDevID
, (WAVEMAPDATA
*)dwUser
, dwParam1
);
498 case WODM_RESTART
: return wodRestart ((WAVEMAPDATA
*)dwUser
);
499 case WODM_RESET
: return wodReset ((WAVEMAPDATA
*)dwUser
);
500 case WODM_MAPPER_STATUS
: return wodMapperStatus ((WAVEMAPDATA
*)dwUser
, dwParam1
, (LPVOID
)dwParam2
);
502 FIXME("unknown message %d!\n", wMsg
);
504 return MMSYSERR_NOTSUPPORTED
;
507 /*======================================================================*
509 *======================================================================*/
511 static void CALLBACK
widCallback(HWAVEIN hWave
, UINT uMsg
, DWORD dwInstance
,
512 DWORD dwParam1
, DWORD dwParam2
)
514 WAVEMAPDATA
* wim
= (WAVEMAPDATA
*)dwInstance
;
516 TRACE("(%p %u %ld %lx %lx);\n", hWave
, uMsg
, dwInstance
, dwParam1
, dwParam2
);
518 if (!WAVEMAP_IsData(wim
)) {
523 if (hWave
!= wim
->u
.in
.hInnerWave
&& uMsg
!= WIM_OPEN
)
524 ERR("Shouldn't happen (%p %p)\n", hWave
, wim
->u
.in
.hInnerWave
);
529 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
532 if (wim
->hAcmStream
) {
533 LPWAVEHDR lpWaveHdrSrc
= (LPWAVEHDR
)dwParam1
;
534 PACMSTREAMHEADER ash
= (PACMSTREAMHEADER
)((LPSTR
)lpWaveHdrSrc
- sizeof(ACMSTREAMHEADER
));
535 LPWAVEHDR lpWaveHdrDst
= (LPWAVEHDR
)ash
->dwUser
;
537 /* convert data just gotten from waveIn into requested format */
538 if (acmStreamConvert(wim
->hAcmStream
, ash
, 0L) != MMSYSERR_NOERROR
) {
539 ERR("ACM conversion failed\n");
542 TRACE("Converted %ld bytes into %ld\n", ash
->cbSrcLengthUsed
, ash
->cbDstLengthUsed
);
544 /* and setup the wavehdr to return accordingly */
545 lpWaveHdrDst
->dwFlags
&= ~WHDR_INQUEUE
;
546 lpWaveHdrDst
->dwFlags
|= WHDR_DONE
;
547 lpWaveHdrDst
->dwBytesRecorded
= ash
->cbDstLengthUsed
;
548 dwParam1
= (DWORD
)lpWaveHdrDst
;
552 ERR("Unknown msg %u\n", uMsg
);
555 DriverCallback(wim
->dwCallback
, HIWORD(wim
->dwFlags
), (HDRVR
)wim
->u
.in
.hOuterWave
,
556 uMsg
, wim
->dwClientInstance
, dwParam1
, dwParam2
);
559 static DWORD
widOpenHelper(WAVEMAPDATA
* wim
, UINT idx
,
560 LPWAVEOPENDESC lpDesc
, LPWAVEFORMATEX lpwfx
,
565 /* source is always PCM, so the formulas below apply */
566 lpwfx
->nBlockAlign
= (lpwfx
->nChannels
* lpwfx
->wBitsPerSample
) / 8;
567 lpwfx
->nAvgBytesPerSec
= lpwfx
->nSamplesPerSec
* lpwfx
->nBlockAlign
;
568 if (dwFlags
& WAVE_FORMAT_QUERY
) {
569 ret
= acmStreamOpen(NULL
, 0, lpwfx
, lpDesc
->lpFormat
, NULL
, 0L, 0L, ACM_STREAMOPENF_QUERY
);
571 ret
= acmStreamOpen(&wim
->hAcmStream
, 0, lpwfx
, lpDesc
->lpFormat
, NULL
, 0L, 0L, 0L);
573 if (ret
== MMSYSERR_NOERROR
) {
574 ret
= waveInOpen(&wim
->u
.in
.hInnerWave
, idx
, lpwfx
, (DWORD
)widCallback
,
575 (DWORD
)wim
, (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
);
576 if (ret
!= MMSYSERR_NOERROR
&& !(dwFlags
& WAVE_FORMAT_QUERY
)) {
577 acmStreamClose(wim
->hAcmStream
, 0);
584 static DWORD
widOpen(LPDWORD lpdwUser
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
588 WAVEMAPDATA
* wim
= HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA
));
590 TRACE("(%p %p %08lx)\n", lpdwUser
, lpDesc
, dwFlags
);
593 return MMSYSERR_NOMEM
;
596 wim
->dwCallback
= lpDesc
->dwCallback
;
597 wim
->dwFlags
= dwFlags
;
598 wim
->dwClientInstance
= lpDesc
->dwInstance
;
599 wim
->u
.in
.hOuterWave
= (HWAVEIN
)lpDesc
->hWave
;
601 ndhi
= waveOutGetNumDevs();
602 if (dwFlags
& WAVE_MAPPED
) {
603 if (lpDesc
->uMappedDeviceID
>= ndhi
) return MMSYSERR_INVALPARAM
;
604 ndlo
= lpDesc
->uMappedDeviceID
;
606 dwFlags
&= ~WAVE_MAPPED
;
611 wim
->avgSpeedOuter
= wim
->avgSpeedInner
= lpDesc
->lpFormat
->nAvgBytesPerSec
;
613 for (i
= ndlo
; i
< ndhi
; i
++) {
614 if (waveInOpen(&wim
->u
.in
.hInnerWave
, i
, lpDesc
->lpFormat
, (DWORD
)widCallback
,
615 (DWORD
)wim
, (dwFlags
& ~CALLBACK_TYPEMASK
) | CALLBACK_FUNCTION
| WAVE_FORMAT_DIRECT
) == MMSYSERR_NOERROR
) {
621 if ((dwFlags
& WAVE_FORMAT_DIRECT
) == 0)
625 wfx
.wFormatTag
= WAVE_FORMAT_PCM
;
626 wfx
.cbSize
= 0; /* normally, this field is not used for PCM format, just in case */
627 /* try some ACM stuff */
629 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
630 if (widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) \
631 {wim->avgSpeedInner = wfx.nAvgBytesPerSec; goto found;}
633 for (i
= ndlo
; i
< ndhi
; i
++) {
634 /* first try with same stereo/mono option as source */
635 wfx
.nChannels
= lpDesc
->lpFormat
->nChannels
;
640 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
649 HeapFree(GetProcessHeap(), 0, wim
);
650 return MMSYSERR_ALLOCATED
;
652 if (dwFlags
& WAVE_FORMAT_QUERY
) {
654 HeapFree(GetProcessHeap(), 0, wim
);
656 *lpdwUser
= (DWORD
)wim
;
658 TRACE("Ok (stream=%08lx)\n", (DWORD
)wim
->hAcmStream
);
659 return MMSYSERR_NOERROR
;
662 static DWORD
widClose(WAVEMAPDATA
* wim
)
664 DWORD ret
= waveInClose(wim
->u
.in
.hInnerWave
);
666 if (ret
== MMSYSERR_NOERROR
) {
667 if (wim
->hAcmStream
) {
668 ret
= acmStreamClose(wim
->hAcmStream
, 0);
670 if (ret
== MMSYSERR_NOERROR
) {
671 HeapFree(GetProcessHeap(), 0, wim
);
677 static DWORD
widAddBuffer(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
679 PACMSTREAMHEADER ash
;
680 LPWAVEHDR lpWaveHdrSrc
;
682 if (!wim
->hAcmStream
) {
683 return waveInAddBuffer(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
686 lpWaveHdrDst
->dwFlags
|= WHDR_INQUEUE
;
687 ash
= (PACMSTREAMHEADER
)lpWaveHdrDst
->reserved
;
689 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
690 return waveInAddBuffer(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
693 static DWORD
widPrepare(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
695 PACMSTREAMHEADER ash
;
698 LPWAVEHDR lpWaveHdrSrc
;
700 if (!wim
->hAcmStream
) {
701 return waveInPrepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
703 if (acmStreamSize(wim
->hAcmStream
, lpWaveHdrDst
->dwBufferLength
, &size
,
704 ACM_STREAMSIZEF_DESTINATION
) != MMSYSERR_NOERROR
)
705 return MMSYSERR_ERROR
;
707 ash
= HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
) + size
);
709 return MMSYSERR_NOMEM
;
711 ash
->cbStruct
= sizeof(*ash
);
713 ash
->dwUser
= (DWORD
)lpWaveHdrDst
;
714 ash
->pbSrc
= (LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
) + sizeof(WAVEHDR
);
715 ash
->cbSrcLength
= size
;
716 /* ash->cbSrcLengthUsed */
717 ash
->dwSrcUser
= 0L; /* FIXME ? */
718 ash
->pbDst
= lpWaveHdrDst
->lpData
;
719 ash
->cbDstLength
= lpWaveHdrDst
->dwBufferLength
;
720 /* ash->cbDstLengthUsed */
721 ash
->dwDstUser
= lpWaveHdrDst
->dwUser
; /* FIXME ? */
722 dwRet
= acmStreamPrepareHeader(wim
->hAcmStream
, ash
, 0L);
723 if (dwRet
!= MMSYSERR_NOERROR
)
726 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
727 lpWaveHdrSrc
->lpData
= ash
->pbSrc
;
728 lpWaveHdrSrc
->dwBufferLength
= size
; /* conversion is not done yet */
729 lpWaveHdrSrc
->dwFlags
= 0;
730 lpWaveHdrSrc
->dwLoops
= 0;
731 dwRet
= waveInPrepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
732 if (dwRet
!= MMSYSERR_NOERROR
)
735 lpWaveHdrDst
->reserved
= (DWORD
)ash
;
736 lpWaveHdrDst
->dwFlags
= WHDR_PREPARED
;
738 return MMSYSERR_NOERROR
;
740 TRACE("=> (%ld)\n", dwRet
);
741 HeapFree(GetProcessHeap(), 0, ash
);
745 static DWORD
widUnprepare(WAVEMAPDATA
* wim
, LPWAVEHDR lpWaveHdrDst
, DWORD dwParam2
)
747 PACMSTREAMHEADER ash
;
748 LPWAVEHDR lpWaveHdrSrc
;
749 DWORD dwRet1
, dwRet2
;
751 if (!wim
->hAcmStream
) {
752 return waveInUnprepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrDst
, dwParam2
);
754 ash
= (PACMSTREAMHEADER
)lpWaveHdrDst
->reserved
;
755 dwRet1
= acmStreamUnprepareHeader(wim
->hAcmStream
, ash
, 0L);
757 lpWaveHdrSrc
= (LPWAVEHDR
)((LPSTR
)ash
+ sizeof(ACMSTREAMHEADER
));
758 dwRet2
= waveInUnprepareHeader(wim
->u
.in
.hInnerWave
, lpWaveHdrSrc
, sizeof(*lpWaveHdrSrc
));
760 HeapFree(GetProcessHeap(), 0, ash
);
762 lpWaveHdrDst
->dwFlags
&= ~WHDR_PREPARED
;
763 return (dwRet1
== MMSYSERR_NOERROR
) ? dwRet2
: dwRet1
;
766 static DWORD
widGetPosition(WAVEMAPDATA
* wim
, LPMMTIME lpTime
, DWORD dwParam2
)
768 DWORD val
= waveInGetPosition(wim
->u
.in
.hInnerWave
, lpTime
, dwParam2
);
769 if (lpTime
->wType
== TIME_BYTES
)
770 val
= MulDiv(val
, wim
->avgSpeedOuter
, wim
->avgSpeedInner
);
771 /* other time types don't require conversion */
775 static DWORD
widGetDevCaps(UINT wDevID
, WAVEMAPDATA
* wim
, LPWAVEINCAPSA lpWaveCaps
, DWORD dwParam2
)
777 /* if opened low driver, forward message */
778 if (WAVEMAP_IsData(wim
))
779 return waveInGetDevCapsA((UINT
)wim
->u
.in
.hInnerWave
, lpWaveCaps
, dwParam2
);
780 /* otherwise, return caps of mapper itself */
781 if (wDevID
== (UINT
)-1 || wDevID
== (UINT16
)-1) {
782 lpWaveCaps
->wMid
= 0x00FF;
783 lpWaveCaps
->wPid
= 0x0001;
784 lpWaveCaps
->vDriverVersion
= 0x0001;
785 strcpy(lpWaveCaps
->szPname
, "Wine wave in mapper");
786 lpWaveCaps
->dwFormats
=
787 WAVE_FORMAT_4M08
| WAVE_FORMAT_4S08
| WAVE_FORMAT_4M16
| WAVE_FORMAT_4S16
|
788 WAVE_FORMAT_2M08
| WAVE_FORMAT_2S08
| WAVE_FORMAT_2M16
| WAVE_FORMAT_2S16
|
789 WAVE_FORMAT_1M08
| WAVE_FORMAT_1S08
| WAVE_FORMAT_1M16
| WAVE_FORMAT_1S16
;
790 lpWaveCaps
->wChannels
= 2;
791 return MMSYSERR_NOERROR
;
793 ERR("This shouldn't happen\n");
794 return MMSYSERR_ERROR
;
797 static DWORD
widStop(WAVEMAPDATA
* wim
)
799 return waveInStop(wim
->u
.in
.hInnerWave
);
802 static DWORD
widStart(WAVEMAPDATA
* wim
)
804 return waveInStart(wim
->u
.in
.hInnerWave
);
807 static DWORD
widReset(WAVEMAPDATA
* wim
)
809 return waveInReset(wim
->u
.in
.hInnerWave
);
812 static DWORD
widMapperStatus(WAVEMAPDATA
* wim
, DWORD flags
, LPVOID ptr
)
815 DWORD ret
= MMSYSERR_NOTSUPPORTED
;
818 case WAVEIN_MAPPER_STATUS_DEVICE
:
819 ret
= waveInGetID(wim
->u
.in
.hInnerWave
, &id
);
822 case WAVEIN_MAPPER_STATUS_MAPPED
:
823 FIXME("Unsupported yet flag=%ld\n", flags
);
824 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
826 case WAVEIN_MAPPER_STATUS_FORMAT
:
827 FIXME("Unsupported flag=%ld\n", flags
);
828 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
829 *(LPDWORD
)ptr
= 0; /* FIXME ?? */
832 FIXME("Unsupported flag=%ld\n", flags
);
839 /**************************************************************************
840 * widMessage (MSACM.@)
842 DWORD WINAPI
WAVEMAP_widMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
843 DWORD dwParam1
, DWORD dwParam2
)
845 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
846 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
853 /* FIXME: Pretend this is supported */
856 case WIDM_OPEN
: return widOpen ((LPDWORD
)dwUser
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
857 case WIDM_CLOSE
: return widClose ((WAVEMAPDATA
*)dwUser
);
859 case WIDM_ADDBUFFER
: return widAddBuffer ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
860 case WIDM_PREPARE
: return widPrepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
861 case WIDM_UNPREPARE
: return widUnprepare ((WAVEMAPDATA
*)dwUser
, (LPWAVEHDR
)dwParam1
, dwParam2
);
862 case WIDM_GETDEVCAPS
: return widGetDevCaps (wDevID
, (WAVEMAPDATA
*)dwUser
, (LPWAVEINCAPSA
)dwParam1
, dwParam2
);
863 case WIDM_GETNUMDEVS
: return 1;
864 case WIDM_GETPOS
: return widGetPosition ((WAVEMAPDATA
*)dwUser
, (LPMMTIME
)dwParam1
, dwParam2
);
865 case WIDM_RESET
: return widReset ((WAVEMAPDATA
*)dwUser
);
866 case WIDM_START
: return widStart ((WAVEMAPDATA
*)dwUser
);
867 case WIDM_STOP
: return widStop ((WAVEMAPDATA
*)dwUser
);
868 case WIDM_MAPPER_STATUS
: return widMapperStatus ((WAVEMAPDATA
*)dwUser
, dwParam1
, (LPVOID
)dwParam2
);
870 FIXME("unknown message %u!\n", wMsg
);
872 return MMSYSERR_NOTSUPPORTED
;
875 /*======================================================================*
877 *======================================================================*/
879 static struct WINE_WAVEMAP
* oss
= NULL
;
881 /**************************************************************************
882 * WAVEMAP_drvOpen [internal]
884 static DWORD
WAVEMAP_drvOpen(LPSTR str
)
889 /* I know, this is ugly, but who cares... */
890 oss
= (struct WINE_WAVEMAP
*)1;
894 /**************************************************************************
895 * WAVEMAP_drvClose [internal]
897 static DWORD
WAVEMAP_drvClose(DWORD dwDevID
)
906 /**************************************************************************
907 * DriverProc (MSACM.@)
909 LONG CALLBACK
WAVEMAP_DriverProc(DWORD dwDevID
, HDRVR hDriv
, DWORD wMsg
,
910 DWORD dwParam1
, DWORD dwParam2
)
912 TRACE("(%08lX, %p, %08lX, %08lX, %08lX)\n",
913 dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
916 case DRV_LOAD
: return 1;
917 case DRV_FREE
: return 1;
918 case DRV_OPEN
: return WAVEMAP_drvOpen((LPSTR
)dwParam1
);
919 case DRV_CLOSE
: return WAVEMAP_drvClose(dwDevID
);
920 case DRV_ENABLE
: return 1;
921 case DRV_DISABLE
: return 1;
922 case DRV_QUERYCONFIGURE
: return 1;
923 case DRV_CONFIGURE
: MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK
); return 1;
924 case DRV_INSTALL
: return DRVCNF_RESTART
;
925 case DRV_REMOVE
: return DRVCNF_RESTART
;
927 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);