xref: /reactos/dll/win32/msacm32.drv/wavemap.c (revision a51fd57d)
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * Wine Wave mapper driver
4  *
5  * Copyright 	1999,2001 Eric Pouech
6  *
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.
11  *
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.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
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...
29  */
30 
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/unicode.h"
41 #include "wine/debug.h"
42 
43 WINE_DEFAULT_DEBUG_CHANNEL(wavemap);
44 
45 typedef	struct tagWAVEMAPDATA {
46     struct tagWAVEMAPDATA*	self;
47     union {
48         struct {
49             HWAVEOUT	hOuterWave;
50             HWAVEOUT	hInnerWave;
51         } out;
52         struct {
53             HWAVEIN	hOuterWave;
54             HWAVEIN	hInnerWave;
55         } in;
56     } u;
57     HACMSTREAM	hAcmStream;
58     /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */
59     DWORD_PTR	dwCallback;
60     DWORD_PTR	dwClientInstance;
61     DWORD	dwFlags;
62     /* ratio to compute position from a PCM playback to any format */
63     DWORD       avgSpeedOuter;
64     DWORD       avgSpeedInner;
65     /* channel size of inner and outer */
66     DWORD       nSamplesPerSecOuter;
67     DWORD       nSamplesPerSecInner;
68 } WAVEMAPDATA;
69 
WAVEMAP_IsData(const WAVEMAPDATA * wm)70 static	BOOL	WAVEMAP_IsData(const WAVEMAPDATA* wm)
71 {
72     return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm);
73 }
74 
75 /*======================================================================*
76  *                  WAVE OUT part                                       *
77  *======================================================================*/
78 
wodCallback(HWAVEOUT hWave,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)79 static void CALLBACK wodCallback(HWAVEOUT hWave, UINT uMsg, DWORD_PTR dwInstance,
80                                  DWORD_PTR dwParam1, DWORD_PTR dwParam2)
81 {
82     WAVEMAPDATA*	wom = (WAVEMAPDATA*)dwInstance;
83 
84     TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
85 
86     if (!WAVEMAP_IsData(wom)) {
87 	ERR("Bad data\n");
88 	return;
89     }
90 
91     if (uMsg != WOM_OPEN && hWave != wom->u.out.hInnerWave)
92 	ERR("Shouldn't happen (%p %p)\n", hWave, wom->u.out.hInnerWave);
93 
94     switch (uMsg) {
95     case WOM_OPEN:
96     case WOM_CLOSE:
97 	/* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
98 	break;
99     case WOM_DONE:
100 	if (wom->hAcmStream) {
101 	    LPWAVEHDR		lpWaveHdrDst = (LPWAVEHDR)dwParam1;
102 	    PACMSTREAMHEADER	ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER));
103 	    LPWAVEHDR		lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser;
104 
105 	    lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE;
106 	    lpWaveHdrSrc->dwFlags |= WHDR_DONE;
107             dwParam1 = (DWORD_PTR)lpWaveHdrSrc;
108 	}
109 	break;
110     default:
111 	ERR("Unknown msg %u\n", uMsg);
112     }
113 
114     DriverCallback(wom->dwCallback, HIWORD(wom->dwFlags), (HDRVR)wom->u.out.hOuterWave,
115 		   uMsg, wom->dwClientInstance, dwParam1, dwParam2);
116 }
117 
118 /******************************************************************
119  *		wodOpenHelper
120  *
121  *
122  */
wodOpenHelper(WAVEMAPDATA * wom,UINT idx,LPWAVEOPENDESC lpDesc,LPWAVEFORMATEX lpwfx,DWORD dwFlags)123 static	DWORD	wodOpenHelper(WAVEMAPDATA* wom, UINT idx,
124 			      LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx,
125 			      DWORD dwFlags)
126 {
127     DWORD	ret;
128 
129     TRACE("(%p %04x %p %p %08x)\n", wom, idx, lpDesc, lpwfx, dwFlags);
130 
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);
136     } else {
137 	ret = acmStreamOpen(&wom->hAcmStream, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, 0L);
138     }
139     if (ret == MMSYSERR_NOERROR) {
140         ret = waveOutOpen(&wom->u.out.hInnerWave, idx, lpwfx,
141                           (DWORD_PTR)wodCallback, (DWORD_PTR)wom,
142                           (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
143 	if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
144 	    acmStreamClose(wom->hAcmStream, 0);
145 	    wom->hAcmStream = 0;
146 	}
147     }
148     TRACE("ret = %08x\n", ret);
149     return ret;
150 }
151 
wodOpen(DWORD_PTR * lpdwUser,LPWAVEOPENDESC lpDesc,DWORD dwFlags)152 static	DWORD	wodOpen(DWORD_PTR *lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
153 {
154     UINT 		ndlo, ndhi;
155     UINT		i;
156     WAVEMAPDATA*	wom = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
157     DWORD               res;
158 
159     TRACE("(%p %p %08x)\n", lpdwUser, lpDesc, dwFlags);
160 
161     if (!wom) {
162         WARN("no memory\n");
163 	return MMSYSERR_NOMEM;
164     }
165 
166     ndhi = waveOutGetNumDevs();
167     if (dwFlags & WAVE_MAPPED) {
168 	if (lpDesc->uMappedDeviceID >= ndhi) {
169             WARN("invalid parameter: dwFlags WAVE_MAPPED\n");
170             HeapFree(GetProcessHeap(), 0, wom);
171             return MMSYSERR_INVALPARAM;
172         }
173 	ndlo = lpDesc->uMappedDeviceID;
174 	ndhi = ndlo + 1;
175 	dwFlags &= ~WAVE_MAPPED;
176     } else {
177 	ndlo = 0;
178     }
179     wom->self = wom;
180     wom->dwCallback = lpDesc->dwCallback;
181     wom->dwFlags = dwFlags;
182     wom->dwClientInstance = lpDesc->dwInstance;
183     wom->u.out.hOuterWave = (HWAVEOUT)lpDesc->hWave;
184     wom->avgSpeedOuter = wom->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;
185     wom->nSamplesPerSecOuter = wom->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec;
186 
187     for (i = ndlo; i < ndhi; i++) {
188 	/* if no ACM stuff is involved, no need to handle callbacks at this
189 	 * level, this will be done transparently
190 	 */
191         if (waveOutOpen(&wom->u.out.hInnerWave, i, lpDesc->lpFormat,
192                         (DWORD_PTR)wodCallback, (DWORD_PTR)wom,
193                         (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) {
194 	    wom->hAcmStream = 0;
195 	    goto found;
196 	}
197     }
198 
199     if ((dwFlags & WAVE_FORMAT_DIRECT) == 0) {
200         WAVEFORMATEX	wfx;
201 
202         wfx.wFormatTag = WAVE_FORMAT_PCM;
203         wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
204         /* try some ACM stuff */
205 
206 #define	TRY(sps,bps)    wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
207                         switch (res=wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
208                             case MMSYSERR_NOERROR: wom->avgSpeedInner = wfx.nAvgBytesPerSec; wom->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \
209                             case WAVERR_BADFORMAT: break; \
210                             default: goto error; \
211                         }
212 
213         if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
214             /* Format changed so keep sample rate and number of channels
215              * the same and just change the bit depth
216              */
217             for (i = ndlo; i < ndhi; i++) {
218                 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
219                 wfx.nChannels = lpDesc->lpFormat->nChannels;
220                 TRY(wfx.nSamplesPerSec, 16);
221                 TRY(wfx.nSamplesPerSec, 8);
222             }
223         } else {
224             /* Our resampling algorithm is quite primitive so first try
225              * to just change the bit depth and number of channels
226              */
227             for (i = ndlo; i < ndhi; i++) {
228                 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
229                 wfx.nChannels = lpDesc->lpFormat->nChannels;
230                 TRY(wfx.nSamplesPerSec, 16);
231                 TRY(wfx.nSamplesPerSec, 8);
232                 wfx.nChannels ^= 3;
233                 TRY(wfx.nSamplesPerSec, 16);
234                 TRY(wfx.nSamplesPerSec, 8);
235             }
236 
237             for (i = ndlo; i < ndhi; i++) {
238                 /* first try with same stereo/mono option as source */
239                 wfx.nChannels = lpDesc->lpFormat->nChannels;
240                 TRY(96000, 16);
241                 TRY(48000, 16);
242                 TRY(44100, 16);
243                 TRY(22050, 16);
244                 TRY(11025, 16);
245 
246                 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
247                 wfx.nChannels ^= 3;
248                 TRY(96000, 16);
249                 TRY(48000, 16);
250                 TRY(44100, 16);
251                 TRY(22050, 16);
252                 TRY(11025, 16);
253 
254                 /* first try with same stereo/mono option as source */
255                 wfx.nChannels = lpDesc->lpFormat->nChannels;
256                 TRY(96000, 8);
257                 TRY(48000, 8);
258                 TRY(44100, 8);
259                 TRY(22050, 8);
260                 TRY(11025, 8);
261 
262                 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
263                 wfx.nChannels ^= 3;
264                 TRY(96000, 8);
265                 TRY(48000, 8);
266                 TRY(44100, 8);
267                 TRY(22050, 8);
268                 TRY(11025, 8);
269             }
270         }
271 #undef TRY
272     }
273 
274     HeapFree(GetProcessHeap(), 0, wom);
275     WARN("ret = WAVERR_BADFORMAT\n");
276     return WAVERR_BADFORMAT;
277 
278 found:
279     if (dwFlags & WAVE_FORMAT_QUERY) {
280 	*lpdwUser = 0L;
281 	HeapFree(GetProcessHeap(), 0, wom);
282     } else {
283         *lpdwUser = (DWORD_PTR)wom;
284     }
285     return MMSYSERR_NOERROR;
286 error:
287     HeapFree(GetProcessHeap(), 0, wom);
288     if (res==ACMERR_NOTPOSSIBLE) {
289         WARN("ret = WAVERR_BADFORMAT\n");
290         return WAVERR_BADFORMAT;
291     }
292     WARN("ret = 0x%08x\n", res);
293     return res;
294 }
295 
wodClose(WAVEMAPDATA * wom)296 static	DWORD	wodClose(WAVEMAPDATA* wom)
297 {
298     DWORD ret;
299 
300     TRACE("(%p)\n", wom);
301 
302     ret = waveOutClose(wom->u.out.hInnerWave);
303     if (ret == MMSYSERR_NOERROR) {
304 	if (wom->hAcmStream) {
305 	    ret = acmStreamClose(wom->hAcmStream, 0);
306 	}
307 	if (ret == MMSYSERR_NOERROR) {
308 	    HeapFree(GetProcessHeap(), 0, wom);
309 	}
310     }
311     return ret;
312 }
313 
wodWrite(WAVEMAPDATA * wom,LPWAVEHDR lpWaveHdrSrc,DWORD dwParam2)314 static	DWORD	wodWrite(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
315 {
316     PACMSTREAMHEADER	ash;
317     LPWAVEHDR		lpWaveHdrDst;
318 
319     TRACE("(%p %p %08x)\n", wom, lpWaveHdrSrc, dwParam2);
320 
321     if (!wom->hAcmStream) {
322 	return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
323     }
324 
325     lpWaveHdrSrc->dwFlags |= WHDR_INQUEUE;
326     ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
327     /* acmStreamConvert will actually check that the new size is less than initial size */
328     ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
329     if (acmStreamConvert(wom->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) {
330         WARN("acmStreamConvert failed\n");
331 	return MMSYSERR_ERROR;
332     }
333 
334     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
335     if (ash->cbSrcLength > ash->cbSrcLengthUsed)
336         FIXME("Not all src buffer has been written, expect bogus sound\n");
337     else if (ash->cbSrcLength < ash->cbSrcLengthUsed)
338         ERR("Codec has read more data than it is allowed to\n");
339 
340     if (ash->cbDstLengthUsed == 0) {
341         /* something went wrong in decoding */
342         FIXME("Got 0 length\n");
343         return MMSYSERR_ERROR;
344     }
345     lpWaveHdrDst->dwBufferLength = ash->cbDstLengthUsed;
346     return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
347 }
348 
wodPrepare(WAVEMAPDATA * wom,LPWAVEHDR lpWaveHdrSrc,DWORD dwParam2)349 static	DWORD	wodPrepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
350 {
351     PACMSTREAMHEADER	ash;
352     DWORD		size;
353     DWORD		dwRet;
354     LPWAVEHDR		lpWaveHdrDst;
355 
356     TRACE("(%p %p %08x)\n", wom, lpWaveHdrSrc, dwParam2);
357 
358     if (!wom->hAcmStream)
359 	return waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
360 
361     if (acmStreamSize(wom->hAcmStream, lpWaveHdrSrc->dwBufferLength, &size, ACM_STREAMSIZEF_SOURCE) != MMSYSERR_NOERROR) {
362         WARN("acmStreamSize failed\n");
363 	return MMSYSERR_ERROR;
364     }
365 
366     ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
367     if (ash == NULL) {
368         WARN("no memory\n");
369 	return MMSYSERR_NOMEM;
370     }
371 
372     ash->cbStruct = sizeof(*ash);
373     ash->fdwStatus = 0L;
374     ash->dwUser = (DWORD_PTR)lpWaveHdrSrc;
375     ash->pbSrc = (LPBYTE)lpWaveHdrSrc->lpData;
376     ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
377     /* ash->cbSrcLengthUsed */
378     ash->dwSrcUser = lpWaveHdrSrc->dwUser; /* FIXME ? */
379     ash->pbDst = (LPBYTE)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
380     ash->cbDstLength = size;
381     /* ash->cbDstLengthUsed */
382     ash->dwDstUser = 0; /* FIXME ? */
383     dwRet = acmStreamPrepareHeader(wom->hAcmStream, ash, 0L);
384     if (dwRet != MMSYSERR_NOERROR) {
385         WARN("acmStreamPrepareHeader failed\n");
386 	goto errCleanUp;
387     }
388 
389     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
390     lpWaveHdrDst->lpData = (LPSTR)ash->pbDst;
391     lpWaveHdrDst->dwBufferLength = size; /* conversion is not done yet */
392     lpWaveHdrDst->dwFlags = 0;
393     lpWaveHdrDst->dwLoops = 0;
394     dwRet = waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
395     if (dwRet != MMSYSERR_NOERROR) {
396         WARN("waveOutPrepareHeader failed\n");
397 	goto errCleanUp;
398     }
399 
400     lpWaveHdrSrc->reserved = (DWORD_PTR)ash;
401     lpWaveHdrSrc->dwFlags = WHDR_PREPARED;
402     TRACE("=> (0)\n");
403     return MMSYSERR_NOERROR;
404 errCleanUp:
405     TRACE("=> (%d)\n", dwRet);
406     HeapFree(GetProcessHeap(), 0, ash);
407     return dwRet;
408 }
409 
wodUnprepare(WAVEMAPDATA * wom,LPWAVEHDR lpWaveHdrSrc,DWORD dwParam2)410 static	DWORD	wodUnprepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
411 {
412     PACMSTREAMHEADER	ash;
413     LPWAVEHDR		lpWaveHdrDst;
414     DWORD		dwRet1, dwRet2;
415 
416     TRACE("(%p %p %08x)\n", wom, lpWaveHdrSrc, dwParam2);
417 
418     if (!wom->hAcmStream) {
419 	return waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
420     }
421     ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
422     dwRet1 = acmStreamUnprepareHeader(wom->hAcmStream, ash, 0L);
423 
424     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
425     dwRet2 = waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
426 
427     HeapFree(GetProcessHeap(), 0, ash);
428 
429     lpWaveHdrSrc->dwFlags &= ~WHDR_PREPARED;
430     return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
431 }
432 
wodGetPosition(WAVEMAPDATA * wom,LPMMTIME lpTime,DWORD dwParam2)433 static	DWORD	wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2)
434 {
435     DWORD       val;
436     MMTIME      timepos;
437     TRACE("(%p %p %08x)\n", wom, lpTime, dwParam2);
438 
439     timepos = *lpTime;
440 
441     /* For TIME_MS, we're going to recalculate using TIME_BYTES */
442     if (lpTime->wType == TIME_MS)
443         timepos.wType = TIME_BYTES;
444 
445     /* This can change timepos.wType if the requested type is not supported */
446     val = waveOutGetPosition(wom->u.out.hInnerWave, &timepos, dwParam2);
447 
448     if (timepos.wType == TIME_BYTES)
449     {
450         DWORD dwInnerSamplesPerOuter = wom->nSamplesPerSecInner / wom->nSamplesPerSecOuter;
451         if (dwInnerSamplesPerOuter > 0)
452         {
453             DWORD dwInnerBytesPerSample = wom->avgSpeedInner / wom->nSamplesPerSecInner;
454             DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter;
455             DWORD remainder = 0;
456 
457             /* If we are up sampling (going from lower sample rate to higher),
458             **   we need to make a special accommodation for times when we've
459             **   written a partial output sample.  This happens frequently
460             **   to us because we use msacm to do our up sampling, and it
461             **   will up sample on an unaligned basis.
462             ** For example, if you convert a 2 byte wide 8,000 'outer'
463             **   buffer to a 2 byte wide 48,000 inner device, you would
464             **   expect 2 bytes of input to produce 12 bytes of output.
465             **   Instead, msacm will produce 8 bytes of output.
466             **   But reporting our position as 1 byte of output is
467             **   nonsensical; the output buffer position needs to be
468             **   aligned on outer sample size, and aggressively rounded up.
469             */
470             remainder = timepos.u.cb % dwInnerBytesPerOuterSample;
471             if (remainder > 0)
472             {
473                 timepos.u.cb -= remainder;
474                 timepos.u.cb += dwInnerBytesPerOuterSample;
475             }
476         }
477 
478         lpTime->u.cb = MulDiv(timepos.u.cb, wom->avgSpeedOuter, wom->avgSpeedInner);
479 
480         /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
481         if (lpTime->wType == TIME_MS)
482             lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wom->avgSpeedOuter);
483         else
484             lpTime->wType = TIME_BYTES;
485     }
486     else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES)
487         lpTime->u.sample = MulDiv(timepos.u.sample, wom->nSamplesPerSecOuter, wom->nSamplesPerSecInner);
488     else
489         /* other time types don't require conversion */
490         lpTime->u = timepos.u;
491 
492     return val;
493 }
494 
wodGetDevCaps(UINT wDevID,WAVEMAPDATA * wom,LPWAVEOUTCAPSW lpWaveCaps,DWORD dwParam2)495 static	DWORD	wodGetDevCaps(UINT wDevID, WAVEMAPDATA* wom, LPWAVEOUTCAPSW lpWaveCaps, DWORD dwParam2)
496 {
497     static const WCHAR name[] = {'W','i','n','e',' ','w','a','v','e',' ','o','u','t',' ','m','a','p','p','e','r',0};
498 
499     TRACE("(%04x %p %p %08x)\n",wDevID, wom, lpWaveCaps, dwParam2);
500 
501     /* if opened low driver, forward message */
502     if (WAVEMAP_IsData(wom))
503         return waveOutGetDevCapsW((UINT_PTR)wom->u.out.hInnerWave, lpWaveCaps, dwParam2);
504     /* else if no drivers, nothing to map so return bad device */
505     if (waveOutGetNumDevs() == 0) {
506         WARN("bad device id\n");
507         return MMSYSERR_BADDEVICEID;
508     }
509     /* otherwise, return caps of mapper itself */
510     if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
511 	WAVEOUTCAPSW woc;
512 	woc.wMid = 0x00FF;
513 	woc.wPid = 0x0001;
514 	woc.vDriverVersion = 0x0332;
515 	lstrcpyW(woc.szPname, name);
516 	woc.dwFormats =
517             WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 |
518             WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 |
519 	    WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
520 	    WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
521 	    WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
522 	woc.wChannels = 2;
523 	woc.wReserved1 = 0;
524 	woc.dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME;
525         memcpy(lpWaveCaps, &woc, min(dwParam2, sizeof(woc)));
526 
527 	return MMSYSERR_NOERROR;
528     }
529     ERR("This shouldn't happen\n");
530     return MMSYSERR_ERROR;
531 }
532 
wodGetVolume(UINT wDevID,WAVEMAPDATA * wom,LPDWORD lpVol)533 static	DWORD	wodGetVolume(UINT wDevID, WAVEMAPDATA* wom, LPDWORD lpVol)
534 {
535     TRACE("(%04x %p %p)\n",wDevID, wom, lpVol);
536 
537     if (WAVEMAP_IsData(wom))
538 	return waveOutGetVolume(wom->u.out.hInnerWave, lpVol);
539     return MMSYSERR_NOERROR;
540 }
541 
wodSetVolume(UINT wDevID,WAVEMAPDATA * wom,DWORD vol)542 static	DWORD	wodSetVolume(UINT wDevID, WAVEMAPDATA* wom, DWORD vol)
543 {
544     TRACE("(%04x %p %08x)\n",wDevID, wom, vol);
545 
546     if (WAVEMAP_IsData(wom))
547 	return waveOutSetVolume(wom->u.out.hInnerWave, vol);
548     return MMSYSERR_NOERROR;
549 }
550 
wodPause(WAVEMAPDATA * wom)551 static	DWORD	wodPause(WAVEMAPDATA* wom)
552 {
553     TRACE("(%p)\n",wom);
554 
555     return waveOutPause(wom->u.out.hInnerWave);
556 }
557 
wodRestart(WAVEMAPDATA * wom)558 static	DWORD	wodRestart(WAVEMAPDATA* wom)
559 {
560     TRACE("(%p)\n",wom);
561 
562     return waveOutRestart(wom->u.out.hInnerWave);
563 }
564 
wodReset(WAVEMAPDATA * wom)565 static	DWORD	wodReset(WAVEMAPDATA* wom)
566 {
567     TRACE("(%p)\n",wom);
568 
569     return waveOutReset(wom->u.out.hInnerWave);
570 }
571 
wodBreakLoop(WAVEMAPDATA * wom)572 static	DWORD	wodBreakLoop(WAVEMAPDATA* wom)
573 {
574     TRACE("(%p)\n",wom);
575 
576     return waveOutBreakLoop(wom->u.out.hInnerWave);
577 }
578 
wodMapperStatus(WAVEMAPDATA * wom,DWORD flags,LPVOID ptr)579 static  DWORD	wodMapperStatus(WAVEMAPDATA* wom, DWORD flags, LPVOID ptr)
580 {
581     UINT	id;
582     DWORD	ret = MMSYSERR_NOTSUPPORTED;
583 
584     TRACE("(%p %08x %p)\n",wom, flags, ptr);
585 
586     switch (flags) {
587     case WAVEOUT_MAPPER_STATUS_DEVICE:
588 	ret = waveOutGetID(wom->u.out.hInnerWave, &id);
589 	*(LPDWORD)ptr = id;
590 	break;
591     case WAVEOUT_MAPPER_STATUS_MAPPED:
592 	FIXME("Unsupported flag=%d\n", flags);
593 	*(LPDWORD)ptr = 0; /* FIXME ?? */
594 	break;
595     case WAVEOUT_MAPPER_STATUS_FORMAT:
596 	FIXME("Unsupported flag=%d\n", flags);
597 	/* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
598 	*(LPDWORD)ptr = 0;
599 	break;
600     default:
601 	FIXME("Unsupported flag=%d\n", flags);
602 	*(LPDWORD)ptr = 0;
603 	break;
604     }
605     return ret;
606 }
607 
wodMapperReconfigure(WAVEMAPDATA * wom,DWORD dwParam1,DWORD dwParam2)608 static  DWORD   wodMapperReconfigure(WAVEMAPDATA* wom, DWORD dwParam1, DWORD dwParam2)
609 {
610     FIXME("(%p %08x %08x) stub!\n", wom, dwParam1, dwParam2);
611 
612     return MMSYSERR_NOERROR;
613 }
614 
615 /**************************************************************************
616  * 				wodMessage (MSACM.@)
617  */
WAVEMAP_wodMessage(UINT wDevID,UINT wMsg,DWORD_PTR dwUser,DWORD_PTR dwParam1,DWORD_PTR dwParam2)618 DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
619                                 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
620 {
621     TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
622 	  wDevID, wMsg, dwUser, dwParam1, dwParam2);
623 
624     switch (wMsg) {
625     case DRVM_INIT:
626     case DRVM_EXIT:
627     case DRVM_ENABLE:
628     case DRVM_DISABLE:
629 	/* FIXME: Pretend this is supported */
630 	return 0;
631     case WODM_OPEN:	 	return wodOpen		((DWORD_PTR*)dwUser,      (LPWAVEOPENDESC)dwParam1,dwParam2);
632     case WODM_CLOSE:	 	return wodClose		((WAVEMAPDATA*)dwUser);
633     case WODM_WRITE:	 	return wodWrite		((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,	dwParam2);
634     case WODM_PAUSE:	 	return wodPause		((WAVEMAPDATA*)dwUser);
635     case WODM_GETPOS:	 	return wodGetPosition	((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, 	dwParam2);
636     case WODM_BREAKLOOP: 	return wodBreakLoop	((WAVEMAPDATA*)dwUser);
637     case WODM_PREPARE:	 	return wodPrepare	((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
638     case WODM_UNPREPARE: 	return wodUnprepare	((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
639     case WODM_GETDEVCAPS:	return wodGetDevCaps	(wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSW)dwParam1,dwParam2);
640     case WODM_GETNUMDEVS:	return 1;
641     case WODM_GETPITCH:	 	return MMSYSERR_NOTSUPPORTED;
642     case WODM_SETPITCH:	 	return MMSYSERR_NOTSUPPORTED;
643     case WODM_GETPLAYBACKRATE:	return MMSYSERR_NOTSUPPORTED;
644     case WODM_SETPLAYBACKRATE:	return MMSYSERR_NOTSUPPORTED;
645     case WODM_GETVOLUME:	return wodGetVolume	(wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1);
646     case WODM_SETVOLUME:	return wodSetVolume	(wDevID, (WAVEMAPDATA*)dwUser, dwParam1);
647     case WODM_RESTART:		return wodRestart	((WAVEMAPDATA*)dwUser);
648     case WODM_RESET:		return wodReset		((WAVEMAPDATA*)dwUser);
649     case WODM_MAPPER_STATUS:	return wodMapperStatus  ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
650     case DRVM_MAPPER_RECONFIGURE: return wodMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2);
651     /* known but not supported */
652     case DRV_QUERYDEVICEINTERFACESIZE:
653     case DRV_QUERYDEVICEINTERFACE:
654         return MMSYSERR_NOTSUPPORTED;
655     default:
656 	FIXME("unknown message %d!\n", wMsg);
657     }
658     return MMSYSERR_NOTSUPPORTED;
659 }
660 
661 /*======================================================================*
662  *                  WAVE IN part                                        *
663  *======================================================================*/
664 
widCallback(HWAVEIN hWave,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)665 static void CALLBACK widCallback(HWAVEIN hWave, UINT uMsg, DWORD_PTR dwInstance,
666                                  DWORD_PTR dwParam1, DWORD_PTR dwParam2)
667 {
668     WAVEMAPDATA* wim = (WAVEMAPDATA*)dwInstance;
669 
670     TRACE("(%p %u %lx %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
671 
672     if (!WAVEMAP_IsData(wim)) {
673 	ERR("Bad data\n");
674 	return;
675     }
676 
677     if (uMsg != WIM_OPEN && hWave != wim->u.in.hInnerWave)
678 	ERR("Shouldn't happen (%p %p)\n", hWave, wim->u.in.hInnerWave);
679 
680     switch (uMsg) {
681     case WIM_OPEN:
682     case WIM_CLOSE:
683 	/* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
684 	break;
685     case WIM_DATA:
686 	if (wim->hAcmStream) {
687 	    LPWAVEHDR		lpWaveHdrSrc = (LPWAVEHDR)dwParam1;
688 	    PACMSTREAMHEADER	ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrSrc - sizeof(ACMSTREAMHEADER));
689 	    LPWAVEHDR		lpWaveHdrDst = (LPWAVEHDR)ash->dwUser;
690 
691 	    /* convert data just gotten from waveIn into requested format */
692 	    if (acmStreamConvert(wim->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) {
693 		ERR("ACM conversion failed\n");
694 		return;
695 	    } else {
696 		TRACE("Converted %d bytes into %d\n", ash->cbSrcLengthUsed, ash->cbDstLengthUsed);
697 	    }
698 	    /* and setup the wavehdr to return accordingly */
699 	    lpWaveHdrDst->dwFlags &= ~WHDR_INQUEUE;
700 	    lpWaveHdrDst->dwFlags |= WHDR_DONE;
701 	    lpWaveHdrDst->dwBytesRecorded = ash->cbDstLengthUsed;
702             dwParam1 = (DWORD_PTR)lpWaveHdrDst;
703 	}
704 	break;
705     default:
706 	ERR("Unknown msg %u\n", uMsg);
707     }
708 
709     DriverCallback(wim->dwCallback, HIWORD(wim->dwFlags), (HDRVR)wim->u.in.hOuterWave,
710 		   uMsg, wim->dwClientInstance, dwParam1, dwParam2);
711 }
712 
widOpenHelper(WAVEMAPDATA * wim,UINT idx,LPWAVEOPENDESC lpDesc,LPWAVEFORMATEX lpwfx,DWORD dwFlags)713 static	DWORD	widOpenHelper(WAVEMAPDATA* wim, UINT idx,
714 			      LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx,
715 			      DWORD dwFlags)
716 {
717     DWORD	ret;
718 
719     TRACE("(%p %04x %p %p %08x)\n", wim, idx, lpDesc, lpwfx, dwFlags);
720 
721     /* source is always PCM, so the formulas below apply */
722     lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
723     lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
724     if (dwFlags & WAVE_FORMAT_QUERY) {
725 	ret = acmStreamOpen(NULL, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);
726     } else {
727 	ret = acmStreamOpen(&wim->hAcmStream, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, 0L);
728     }
729     if (ret == MMSYSERR_NOERROR) {
730         ret = waveInOpen(&wim->u.in.hInnerWave, idx, lpwfx,
731                          (DWORD_PTR)widCallback, (DWORD_PTR)wim,
732                          (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
733 	if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
734 	    acmStreamClose(wim->hAcmStream, 0);
735 	    wim->hAcmStream = 0;
736 	}
737     }
738     TRACE("ret = %08x\n", ret);
739     return ret;
740 }
741 
widOpen(DWORD_PTR * lpdwUser,LPWAVEOPENDESC lpDesc,DWORD dwFlags)742 static	DWORD	widOpen(DWORD_PTR *lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
743 {
744     UINT 		ndlo, ndhi;
745     UINT		i;
746     WAVEMAPDATA*	wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
747     DWORD               res;
748 
749     TRACE("(%p %p %08x)\n", lpdwUser, lpDesc, dwFlags);
750 
751     if (!wim) {
752         WARN("no memory\n");
753 	return MMSYSERR_NOMEM;
754     }
755 
756     wim->self = wim;
757     wim->dwCallback = lpDesc->dwCallback;
758     wim->dwFlags = dwFlags;
759     wim->dwClientInstance = lpDesc->dwInstance;
760     wim->u.in.hOuterWave = (HWAVEIN)lpDesc->hWave;
761 
762     ndhi = waveInGetNumDevs();
763     if (dwFlags & WAVE_MAPPED) {
764 	if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM;
765 	ndlo = lpDesc->uMappedDeviceID;
766 	ndhi = ndlo + 1;
767 	dwFlags &= ~WAVE_MAPPED;
768     } else {
769 	ndlo = 0;
770     }
771 
772     wim->avgSpeedOuter = wim->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;
773     wim->nSamplesPerSecOuter = wim->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec;
774 
775     for (i = ndlo; i < ndhi; i++) {
776         if (waveInOpen(&wim->u.in.hInnerWave, i, lpDesc->lpFormat,
777                        (DWORD_PTR)widCallback, (DWORD_PTR)wim,
778                        (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) {
779 	    wim->hAcmStream = 0;
780 	    goto found;
781 	}
782     }
783 
784     if ((dwFlags & WAVE_FORMAT_DIRECT) == 0)
785     {
786         WAVEFORMATEX	wfx;
787 
788         wfx.wFormatTag = WAVE_FORMAT_PCM;
789         wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
790         /* try some ACM stuff */
791 
792 #define	TRY(sps,bps)    wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
793                         switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
794                         case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; wim->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \
795                         case WAVERR_BADFORMAT: break; \
796                         default: goto error; \
797                         }
798 
799         for (i = ndlo; i < ndhi; i++) {
800 	    wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
801             /* first try with same stereo/mono option as source */
802             wfx.nChannels = lpDesc->lpFormat->nChannels;
803 			TRY(wfx.nSamplesPerSec, 16);
804 			TRY(wfx.nSamplesPerSec, 8);
805 			wfx.nChannels ^= 3;
806 			TRY(wfx.nSamplesPerSec, 16);
807 			TRY(wfx.nSamplesPerSec, 8);
808 	}
809 
810         for (i = ndlo; i < ndhi; i++) {
811 	    wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
812             /* first try with same stereo/mono option as source */
813             wfx.nChannels = lpDesc->lpFormat->nChannels;
814             TRY(96000, 16);
815             TRY(48000, 16);
816             TRY(44100, 16);
817             TRY(22050, 16);
818             TRY(11025, 16);
819 
820             /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
821             wfx.nChannels ^= 3;
822             TRY(96000, 16);
823             TRY(48000, 16);
824             TRY(44100, 16);
825             TRY(22050, 16);
826             TRY(11025, 16);
827 
828             /* first try with same stereo/mono option as source */
829             wfx.nChannels = lpDesc->lpFormat->nChannels;
830             TRY(96000, 8);
831             TRY(48000, 8);
832             TRY(44100, 8);
833             TRY(22050, 8);
834             TRY(11025, 8);
835 
836             /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
837             wfx.nChannels ^= 3;
838             TRY(96000, 8);
839             TRY(48000, 8);
840             TRY(44100, 8);
841             TRY(22050, 8);
842             TRY(11025, 8);
843         }
844 #undef TRY
845     }
846 
847     HeapFree(GetProcessHeap(), 0, wim);
848     WARN("ret = WAVERR_BADFORMAT\n");
849     return WAVERR_BADFORMAT;
850 found:
851     if (dwFlags & WAVE_FORMAT_QUERY) {
852 	*lpdwUser = 0L;
853 	HeapFree(GetProcessHeap(), 0, wim);
854     } else {
855         *lpdwUser = (DWORD_PTR)wim;
856         TRACE("Ok (stream=%p)\n", wim->hAcmStream);
857     }
858     return MMSYSERR_NOERROR;
859 error:
860     HeapFree(GetProcessHeap(), 0, wim);
861     if (res==ACMERR_NOTPOSSIBLE) {
862         WARN("ret = WAVERR_BADFORMAT\n");
863         return WAVERR_BADFORMAT;
864     }
865     WARN("ret = 0x%08x\n", res);
866     return res;
867 }
868 
widClose(WAVEMAPDATA * wim)869 static	DWORD	widClose(WAVEMAPDATA* wim)
870 {
871     DWORD ret;
872 
873     TRACE("(%p)\n", wim);
874 
875     ret = waveInClose(wim->u.in.hInnerWave);
876     if (ret == MMSYSERR_NOERROR) {
877 	if (wim->hAcmStream) {
878 	    ret = acmStreamClose(wim->hAcmStream, 0);
879 	}
880 	if (ret == MMSYSERR_NOERROR) {
881 	    HeapFree(GetProcessHeap(), 0, wim);
882 	}
883     }
884     return ret;
885 }
886 
widAddBuffer(WAVEMAPDATA * wim,LPWAVEHDR lpWaveHdrDst,DWORD dwParam2)887 static	DWORD	widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
888 {
889     PACMSTREAMHEADER	ash;
890     LPWAVEHDR		lpWaveHdrSrc;
891 
892     TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2);
893 
894     if (!wim->hAcmStream) {
895 	return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
896     }
897 
898     lpWaveHdrDst->dwFlags |= WHDR_INQUEUE;
899     ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
900 
901     lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
902     return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
903 }
904 
widPrepare(WAVEMAPDATA * wim,LPWAVEHDR lpWaveHdrDst,DWORD dwParam2)905 static	DWORD	widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
906 {
907     PACMSTREAMHEADER	ash;
908     DWORD		size;
909     DWORD		dwRet;
910     LPWAVEHDR		lpWaveHdrSrc;
911 
912     TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2);
913 
914     if (!wim->hAcmStream) {
915 	return waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
916     }
917     if (acmStreamSize(wim->hAcmStream, lpWaveHdrDst->dwBufferLength, &size,
918 		      ACM_STREAMSIZEF_DESTINATION) != MMSYSERR_NOERROR) {
919         WARN("acmStreamSize failed\n");
920 	return MMSYSERR_ERROR;
921     }
922 
923     ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
924     if (ash == NULL) {
925         WARN("no memory\n");
926 	return MMSYSERR_NOMEM;
927     }
928 
929     ash->cbStruct = sizeof(*ash);
930     ash->fdwStatus = 0L;
931     ash->dwUser = (DWORD_PTR)lpWaveHdrDst;
932     ash->pbSrc = (LPBYTE)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
933     ash->cbSrcLength = size;
934     /* ash->cbSrcLengthUsed */
935     ash->dwSrcUser = 0L; /* FIXME ? */
936     ash->pbDst = (LPBYTE)lpWaveHdrDst->lpData;
937     ash->cbDstLength = lpWaveHdrDst->dwBufferLength;
938     /* ash->cbDstLengthUsed */
939     ash->dwDstUser = lpWaveHdrDst->dwUser; /* FIXME ? */
940     dwRet = acmStreamPrepareHeader(wim->hAcmStream, ash, 0L);
941     if (dwRet != MMSYSERR_NOERROR) {
942         WARN("acmStreamPrepareHeader failed\n");
943 	goto errCleanUp;
944     }
945 
946     lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
947     lpWaveHdrSrc->lpData = (LPSTR)ash->pbSrc;
948     lpWaveHdrSrc->dwBufferLength = size; /* conversion is not done yet */
949     lpWaveHdrSrc->dwFlags = 0;
950     lpWaveHdrSrc->dwLoops = 0;
951     dwRet = waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
952     if (dwRet != MMSYSERR_NOERROR) {
953         WARN("waveInPrepareHeader failed\n");
954 	goto errCleanUp;
955     }
956 
957     lpWaveHdrDst->reserved = (DWORD_PTR)ash;
958     lpWaveHdrDst->dwFlags = WHDR_PREPARED;
959     TRACE("=> (0)\n");
960     return MMSYSERR_NOERROR;
961 errCleanUp:
962     TRACE("=> (%d)\n", dwRet);
963     HeapFree(GetProcessHeap(), 0, ash);
964     return dwRet;
965 }
966 
widUnprepare(WAVEMAPDATA * wim,LPWAVEHDR lpWaveHdrDst,DWORD dwParam2)967 static	DWORD	widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
968 {
969     PACMSTREAMHEADER	ash;
970     LPWAVEHDR		lpWaveHdrSrc;
971     DWORD		dwRet1, dwRet2;
972 
973     TRACE("(%p %p %08x)\n", wim, lpWaveHdrDst, dwParam2);
974 
975     if (!wim->hAcmStream) {
976 	return waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
977     }
978     ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
979     dwRet1 = acmStreamUnprepareHeader(wim->hAcmStream, ash, 0L);
980 
981     lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
982     dwRet2 = waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
983 
984     HeapFree(GetProcessHeap(), 0, ash);
985 
986     lpWaveHdrDst->dwFlags &= ~WHDR_PREPARED;
987     return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
988 }
989 
widGetPosition(WAVEMAPDATA * wim,LPMMTIME lpTime,DWORD dwParam2)990 static	DWORD	widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2)
991 {
992     DWORD       val;
993     MMTIME      timepos;
994     TRACE("(%p %p %08x)\n", wim, lpTime, dwParam2);
995 
996     timepos = *lpTime;
997 
998     /* For TIME_MS, we're going to recalculate using TIME_BYTES */
999     if (lpTime->wType == TIME_MS)
1000         timepos.wType = TIME_BYTES;
1001 
1002     /* This can change timepos.wType if the requested type is not supported */
1003     val = waveInGetPosition(wim->u.in.hInnerWave, &timepos, dwParam2);
1004 
1005     if (timepos.wType == TIME_BYTES)
1006     {
1007         DWORD dwInnerSamplesPerOuter = wim->nSamplesPerSecInner / wim->nSamplesPerSecOuter;
1008         if (dwInnerSamplesPerOuter > 0)
1009         {
1010             DWORD dwInnerBytesPerSample = wim->avgSpeedInner / wim->nSamplesPerSecInner;
1011             DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter;
1012             DWORD remainder = 0;
1013 
1014             /* If we are up sampling (going from lower sample rate to higher),
1015             **   we need to make a special accommodation for times when we've
1016             **   written a partial output sample.  This happens frequently
1017             **   to us because we use msacm to do our up sampling, and it
1018             **   will up sample on an unaligned basis.
1019             ** For example, if you convert a 2 byte wide 8,000 'outer'
1020             **   buffer to a 2 byte wide 48,000 inner device, you would
1021             **   expect 2 bytes of input to produce 12 bytes of output.
1022             **   Instead, msacm will produce 8 bytes of output.
1023             **   But reporting our position as 1 byte of output is
1024             **   nonsensical; the output buffer position needs to be
1025             **   aligned on outer sample size, and aggressively rounded up.
1026             */
1027             remainder = timepos.u.cb % dwInnerBytesPerOuterSample;
1028             if (remainder > 0)
1029             {
1030                 timepos.u.cb -= remainder;
1031                 timepos.u.cb += dwInnerBytesPerOuterSample;
1032             }
1033         }
1034 
1035         lpTime->u.cb = MulDiv(timepos.u.cb, wim->avgSpeedOuter, wim->avgSpeedInner);
1036 
1037         /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
1038         if (lpTime->wType == TIME_MS)
1039             lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wim->avgSpeedOuter);
1040         else
1041             lpTime->wType = TIME_BYTES;
1042     }
1043     else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES)
1044         lpTime->u.sample = MulDiv(timepos.u.sample, wim->nSamplesPerSecOuter, wim->nSamplesPerSecInner);
1045     else
1046         /* other time types don't require conversion */
1047         lpTime->u = timepos.u;
1048 
1049     return val;
1050 }
1051 
widGetDevCaps(UINT wDevID,WAVEMAPDATA * wim,LPWAVEINCAPSW lpWaveCaps,DWORD dwParam2)1052 static	DWORD	widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSW lpWaveCaps, DWORD dwParam2)
1053 {
1054     TRACE("(%04x, %p %p %08x)\n", wDevID, wim, lpWaveCaps, dwParam2);
1055 
1056     /* if opened low driver, forward message */
1057     if (WAVEMAP_IsData(wim))
1058         return waveInGetDevCapsW((UINT_PTR)wim->u.in.hInnerWave, lpWaveCaps, dwParam2);
1059     /* else if no drivers, nothing to map so return bad device */
1060     if (waveInGetNumDevs() == 0) {
1061         WARN("bad device id\n");
1062         return MMSYSERR_BADDEVICEID;
1063     }
1064     /* otherwise, return caps of mapper itself */
1065     if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
1066         WAVEINCAPSW wic;
1067         static const WCHAR init[] = {'W','i','n','e',' ','w','a','v','e',' ','i','n',' ','m','a','p','p','e','r',0};
1068 	wic.wMid = 0x00FF;
1069 	wic.wPid = 0x0001;
1070 	wic.vDriverVersion = 0x0001;
1071 	strcpyW(wic.szPname, init);
1072 	wic.dwFormats =
1073             WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 |
1074             WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 |
1075 	    WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
1076 	    WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
1077 	    WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
1078 	wic.wChannels = 2;
1079 	wic.wReserved1 = 0;
1080         memcpy(lpWaveCaps, &wic, min(dwParam2, sizeof(wic)));
1081 
1082 	return MMSYSERR_NOERROR;
1083     }
1084     ERR("This shouldn't happen\n");
1085     return MMSYSERR_ERROR;
1086 }
1087 
widStop(WAVEMAPDATA * wim)1088 static	DWORD	widStop(WAVEMAPDATA* wim)
1089 {
1090     TRACE("(%p)\n", wim);
1091 
1092     return waveInStop(wim->u.in.hInnerWave);
1093 }
1094 
widStart(WAVEMAPDATA * wim)1095 static	DWORD	widStart(WAVEMAPDATA* wim)
1096 {
1097     TRACE("(%p)\n", wim);
1098 
1099     return waveInStart(wim->u.in.hInnerWave);
1100 }
1101 
widReset(WAVEMAPDATA * wim)1102 static	DWORD	widReset(WAVEMAPDATA* wim)
1103 {
1104     TRACE("(%p)\n", wim);
1105 
1106     return waveInReset(wim->u.in.hInnerWave);
1107 }
1108 
widMapperStatus(WAVEMAPDATA * wim,DWORD flags,LPVOID ptr)1109 static  DWORD	widMapperStatus(WAVEMAPDATA* wim, DWORD flags, LPVOID ptr)
1110 {
1111     UINT	id;
1112     DWORD	ret = MMSYSERR_NOTSUPPORTED;
1113 
1114     TRACE("(%p %08x %p)\n", wim, flags, ptr);
1115 
1116     switch (flags) {
1117     case WAVEIN_MAPPER_STATUS_DEVICE:
1118 	ret = waveInGetID(wim->u.in.hInnerWave, &id);
1119 	*(LPDWORD)ptr = id;
1120 	break;
1121     case WAVEIN_MAPPER_STATUS_MAPPED:
1122 	FIXME("Unsupported yet flag=%d\n", flags);
1123 	*(LPDWORD)ptr = 0; /* FIXME ?? */
1124 	break;
1125     case WAVEIN_MAPPER_STATUS_FORMAT:
1126 	FIXME("Unsupported flag=%d\n", flags);
1127 	/* ptr points to a WAVEFORMATEX struct  - before or after streaming ? */
1128 	*(LPDWORD)ptr = 0; /* FIXME ?? */
1129 	break;
1130     default:
1131 	FIXME("Unsupported flag=%d\n", flags);
1132 	*(LPDWORD)ptr = 0;
1133 	break;
1134     }
1135     return ret;
1136 }
1137 
widMapperReconfigure(WAVEMAPDATA * wim,DWORD dwParam1,DWORD dwParam2)1138 static  DWORD   widMapperReconfigure(WAVEMAPDATA* wim, DWORD dwParam1, DWORD dwParam2)
1139 {
1140     FIXME("(%p %08x %08x) stub!\n", wim, dwParam1, dwParam2);
1141 
1142     return MMSYSERR_NOERROR;
1143 }
1144 
1145 /**************************************************************************
1146  * 				widMessage (MSACM.@)
1147  */
WAVEMAP_widMessage(WORD wDevID,WORD wMsg,DWORD_PTR dwUser,DWORD_PTR dwParam1,DWORD_PTR dwParam2)1148 DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD_PTR dwUser,
1149                                 DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1150 {
1151     TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1152 	  wDevID, wMsg, dwUser, dwParam1, dwParam2);
1153 
1154     switch (wMsg) {
1155     case DRVM_INIT:
1156     case DRVM_EXIT:
1157     case DRVM_ENABLE:
1158     case DRVM_DISABLE:
1159 	/* FIXME: Pretend this is supported */
1160 	return 0;
1161 
1162     case WIDM_OPEN:		return widOpen          ((DWORD_PTR*)dwUser,     (LPWAVEOPENDESC)dwParam1, dwParam2);
1163     case WIDM_CLOSE:		return widClose         ((WAVEMAPDATA*)dwUser);
1164 
1165     case WIDM_ADDBUFFER:	return widAddBuffer     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
1166     case WIDM_PREPARE:		return widPrepare       ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
1167     case WIDM_UNPREPARE:	return widUnprepare     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, 	dwParam2);
1168     case WIDM_GETDEVCAPS:	return widGetDevCaps    (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSW)dwParam1, dwParam2);
1169     case WIDM_GETNUMDEVS:	return 1;
1170     case WIDM_GETPOS:		return widGetPosition   ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, 	dwParam2);
1171     case WIDM_RESET:		return widReset         ((WAVEMAPDATA*)dwUser);
1172     case WIDM_START:		return widStart         ((WAVEMAPDATA*)dwUser);
1173     case WIDM_STOP:		return widStop          ((WAVEMAPDATA*)dwUser);
1174     case WIDM_MAPPER_STATUS:	return widMapperStatus  ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
1175     case DRVM_MAPPER_RECONFIGURE: return widMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2);
1176     /* known but not supported */
1177     case DRV_QUERYDEVICEINTERFACESIZE:
1178     case DRV_QUERYDEVICEINTERFACE:
1179         return MMSYSERR_NOTSUPPORTED;
1180     default:
1181 	FIXME("unknown message %u!\n", wMsg);
1182     }
1183     return MMSYSERR_NOTSUPPORTED;
1184 }
1185 
1186 /*======================================================================*
1187  *                  Driver part                                         *
1188  *======================================================================*/
1189 
1190 static	struct WINE_WAVEMAP* oss = NULL;
1191 
1192 /**************************************************************************
1193  * 				WAVEMAP_drvOpen			[internal]
1194  */
WAVEMAP_drvOpen(LPSTR str)1195 static LRESULT WAVEMAP_drvOpen(LPSTR str)
1196 {
1197     TRACE("(%p)\n", str);
1198 
1199     if (oss)
1200 	return 0;
1201 
1202     /* I know, this is ugly, but who cares... */
1203     oss = (struct WINE_WAVEMAP*)1;
1204     return 1;
1205 }
1206 
1207 /**************************************************************************
1208  * 				WAVEMAP_drvClose		[internal]
1209  */
WAVEMAP_drvClose(DWORD_PTR dwDevID)1210 static LRESULT WAVEMAP_drvClose(DWORD_PTR dwDevID)
1211 {
1212     TRACE("(%08lx)\n", dwDevID);
1213 
1214     if (oss) {
1215 	oss = NULL;
1216 	return 1;
1217     }
1218     return 0;
1219 }
1220 
1221 /**************************************************************************
1222  * 				DriverProc (MSACM.@)
1223  */
WAVEMAP_DriverProc(DWORD_PTR dwDevID,HDRVR hDriv,UINT wMsg,LPARAM dwParam1,LPARAM dwParam2)1224 LRESULT CALLBACK WAVEMAP_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
1225                                     LPARAM dwParam1, LPARAM dwParam2)
1226 {
1227     TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
1228 	  dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1229 
1230     switch(wMsg) {
1231     case DRV_LOAD:		return 1;
1232     case DRV_FREE:		return 1;
1233     case DRV_OPEN:		return WAVEMAP_drvOpen((LPSTR)dwParam1);
1234     case DRV_CLOSE:		return WAVEMAP_drvClose(dwDevID);
1235     case DRV_ENABLE:		return 1;
1236     case DRV_DISABLE:		return 1;
1237     case DRV_QUERYCONFIGURE:	return 1;
1238     case DRV_CONFIGURE:		MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK);	return 1;
1239     case DRV_INSTALL:		return DRVCNF_RESTART;
1240     case DRV_REMOVE:		return DRVCNF_RESTART;
1241     default:
1242 	return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1243     }
1244 }
1245