Don't try to find alternate formats for non PCM formats.
[wine/wine64.git] / dlls / winmm / wavemap / wavemap.c
blob41a5ebe389110f5dbdbb4424da54a183ea5db264
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
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
22 /* TODOs
23 * + better protection against evilish dwUser parameters
24 * + use asynchronous ACM conversion
25 * + don't use callback functions when none is required in open
26 * + the buffer sizes may not be accurate, so there may be some
27 * remaining bytes in src and dst buffers after ACM conversions...
28 * those should be taken care of...
31 #include <stdarg.h>
32 #include <string.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wingdi.h"
36 #include "winuser.h"
37 #include "mmddk.h"
38 #include "mmreg.h"
39 #include "msacm.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(wavemap);
44 typedef struct tagWAVEMAPDATA {
45 struct tagWAVEMAPDATA* self;
46 union {
47 struct {
48 HWAVEOUT hOuterWave;
49 HWAVEOUT hInnerWave;
50 } out;
51 struct {
52 HWAVEIN hOuterWave;
53 HWAVEIN hInnerWave;
54 } in;
55 } u;
56 HACMSTREAM hAcmStream;
57 /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */
58 DWORD dwCallback;
59 DWORD dwClientInstance;
60 DWORD dwFlags;
61 /* ratio to compute position from a PCM playback to any format */
62 DWORD avgSpeedOuter;
63 DWORD avgSpeedInner;
64 } WAVEMAPDATA;
66 static BOOL WAVEMAP_IsData(WAVEMAPDATA* wm)
68 return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm);
71 /*======================================================================*
72 * WAVE OUT part *
73 *======================================================================*/
75 static void CALLBACK wodCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwInstance,
76 DWORD dwParam1, DWORD dwParam2)
78 WAVEMAPDATA* wom = (WAVEMAPDATA*)dwInstance;
80 TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
82 if (!WAVEMAP_IsData(wom)) {
83 ERR("Bad data\n");
84 return;
87 if (hWave != wom->u.out.hInnerWave && uMsg != WOM_OPEN)
88 ERR("Shouldn't happen (%p %p)\n", hWave, wom->u.out.hInnerWave);
90 switch (uMsg) {
91 case WOM_OPEN:
92 case WOM_CLOSE:
93 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
94 break;
95 case WOM_DONE:
96 if (wom->hAcmStream) {
97 LPWAVEHDR lpWaveHdrDst = (LPWAVEHDR)dwParam1;
98 PACMSTREAMHEADER ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER));
99 LPWAVEHDR lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser;
101 lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE;
102 lpWaveHdrSrc->dwFlags |= WHDR_DONE;
103 dwParam1 = (DWORD)lpWaveHdrSrc;
105 break;
106 default:
107 ERR("Unknown msg %u\n", uMsg);
110 DriverCallback(wom->dwCallback, HIWORD(wom->dwFlags), (HDRVR)wom->u.out.hOuterWave,
111 uMsg, wom->dwClientInstance, dwParam1, dwParam2);
114 /******************************************************************
115 * wodOpenHelper
119 static DWORD wodOpenHelper(WAVEMAPDATA* wom, UINT idx,
120 LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx,
121 DWORD dwFlags)
123 DWORD ret;
125 TRACE("(%p %04x %p %p %08lx)\n", wom, idx, lpDesc, lpwfx, dwFlags);
127 /* destination is always PCM, so the formulas below apply */
128 lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
129 lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
130 if (dwFlags & WAVE_FORMAT_QUERY) {
131 ret = acmStreamOpen(NULL, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);
132 } else {
133 ret = acmStreamOpen(&wom->hAcmStream, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, 0L);
135 if (ret == MMSYSERR_NOERROR) {
136 ret = waveOutOpen(&wom->u.out.hInnerWave, idx, lpwfx, (DWORD)wodCallback,
137 (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
138 if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
139 acmStreamClose(wom->hAcmStream, 0);
140 wom->hAcmStream = 0;
143 TRACE("ret = %08lx\n", ret);
144 return ret;
147 static DWORD wodOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
149 UINT ndlo, ndhi;
150 UINT i;
151 WAVEMAPDATA* wom = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
152 DWORD res;
154 TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags);
156 if (!wom) {
157 WARN("no memory\n");
158 return MMSYSERR_NOMEM;
161 ndhi = waveOutGetNumDevs();
162 if (dwFlags & WAVE_MAPPED) {
163 if (lpDesc->uMappedDeviceID >= ndhi) {
164 WARN("invalid parameter: dwFlags WAVE_MAPPED\n");
165 return MMSYSERR_INVALPARAM;
167 ndlo = lpDesc->uMappedDeviceID;
168 ndhi = ndlo + 1;
169 dwFlags &= ~WAVE_MAPPED;
170 } else {
171 ndlo = 0;
173 wom->self = wom;
174 wom->dwCallback = lpDesc->dwCallback;
175 wom->dwFlags = dwFlags;
176 wom->dwClientInstance = lpDesc->dwInstance;
177 wom->u.out.hOuterWave = (HWAVEOUT)lpDesc->hWave;
178 wom->avgSpeedOuter = wom->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;
180 for (i = ndlo; i < ndhi; i++) {
181 /* if no ACM stuff is involved, no need to handle callbacks at this
182 * level, this will be done transparently
184 if (waveOutOpen(&wom->u.out.hInnerWave, i, lpDesc->lpFormat, (DWORD)wodCallback,
185 (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) {
186 wom->hAcmStream = 0;
187 goto found;
191 if ((dwFlags & WAVE_FORMAT_DIRECT) == 0 && lpDesc->lpFormat->wFormatTag == WAVE_FORMAT_PCM) {
192 WAVEFORMATEX wfx;
194 wfx.wFormatTag = WAVE_FORMAT_PCM;
195 wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
196 /* try some ACM stuff */
198 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
199 switch (res=wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
200 case MMSYSERR_NOERROR: wom->avgSpeedInner = wfx.nAvgBytesPerSec; goto found; \
201 case WAVERR_BADFORMAT: break; \
202 default: goto error; \
205 /* Our resampling algorithm is quite primitive so first try
206 * to just change the bit depth and number of channels
208 for (i = ndlo; i < ndhi; i++) {
209 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
210 wfx.nChannels = lpDesc->lpFormat->nChannels;
211 TRY(wfx.nSamplesPerSec, 16);
212 TRY(wfx.nSamplesPerSec, 8);
213 wfx.nChannels ^= 3;
214 TRY(wfx.nSamplesPerSec, 16);
215 TRY(wfx.nSamplesPerSec, 8);
218 for (i = ndlo; i < ndhi; i++) {
219 /* first try with same stereo/mono option as source */
220 wfx.nChannels = lpDesc->lpFormat->nChannels;
221 TRY(96000, 16);
222 TRY(48000, 16);
223 TRY(44100, 16);
224 TRY(22050, 16);
225 TRY(11025, 16);
227 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
228 wfx.nChannels ^= 3;
229 TRY(96000, 16);
230 TRY(48000, 16);
231 TRY(44100, 16);
232 TRY(22050, 16);
233 TRY(11025, 16);
235 /* first try with same stereo/mono option as source */
236 wfx.nChannels = lpDesc->lpFormat->nChannels;
237 TRY(96000, 8);
238 TRY(48000, 8);
239 TRY(44100, 8);
240 TRY(22050, 8);
241 TRY(11025, 8);
243 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
244 wfx.nChannels ^= 3;
245 TRY(96000, 8);
246 TRY(48000, 8);
247 TRY(44100, 8);
248 TRY(22050, 8);
249 TRY(11025, 8);
251 #undef TRY
254 HeapFree(GetProcessHeap(), 0, wom);
255 WARN("ret = WAVERR_BADFORMAT\n");
256 return WAVERR_BADFORMAT;
258 found:
259 if (dwFlags & WAVE_FORMAT_QUERY) {
260 *lpdwUser = 0L;
261 HeapFree(GetProcessHeap(), 0, wom);
262 } else {
263 *lpdwUser = (DWORD)wom;
265 return MMSYSERR_NOERROR;
266 error:
267 HeapFree(GetProcessHeap(), 0, wom);
268 if (res==ACMERR_NOTPOSSIBLE) {
269 WARN("ret = WAVERR_BADFORMAT\n");
270 return WAVERR_BADFORMAT;
272 WARN("ret = MMSYSERR_ERROR\n");
273 return MMSYSERR_ERROR;
276 static DWORD wodClose(WAVEMAPDATA* wom)
278 DWORD ret;
280 TRACE("(%p)\n", wom);
282 ret = waveOutClose(wom->u.out.hInnerWave);
283 if (ret == MMSYSERR_NOERROR) {
284 if (wom->hAcmStream) {
285 ret = acmStreamClose(wom->hAcmStream, 0);
287 if (ret == MMSYSERR_NOERROR) {
288 HeapFree(GetProcessHeap(), 0, wom);
291 return ret;
294 static DWORD wodWrite(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
296 PACMSTREAMHEADER ash;
297 LPWAVEHDR lpWaveHdrDst;
299 TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2);
301 if (!wom->hAcmStream) {
302 return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
305 lpWaveHdrSrc->dwFlags |= WHDR_INQUEUE;
306 ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
307 /* acmStreamConvert will actually check that the new size is less than initial size */
308 ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
309 if (acmStreamConvert(wom->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) {
310 WARN("acmStreamConvert failed\n");
311 return MMSYSERR_ERROR;
314 lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
315 if (ash->cbSrcLength > ash->cbSrcLengthUsed)
316 FIXME("Not all src buffer has been written, expect bogus sound\n");
317 else if (ash->cbSrcLength < ash->cbSrcLengthUsed)
318 ERR("CoDec has read more data than it is allowed to\n");
320 if (ash->cbDstLengthUsed == 0) {
321 /* something went wrong in decoding */
322 FIXME("Got 0 length\n");
323 return MMSYSERR_ERROR;
325 lpWaveHdrDst->dwBufferLength = ash->cbDstLengthUsed;
326 return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
329 static DWORD wodPrepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
331 PACMSTREAMHEADER ash;
332 DWORD size;
333 DWORD dwRet;
334 LPWAVEHDR lpWaveHdrDst;
336 TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2);
338 if (!wom->hAcmStream)
339 return waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
341 if (acmStreamSize(wom->hAcmStream, lpWaveHdrSrc->dwBufferLength, &size, ACM_STREAMSIZEF_SOURCE) != MMSYSERR_NOERROR) {
342 WARN("acmStreamSize failed\n");
343 return MMSYSERR_ERROR;
346 ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
347 if (ash == NULL) {
348 WARN("no memory\n");
349 return MMSYSERR_NOMEM;
352 ash->cbStruct = sizeof(*ash);
353 ash->fdwStatus = 0L;
354 ash->dwUser = (DWORD)lpWaveHdrSrc;
355 ash->pbSrc = lpWaveHdrSrc->lpData;
356 ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
357 /* ash->cbSrcLengthUsed */
358 ash->dwSrcUser = lpWaveHdrSrc->dwUser; /* FIXME ? */
359 ash->pbDst = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
360 ash->cbDstLength = size;
361 /* ash->cbDstLengthUsed */
362 ash->dwDstUser = 0; /* FIXME ? */
363 dwRet = acmStreamPrepareHeader(wom->hAcmStream, ash, 0L);
364 if (dwRet != MMSYSERR_NOERROR) {
365 WARN("acmStreamPrepareHeader failed\n");
366 goto errCleanUp;
369 lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
370 lpWaveHdrDst->lpData = ash->pbDst;
371 lpWaveHdrDst->dwBufferLength = size; /* conversion is not done yet */
372 lpWaveHdrDst->dwFlags = 0;
373 lpWaveHdrDst->dwLoops = 0;
374 dwRet = waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
375 if (dwRet != MMSYSERR_NOERROR) {
376 WARN("waveOutPrepareHeader failed\n");
377 goto errCleanUp;
380 lpWaveHdrSrc->reserved = (DWORD)ash;
381 lpWaveHdrSrc->dwFlags = WHDR_PREPARED;
382 TRACE("=> (0)\n");
383 return MMSYSERR_NOERROR;
384 errCleanUp:
385 TRACE("=> (%ld)\n", dwRet);
386 HeapFree(GetProcessHeap(), 0, ash);
387 return dwRet;
390 static DWORD wodUnprepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
392 PACMSTREAMHEADER ash;
393 LPWAVEHDR lpWaveHdrDst;
394 DWORD dwRet1, dwRet2;
396 TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2);
398 if (!wom->hAcmStream) {
399 return waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
401 ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
402 dwRet1 = acmStreamUnprepareHeader(wom->hAcmStream, ash, 0L);
404 lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
405 dwRet2 = waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
407 HeapFree(GetProcessHeap(), 0, ash);
409 lpWaveHdrSrc->dwFlags &= ~WHDR_PREPARED;
410 return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
413 static DWORD wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2)
415 DWORD val;
416 TRACE("(%p %p %08lx)\n", wom, lpTime, dwParam2);
418 val = waveOutGetPosition(wom->u.out.hInnerWave, lpTime, dwParam2);
419 if (lpTime->wType == TIME_BYTES)
420 lpTime->u.cb = MulDiv(lpTime->u.cb, wom->avgSpeedOuter, wom->avgSpeedInner);
421 /* other time types don't require conversion */
422 return val;
425 static DWORD wodGetDevCaps(UINT wDevID, WAVEMAPDATA* wom, LPWAVEOUTCAPSA lpWaveCaps, DWORD dwParam2)
427 TRACE("(%04x %p %p %08lx)\n",wDevID, wom, lpWaveCaps, dwParam2);
429 /* if opened low driver, forward message */
430 if (WAVEMAP_IsData(wom))
431 return waveOutGetDevCapsA((UINT)wom->u.out.hInnerWave, lpWaveCaps, dwParam2);
432 /* else if no drivers, nothing to map so return bad device */
433 if (waveOutGetNumDevs() == 0) {
434 WARN("bad device id\n");
435 return MMSYSERR_BADDEVICEID;
437 /* otherwise, return caps of mapper itself */
438 if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
439 WAVEOUTCAPSA woc;
440 woc.wMid = 0x00FF;
441 woc.wPid = 0x0001;
442 woc.vDriverVersion = 0x0100;
443 strcpy(woc.szPname, "Wine wave out mapper");
444 woc.dwFormats =
445 WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 |
446 WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 |
447 WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
448 WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
449 WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
450 woc.wChannels = 2;
451 woc.dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME;
452 memcpy(lpWaveCaps, &woc, min(dwParam2, sizeof(woc)));
454 return MMSYSERR_NOERROR;
456 ERR("This shouldn't happen\n");
457 return MMSYSERR_ERROR;
460 static DWORD wodGetVolume(UINT wDevID, WAVEMAPDATA* wom, LPDWORD lpVol)
462 TRACE("(%04x %p %p)\n",wDevID, wom, lpVol);
464 if (WAVEMAP_IsData(wom))
465 return waveOutGetVolume(wom->u.out.hInnerWave, lpVol);
466 return MMSYSERR_NOERROR;
469 static DWORD wodSetVolume(UINT wDevID, WAVEMAPDATA* wom, DWORD vol)
471 TRACE("(%04x %p %08lx)\n",wDevID, wom, vol);
473 if (WAVEMAP_IsData(wom))
474 return waveOutSetVolume(wom->u.out.hInnerWave, vol);
475 return MMSYSERR_NOERROR;
478 static DWORD wodPause(WAVEMAPDATA* wom)
480 TRACE("(%p)\n",wom);
482 return waveOutPause(wom->u.out.hInnerWave);
485 static DWORD wodRestart(WAVEMAPDATA* wom)
487 TRACE("(%p)\n",wom);
489 return waveOutRestart(wom->u.out.hInnerWave);
492 static DWORD wodReset(WAVEMAPDATA* wom)
494 TRACE("(%p)\n",wom);
496 return waveOutReset(wom->u.out.hInnerWave);
499 static DWORD wodBreakLoop(WAVEMAPDATA* wom)
501 TRACE("(%p)\n",wom);
503 return waveOutBreakLoop(wom->u.out.hInnerWave);
506 static DWORD wodMapperStatus(WAVEMAPDATA* wom, DWORD flags, LPVOID ptr)
508 UINT id;
509 DWORD ret = MMSYSERR_NOTSUPPORTED;
511 TRACE("(%p %08lx %p)\n",wom, flags, ptr);
513 switch (flags) {
514 case WAVEOUT_MAPPER_STATUS_DEVICE:
515 ret = waveOutGetID(wom->u.out.hInnerWave, &id);
516 *(LPDWORD)ptr = id;
517 break;
518 case WAVEOUT_MAPPER_STATUS_MAPPED:
519 FIXME("Unsupported flag=%ld\n", flags);
520 *(LPDWORD)ptr = 0; /* FIXME ?? */
521 break;
522 case WAVEOUT_MAPPER_STATUS_FORMAT:
523 FIXME("Unsupported flag=%ld\n", flags);
524 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
525 *(LPDWORD)ptr = 0;
526 break;
527 default:
528 FIXME("Unsupported flag=%ld\n", flags);
529 *(LPDWORD)ptr = 0;
530 break;
532 return ret;
535 /**************************************************************************
536 * wodMessage (MSACM.@)
538 DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
539 DWORD dwParam1, DWORD dwParam2)
541 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
542 wDevID, wMsg, dwUser, dwParam1, dwParam2);
544 switch (wMsg) {
545 case DRVM_INIT:
546 case DRVM_EXIT:
547 case DRVM_ENABLE:
548 case DRVM_DISABLE:
549 /* FIXME: Pretend this is supported */
550 return 0;
551 case WODM_OPEN: return wodOpen ((LPDWORD)dwUser, (LPWAVEOPENDESC)dwParam1,dwParam2);
552 case WODM_CLOSE: return wodClose ((WAVEMAPDATA*)dwUser);
553 case WODM_WRITE: return wodWrite ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
554 case WODM_PAUSE: return wodPause ((WAVEMAPDATA*)dwUser);
555 case WODM_GETPOS: return wodGetPosition ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, dwParam2);
556 case WODM_BREAKLOOP: return wodBreakLoop ((WAVEMAPDATA*)dwUser);
557 case WODM_PREPARE: return wodPrepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
558 case WODM_UNPREPARE: return wodUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
559 case WODM_GETDEVCAPS: return wodGetDevCaps (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSA)dwParam1,dwParam2);
560 case WODM_GETNUMDEVS: return 1;
561 case WODM_GETPITCH: return MMSYSERR_NOTSUPPORTED;
562 case WODM_SETPITCH: return MMSYSERR_NOTSUPPORTED;
563 case WODM_GETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED;
564 case WODM_SETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED;
565 case WODM_GETVOLUME: return wodGetVolume (wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1);
566 case WODM_SETVOLUME: return wodSetVolume (wDevID, (WAVEMAPDATA*)dwUser, dwParam1);
567 case WODM_RESTART: return wodRestart ((WAVEMAPDATA*)dwUser);
568 case WODM_RESET: return wodReset ((WAVEMAPDATA*)dwUser);
569 case WODM_MAPPER_STATUS: return wodMapperStatus ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
570 /* known but not supported */
571 case DRV_QUERYDEVICEINTERFACESIZE:
572 case DRV_QUERYDEVICEINTERFACE:
573 return MMSYSERR_NOTSUPPORTED;
574 default:
575 FIXME("unknown message %d!\n", wMsg);
577 return MMSYSERR_NOTSUPPORTED;
580 /*======================================================================*
581 * WAVE IN part *
582 *======================================================================*/
584 static void CALLBACK widCallback(HWAVEIN hWave, UINT uMsg, DWORD dwInstance,
585 DWORD dwParam1, DWORD dwParam2)
587 WAVEMAPDATA* wim = (WAVEMAPDATA*)dwInstance;
589 TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
591 if (!WAVEMAP_IsData(wim)) {
592 ERR("Bad data\n");
593 return;
596 if (hWave != wim->u.in.hInnerWave && uMsg != WIM_OPEN)
597 ERR("Shouldn't happen (%p %p)\n", hWave, wim->u.in.hInnerWave);
599 switch (uMsg) {
600 case WIM_OPEN:
601 case WIM_CLOSE:
602 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
603 break;
604 case WIM_DATA:
605 if (wim->hAcmStream) {
606 LPWAVEHDR lpWaveHdrSrc = (LPWAVEHDR)dwParam1;
607 PACMSTREAMHEADER ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrSrc - sizeof(ACMSTREAMHEADER));
608 LPWAVEHDR lpWaveHdrDst = (LPWAVEHDR)ash->dwUser;
610 /* convert data just gotten from waveIn into requested format */
611 if (acmStreamConvert(wim->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) {
612 ERR("ACM conversion failed\n");
613 return;
614 } else {
615 TRACE("Converted %ld bytes into %ld\n", ash->cbSrcLengthUsed, ash->cbDstLengthUsed);
617 /* and setup the wavehdr to return accordingly */
618 lpWaveHdrDst->dwFlags &= ~WHDR_INQUEUE;
619 lpWaveHdrDst->dwFlags |= WHDR_DONE;
620 lpWaveHdrDst->dwBytesRecorded = ash->cbDstLengthUsed;
621 dwParam1 = (DWORD)lpWaveHdrDst;
623 break;
624 default:
625 ERR("Unknown msg %u\n", uMsg);
628 DriverCallback(wim->dwCallback, HIWORD(wim->dwFlags), (HDRVR)wim->u.in.hOuterWave,
629 uMsg, wim->dwClientInstance, dwParam1, dwParam2);
632 static DWORD widOpenHelper(WAVEMAPDATA* wim, UINT idx,
633 LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx,
634 DWORD dwFlags)
636 DWORD ret;
638 TRACE("(%p %04x %p %p %08lx)\n", wim, idx, lpDesc, lpwfx, dwFlags);
640 /* source is always PCM, so the formulas below apply */
641 lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
642 lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
643 if (dwFlags & WAVE_FORMAT_QUERY) {
644 ret = acmStreamOpen(NULL, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);
645 } else {
646 ret = acmStreamOpen(&wim->hAcmStream, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, 0L);
648 if (ret == MMSYSERR_NOERROR) {
649 ret = waveInOpen(&wim->u.in.hInnerWave, idx, lpwfx, (DWORD)widCallback,
650 (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
651 if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
652 acmStreamClose(wim->hAcmStream, 0);
653 wim->hAcmStream = 0;
656 TRACE("ret = %08lx\n", ret);
657 return ret;
660 static DWORD widOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
662 UINT ndlo, ndhi;
663 UINT i;
664 WAVEMAPDATA* wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
665 DWORD res;
667 TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags);
669 if (!wim) {
670 WARN("no memory\n");
671 return MMSYSERR_NOMEM;
674 wim->self = wim;
675 wim->dwCallback = lpDesc->dwCallback;
676 wim->dwFlags = dwFlags;
677 wim->dwClientInstance = lpDesc->dwInstance;
678 wim->u.in.hOuterWave = (HWAVEIN)lpDesc->hWave;
680 ndhi = waveInGetNumDevs();
681 if (dwFlags & WAVE_MAPPED) {
682 if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM;
683 ndlo = lpDesc->uMappedDeviceID;
684 ndhi = ndlo + 1;
685 dwFlags &= ~WAVE_MAPPED;
686 } else {
687 ndlo = 0;
690 wim->avgSpeedOuter = wim->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;
692 for (i = ndlo; i < ndhi; i++) {
693 if (waveInOpen(&wim->u.in.hInnerWave, i, lpDesc->lpFormat, (DWORD)widCallback,
694 (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) {
695 wim->hAcmStream = 0;
696 goto found;
700 if ((dwFlags & WAVE_FORMAT_DIRECT) == 0)
702 WAVEFORMATEX wfx;
704 wfx.wFormatTag = WAVE_FORMAT_PCM;
705 wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
706 /* try some ACM stuff */
708 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
709 switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
710 case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; goto found; \
711 case WAVERR_BADFORMAT: break; \
712 default: goto error; \
715 for (i = ndlo; i < ndhi; i++) {
716 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
717 /* first try with same stereo/mono option as source */
718 wfx.nChannels = lpDesc->lpFormat->nChannels;
719 TRY(wfx.nSamplesPerSec, 16);
720 TRY(wfx.nSamplesPerSec, 8);
721 wfx.nChannels ^= 3;
722 TRY(wfx.nSamplesPerSec, 16);
723 TRY(wfx.nSamplesPerSec, 8);
726 for (i = ndlo; i < ndhi; i++) {
727 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
728 /* first try with same stereo/mono option as source */
729 wfx.nChannels = lpDesc->lpFormat->nChannels;
730 TRY(96000, 16);
731 TRY(48000, 16);
732 TRY(44100, 16);
733 TRY(22050, 16);
734 TRY(11025, 16);
736 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
737 wfx.nChannels ^= 3;
738 TRY(96000, 16);
739 TRY(48000, 16);
740 TRY(44100, 16);
741 TRY(22050, 16);
742 TRY(11025, 16);
744 /* first try with same stereo/mono option as source */
745 wfx.nChannels = lpDesc->lpFormat->nChannels;
746 TRY(96000, 8);
747 TRY(48000, 8);
748 TRY(44100, 8);
749 TRY(22050, 8);
750 TRY(11025, 8);
752 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
753 wfx.nChannels ^= 3;
754 TRY(96000, 8);
755 TRY(48000, 8);
756 TRY(44100, 8);
757 TRY(22050, 8);
758 TRY(11025, 8);
760 #undef TRY
763 HeapFree(GetProcessHeap(), 0, wim);
764 WARN("ret = WAVERR_BADFORMAT\n");
765 return WAVERR_BADFORMAT;
766 found:
767 if (dwFlags & WAVE_FORMAT_QUERY) {
768 *lpdwUser = 0L;
769 HeapFree(GetProcessHeap(), 0, wim);
770 } else {
771 *lpdwUser = (DWORD)wim;
773 TRACE("Ok (stream=%08lx)\n", (DWORD)wim->hAcmStream);
774 return MMSYSERR_NOERROR;
775 error:
776 HeapFree(GetProcessHeap(), 0, wim);
777 if (res==ACMERR_NOTPOSSIBLE) {
778 WARN("ret = WAVERR_BADFORMAT\n");
779 return WAVERR_BADFORMAT;
781 WARN("ret = MMSYSERR_ERROR\n");
782 return MMSYSERR_ERROR;
785 static DWORD widClose(WAVEMAPDATA* wim)
787 DWORD ret;
789 TRACE("(%p)\n", wim);
791 ret = waveInClose(wim->u.in.hInnerWave);
792 if (ret == MMSYSERR_NOERROR) {
793 if (wim->hAcmStream) {
794 ret = acmStreamClose(wim->hAcmStream, 0);
796 if (ret == MMSYSERR_NOERROR) {
797 HeapFree(GetProcessHeap(), 0, wim);
800 return ret;
803 static DWORD widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
805 PACMSTREAMHEADER ash;
806 LPWAVEHDR lpWaveHdrSrc;
808 TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2);
810 if (!wim->hAcmStream) {
811 return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
814 lpWaveHdrDst->dwFlags |= WHDR_INQUEUE;
815 ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
817 lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
818 return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
821 static DWORD widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
823 PACMSTREAMHEADER ash;
824 DWORD size;
825 DWORD dwRet;
826 LPWAVEHDR lpWaveHdrSrc;
828 TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2);
830 if (!wim->hAcmStream) {
831 return waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
833 if (acmStreamSize(wim->hAcmStream, lpWaveHdrDst->dwBufferLength, &size,
834 ACM_STREAMSIZEF_DESTINATION) != MMSYSERR_NOERROR) {
835 WARN("acmStreamSize failed\n");
836 return MMSYSERR_ERROR;
839 ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
840 if (ash == NULL) {
841 WARN("no memory\n");
842 return MMSYSERR_NOMEM;
845 ash->cbStruct = sizeof(*ash);
846 ash->fdwStatus = 0L;
847 ash->dwUser = (DWORD)lpWaveHdrDst;
848 ash->pbSrc = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
849 ash->cbSrcLength = size;
850 /* ash->cbSrcLengthUsed */
851 ash->dwSrcUser = 0L; /* FIXME ? */
852 ash->pbDst = lpWaveHdrDst->lpData;
853 ash->cbDstLength = lpWaveHdrDst->dwBufferLength;
854 /* ash->cbDstLengthUsed */
855 ash->dwDstUser = lpWaveHdrDst->dwUser; /* FIXME ? */
856 dwRet = acmStreamPrepareHeader(wim->hAcmStream, ash, 0L);
857 if (dwRet != MMSYSERR_NOERROR) {
858 WARN("acmStreamPrepareHeader failed\n");
859 goto errCleanUp;
862 lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
863 lpWaveHdrSrc->lpData = ash->pbSrc;
864 lpWaveHdrSrc->dwBufferLength = size; /* conversion is not done yet */
865 lpWaveHdrSrc->dwFlags = 0;
866 lpWaveHdrSrc->dwLoops = 0;
867 dwRet = waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
868 if (dwRet != MMSYSERR_NOERROR) {
869 WARN("waveInPrepareHeader failed\n");
870 goto errCleanUp;
873 lpWaveHdrDst->reserved = (DWORD)ash;
874 lpWaveHdrDst->dwFlags = WHDR_PREPARED;
875 TRACE("=> (0)\n");
876 return MMSYSERR_NOERROR;
877 errCleanUp:
878 TRACE("=> (%ld)\n", dwRet);
879 HeapFree(GetProcessHeap(), 0, ash);
880 return dwRet;
883 static DWORD widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
885 PACMSTREAMHEADER ash;
886 LPWAVEHDR lpWaveHdrSrc;
887 DWORD dwRet1, dwRet2;
889 TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2);
891 if (!wim->hAcmStream) {
892 return waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
894 ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
895 dwRet1 = acmStreamUnprepareHeader(wim->hAcmStream, ash, 0L);
897 lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
898 dwRet2 = waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
900 HeapFree(GetProcessHeap(), 0, ash);
902 lpWaveHdrDst->dwFlags &= ~WHDR_PREPARED;
903 return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
906 static DWORD widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2)
908 DWORD val;
910 TRACE("(%p %p %08lx)\n", wim, lpTime, dwParam2);
912 val = waveInGetPosition(wim->u.in.hInnerWave, lpTime, dwParam2);
913 if (lpTime->wType == TIME_BYTES)
914 lpTime->u.cb = MulDiv(lpTime->u.cb, wim->avgSpeedOuter, wim->avgSpeedInner);
915 /* other time types don't require conversion */
916 return val;
919 static DWORD widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSA lpWaveCaps, DWORD dwParam2)
921 TRACE("(%04x, %p %p %08lx)\n", wDevID, wim, lpWaveCaps, dwParam2);
923 /* if opened low driver, forward message */
924 if (WAVEMAP_IsData(wim))
925 return waveInGetDevCapsA((UINT)wim->u.in.hInnerWave, lpWaveCaps, dwParam2);
926 /* else if no drivers, nothing to map so return bad device */
927 if (waveInGetNumDevs() == 0) {
928 WARN("bad device id\n");
929 return MMSYSERR_BADDEVICEID;
931 /* otherwise, return caps of mapper itself */
932 if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
933 WAVEINCAPSA wic;
934 wic.wMid = 0x00FF;
935 wic.wPid = 0x0001;
936 wic.vDriverVersion = 0x0001;
937 strcpy(wic.szPname, "Wine wave in mapper");
938 wic.dwFormats =
939 WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 |
940 WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 |
941 WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
942 WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
943 WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
944 wic.wChannels = 2;
945 memcpy(lpWaveCaps, &wic, min(dwParam2, sizeof(wic)));
947 return MMSYSERR_NOERROR;
949 ERR("This shouldn't happen\n");
950 return MMSYSERR_ERROR;
953 static DWORD widStop(WAVEMAPDATA* wim)
955 TRACE("(%p)\n", wim);
957 return waveInStop(wim->u.in.hInnerWave);
960 static DWORD widStart(WAVEMAPDATA* wim)
962 TRACE("(%p)\n", wim);
964 return waveInStart(wim->u.in.hInnerWave);
967 static DWORD widReset(WAVEMAPDATA* wim)
969 TRACE("(%p)\n", wim);
971 return waveInReset(wim->u.in.hInnerWave);
974 static DWORD widMapperStatus(WAVEMAPDATA* wim, DWORD flags, LPVOID ptr)
976 UINT id;
977 DWORD ret = MMSYSERR_NOTSUPPORTED;
979 TRACE("(%p %08lx %p)\n", wim, flags, ptr);
981 switch (flags) {
982 case WAVEIN_MAPPER_STATUS_DEVICE:
983 ret = waveInGetID(wim->u.in.hInnerWave, &id);
984 *(LPDWORD)ptr = id;
985 break;
986 case WAVEIN_MAPPER_STATUS_MAPPED:
987 FIXME("Unsupported yet flag=%ld\n", flags);
988 *(LPDWORD)ptr = 0; /* FIXME ?? */
989 break;
990 case WAVEIN_MAPPER_STATUS_FORMAT:
991 FIXME("Unsupported flag=%ld\n", flags);
992 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
993 *(LPDWORD)ptr = 0; /* FIXME ?? */
994 break;
995 default:
996 FIXME("Unsupported flag=%ld\n", flags);
997 *(LPDWORD)ptr = 0;
998 break;
1000 return ret;
1003 /**************************************************************************
1004 * widMessage (MSACM.@)
1006 DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1007 DWORD dwParam1, DWORD dwParam2)
1009 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1010 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1012 switch (wMsg) {
1013 case DRVM_INIT:
1014 case DRVM_EXIT:
1015 case DRVM_ENABLE:
1016 case DRVM_DISABLE:
1017 /* FIXME: Pretend this is supported */
1018 return 0;
1020 case WIDM_OPEN: return widOpen ((LPDWORD)dwUser, (LPWAVEOPENDESC)dwParam1, dwParam2);
1021 case WIDM_CLOSE: return widClose ((WAVEMAPDATA*)dwUser);
1023 case WIDM_ADDBUFFER: return widAddBuffer ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
1024 case WIDM_PREPARE: return widPrepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
1025 case WIDM_UNPREPARE: return widUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
1026 case WIDM_GETDEVCAPS: return widGetDevCaps (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSA)dwParam1, dwParam2);
1027 case WIDM_GETNUMDEVS: return 1;
1028 case WIDM_GETPOS: return widGetPosition ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, dwParam2);
1029 case WIDM_RESET: return widReset ((WAVEMAPDATA*)dwUser);
1030 case WIDM_START: return widStart ((WAVEMAPDATA*)dwUser);
1031 case WIDM_STOP: return widStop ((WAVEMAPDATA*)dwUser);
1032 case WIDM_MAPPER_STATUS: return widMapperStatus ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
1033 /* known but not supported */
1034 case DRV_QUERYDEVICEINTERFACESIZE:
1035 case DRV_QUERYDEVICEINTERFACE:
1036 return MMSYSERR_NOTSUPPORTED;
1037 default:
1038 FIXME("unknown message %u!\n", wMsg);
1040 return MMSYSERR_NOTSUPPORTED;
1043 /*======================================================================*
1044 * Driver part *
1045 *======================================================================*/
1047 static struct WINE_WAVEMAP* oss = NULL;
1049 /**************************************************************************
1050 * WAVEMAP_drvOpen [internal]
1052 static DWORD WAVEMAP_drvOpen(LPSTR str)
1054 TRACE("(%p)\n", str);
1056 if (oss)
1057 return 0;
1059 /* I know, this is ugly, but who cares... */
1060 oss = (struct WINE_WAVEMAP*)1;
1061 return 1;
1064 /**************************************************************************
1065 * WAVEMAP_drvClose [internal]
1067 static DWORD WAVEMAP_drvClose(DWORD dwDevID)
1069 TRACE("(%08lx)\n", dwDevID);
1071 if (oss) {
1072 oss = NULL;
1073 return 1;
1075 return 0;
1078 /**************************************************************************
1079 * DriverProc (MSACM.@)
1081 LONG CALLBACK WAVEMAP_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
1082 DWORD dwParam1, DWORD dwParam2)
1084 TRACE("(%08lX, %p, %08lX, %08lX, %08lX)\n",
1085 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1087 switch(wMsg) {
1088 case DRV_LOAD: return 1;
1089 case DRV_FREE: return 1;
1090 case DRV_OPEN: return WAVEMAP_drvOpen((LPSTR)dwParam1);
1091 case DRV_CLOSE: return WAVEMAP_drvClose(dwDevID);
1092 case DRV_ENABLE: return 1;
1093 case DRV_DISABLE: return 1;
1094 case DRV_QUERYCONFIGURE: return 1;
1095 case DRV_CONFIGURE: MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK); return 1;
1096 case DRV_INSTALL: return DRVCNF_RESTART;
1097 case DRV_REMOVE: return DRVCNF_RESTART;
1098 default:
1099 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);