xref: /reactos/dll/win32/msacm32/pcmconverter.c (revision 8a978a17)
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 
3 /*
4  *      MSACM32 library
5  *
6  *      Copyright 2000		Eric Pouech
7  *      Copyright 2004		Robert Reif
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  *
23  *	FIXME / TODO list
24  *	+ get rid of hack for PCM_DriverProc (msacm32.dll shouldn't export
25  *	  a DriverProc, but this would require implementing a generic
26  *	  embedded driver handling scheme in msacm32.dll which isn't done yet
27  */
28 
29 
30 #include <assert.h>
31 #include <stdarg.h>
32 #include <string.h>
33 
34 #include "windef.h"
35 #include "winbase.h"
36 #include "mmsystem.h"
37 #define NOBITMAP
38 #include "mmreg.h"
39 #include "msacm.h"
40 #include "wingdi.h"
41 #include "winnls.h"
42 #include "winuser.h"
43 
44 #include "msacmdrv.h"
45 #include "wineacm.h"
46 
47 #include "wine/debug.h"
48 
49 WINE_DEFAULT_DEBUG_CHANNEL(msacm);
50 
51 /***********************************************************************
52  *           PCM_drvOpen
53  */
54 static	DWORD	PCM_drvOpen(LPCSTR str, PACMDRVOPENDESCW adod)
55 {
56     TRACE("(%p, %p)\n", str, adod);
57 
58     return (adod == NULL) ||
59 	(adod->fccType == ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC &&
60 	 adod->fccComp == ACMDRIVERDETAILS_FCCCOMP_UNDEFINED);
61 }
62 
63 /***********************************************************************
64  *           PCM_drvClose
65  */
66 static	DWORD	PCM_drvClose(DWORD dwDevID)
67 {
68     TRACE("(%d)\n", dwDevID);
69 
70     return 1;
71 }
72 
73 #define	NUM_OF(a,b)	((a)/(b))
74 
75 /* flags for fdwDriver */
76 #define PCM_RESAMPLE	1
77 
78 typedef void (*PCM_CONVERT_KEEP_RATE)(const unsigned char*, int, unsigned char*);
79 
80 typedef void (*PCM_CONVERT_CHANGE_RATE)(const DWORD, const unsigned char*, DWORD*, const DWORD, unsigned char*, DWORD*);
81 
82 /* data used while converting */
83 typedef struct tagAcmPcmData {
84     /* conversion routine, depending if rate conversion is required */
85     union {
86         PCM_CONVERT_KEEP_RATE cvtKeepRate;
87         PCM_CONVERT_CHANGE_RATE cvtChangeRate;
88     } cvt;
89 } AcmPcmData;
90 
91 /* table to list all supported formats... those are the basic ones. this
92  * also helps given a unique index to each of the supported formats
93  */
94 static const struct {
95     int		nChannels;
96     int		nBits;
97     int		rate;
98 } PCM_Formats[] = {
99     {1,  8,  8000}, {2,  8,  8000}, {1, 16,  8000}, {2, 16,  8000}, {1, 24,  8000}, {2, 24,  8000},
100     {1,  8, 11025}, {2,  8, 11025}, {1, 16, 11025}, {2, 16, 11025}, {1, 24, 11025}, {2, 24, 11025},
101     {1,  8, 22050}, {2,  8, 22050}, {1, 16, 22050}, {2, 16, 22050}, {1, 24, 22050}, {2, 24, 22050},
102     {1,  8, 44100}, {2,  8, 44100}, {1, 16, 44100}, {2, 16, 44100}, {1, 24, 44100}, {2, 24, 44100},
103     {1,  8, 48000}, {2,  8, 48000}, {1, 16, 48000}, {2, 16, 48000}, {1, 24, 48000}, {2, 24, 48000},
104     {1,  8, 96000}, {2,  8, 96000}, {1, 16, 96000}, {2, 16, 96000}, {1, 24, 96000}, {2, 24, 96000},
105 };
106 
107 /***********************************************************************
108  *           PCM_GetFormatIndex
109  */
110 static DWORD PCM_GetFormatIndex(LPWAVEFORMATEX wfx)
111 {
112     unsigned int i;
113     TRACE("(%p)\n", wfx);
114 
115     for (i = 0; i < ARRAY_SIZE(PCM_Formats); i++) {
116 	if (wfx->nChannels == PCM_Formats[i].nChannels &&
117 	    wfx->nSamplesPerSec == PCM_Formats[i].rate &&
118 	    wfx->wBitsPerSample == PCM_Formats[i].nBits)
119 	    return i;
120     }
121     return 0xFFFFFFFF;
122 }
123 
124 /* PCM Conversions:
125  *
126  * parameters:
127  *	+ 8 bit unsigned vs 16 bit signed
128  *	+ mono vs stereo (1 or 2 channels)
129  *	+ sampling rate (8.0, 11.025, 22.05, 44.1 kHz are defined, but algo
130  *	  shall work in all cases)
131  *
132  * mono => stereo: copy the same sample on Left & Right channels
133  * stereo => mono: use the sum of Left & Right channels
134  */
135 
136 /***********************************************************************
137  *           C816
138  *
139  * Converts a 8 bit sample to a 16 bit one
140  */
141 static inline short C816(unsigned char b)
142 {
143     return (b - 128) << 8;
144 }
145 
146 /***********************************************************************
147  *           C168
148  *
149  * Converts a 16 bit sample to a 8 bit one (data loss !!)
150  */
151 static inline unsigned char C168(short s)
152 {
153     return HIBYTE(s) ^ (unsigned char)0x80;
154 }
155 
156 /***********************************************************************
157  *           C248
158  *
159  * Converts a 24 bit sample to a 8 bit one (data loss !!)
160  */
161 static inline unsigned char C248(int s)
162 {
163     return HIBYTE(HIWORD(s)) ^ (unsigned char)0x80;
164 }
165 
166 /***********************************************************************
167  *           C2416
168  *
169  * Converts a 24 bit sample to a 16 bit one (data loss !!)
170  */
171 static inline short C2416(int s)
172 {
173     return HIWORD(s);
174 }
175 
176 /***********************************************************************
177  *           R16
178  *
179  * Read a 16 bit sample (correctly handles endianness)
180  */
181 static inline short  R16(const unsigned char* src)
182 {
183     return (short)((unsigned short)src[0] | ((unsigned short)src[1] << 8));
184 }
185 
186 /***********************************************************************
187  *           R24
188  *
189  * Read a 24 bit sample (correctly handles endianness)
190  * Note, to support signed arithmetic, the values are shifted high in the int
191  * and low 8 bytes are unused.
192  */
193 static inline int R24(const unsigned char* src)
194 {
195     return ((int)src[0] | (int)src[1] << 8 | (int)src[2] << 16) << 8;
196 }
197 
198 /***********************************************************************
199  *           W16
200  *
201  * Write a 16 bit sample (correctly handles endianness)
202  */
203 static inline void  W16(unsigned char* dst, short s)
204 {
205     dst[0] = LOBYTE(s);
206     dst[1] = HIBYTE(s);
207 }
208 
209 /***********************************************************************
210  *           W24
211  *
212  * Write a 24 bit sample (correctly handles endianness)
213  */
214 static inline void  W24(unsigned char* dst, int s)
215 {
216     dst[0] = HIBYTE(LOWORD(s));
217     dst[1] = LOBYTE(HIWORD(s));
218     dst[2] = HIBYTE(HIWORD(s));
219 }
220 
221 /***********************************************************************
222  *           M24
223  *
224  * Convert the (l,r) 24 bit stereo sample into a 24 bit mono
225  * (takes the sum of the two values)
226  */
227 static inline int M24(int l, int r)
228 {
229     LONGLONG sum = l + r;
230 
231     /* clip sum to saturation */
232     if (sum > 0x7fffff00)
233         sum = 0x7fffff00;
234     else if (sum < -0x7fffff00)
235         sum = -0x7fffff00;
236 
237     return sum;
238 }
239 
240 /***********************************************************************
241  *           M16
242  *
243  * Convert the (l,r) 16 bit stereo sample into a 16 bit mono
244  * (takes the sum of the two values)
245  */
246 static inline short M16(short l, short r)
247 {
248     int	sum = l + r;
249 
250     /* clip sum to saturation */
251     if (sum > 32767)
252         sum = 32767;
253     else if (sum < -32768)
254         sum = -32768;
255 
256     return sum;
257 }
258 
259 /***********************************************************************
260  *           M8
261  *
262  * Convert the (l,r) 8 bit stereo sample into a 8 bit mono
263  * (takes the sum of the two values)
264  */
265 static inline unsigned char M8(unsigned char a, unsigned char b)
266 {
267     int l = a - 128;
268     int r = b - 128;
269     int	sum = (l + r) + 128;
270 
271     /* clip sum to saturation */
272     if (sum > 0xff)
273         sum = 0xff;
274     else if (sum < 0)
275         sum = 0;
276 
277     return sum;
278 }
279 
280 /* the conversion routines without rate conversion are labelled cvt<X><Y><N><M>K
281  * where :
282  * <X> is the (M)ono/(S)tereo configuration of  input channel
283  * <Y> is the (M)ono/(S)tereo configuration of output channel
284  * <N> is the number of bits of  input channel (8 or 16)
285  * <M> is the number of bits of output channel (8 or 16)
286  *
287  * in the parameters, ns is always the number of samples, so the size of input
288  * buffer (resp output buffer) is ns * (<X> == 'Mono' ? 1:2) * (<N> == 8 ? 1:2)
289  */
290 
291 static	void cvtMM88K(const unsigned char* src, int ns, unsigned char* dst)
292 {
293     TRACE("(%p, %d, %p)\n", src, ns, dst);
294     memcpy(dst, src, ns);
295 }
296 
297 static	void cvtSS88K(const unsigned char* src, int ns, unsigned char* dst)
298 {
299     TRACE("(%p, %d, %p)\n", src, ns, dst);
300     memcpy(dst, src, ns * 2);
301 }
302 
303 static	void cvtMM1616K(const unsigned char* src, int ns, unsigned char* dst)
304 {
305     TRACE("(%p, %d, %p)\n", src, ns, dst);
306     memcpy(dst, src, ns * 2);
307 }
308 
309 static	void cvtSS1616K(const unsigned char* src, int ns, unsigned char* dst)
310 {
311     TRACE("(%p, %d, %p)\n", src, ns, dst);
312     memcpy(dst, src, ns * 4);
313 }
314 
315 static	void cvtMS88K(const unsigned char* src, int ns, unsigned char* dst)
316 {
317     TRACE("(%p, %d, %p)\n", src, ns, dst);
318 
319     while (ns--) {
320 	*dst++ = *src;
321 	*dst++ = *src++;
322     }
323 }
324 
325 static	void cvtMS816K(const unsigned char* src, int ns, unsigned char* dst)
326 {
327     short	v;
328     TRACE("(%p, %d, %p)\n", src, ns, dst);
329 
330     while (ns--) {
331 	v = C816(*src++);
332 	W16(dst, v);		dst += 2;
333 	W16(dst, v);		dst += 2;
334     }
335 }
336 
337 static	void cvtMS168K(const unsigned char* src, int ns, unsigned char* dst)
338 {
339     unsigned char v;
340     TRACE("(%p, %d, %p)\n", src, ns, dst);
341 
342     while (ns--) {
343 	v = C168(R16(src));	src += 2;
344 	*dst++ = v;
345 	*dst++ = v;
346     }
347 }
348 
349 static	void cvtMS1616K(const unsigned char* src, int ns, unsigned char* dst)
350 {
351     short	v;
352     TRACE("(%p, %d, %p)\n", src, ns, dst);
353 
354     while (ns--) {
355 	v = R16(src);		src += 2;
356 	W16(dst, v);		dst += 2;
357 	W16(dst, v);		dst += 2;
358     }
359 }
360 
361 static	void cvtSM88K(const unsigned char* src, int ns, unsigned char* dst)
362 {
363     TRACE("(%p, %d, %p)\n", src, ns, dst);
364 
365     while (ns--) {
366 	*dst++ = M8(src[0], src[1]);
367 	src += 2;
368     }
369 }
370 
371 static	void cvtSM816K(const unsigned char* src, int ns, unsigned char* dst)
372 {
373     short	v;
374     TRACE("(%p, %d, %p)\n", src, ns, dst);
375 
376     while (ns--) {
377 	v = M16(C816(src[0]), C816(src[1]));
378 	src += 2;
379 	W16(dst, v);		dst += 2;
380     }
381 }
382 
383 static	void cvtSM168K(const unsigned char* src, int ns, unsigned char* dst)
384 {
385     TRACE("(%p, %d, %p)\n", src, ns, dst);
386 
387     while (ns--) {
388 	*dst++ = C168(M16(R16(src), R16(src + 2)));
389 	src += 4;
390     }
391 }
392 
393 static	void cvtSM1616K(const unsigned char* src, int ns, unsigned char* dst)
394 {
395     TRACE("(%p, %d, %p)\n", src, ns, dst);
396 
397     while (ns--) {
398 	W16(dst, M16(R16(src),R16(src+2)));	dst += 2;
399 	src += 4;
400     }
401 }
402 
403 static	void cvtMM816K(const unsigned char* src, int ns, unsigned char* dst)
404 {
405     TRACE("(%p, %d, %p)\n", src, ns, dst);
406 
407     while (ns--) {
408 	W16(dst, C816(*src++));		dst += 2;
409     }
410 }
411 
412 static	void cvtSS816K(const unsigned char* src, int ns, unsigned char* dst)
413 {
414     TRACE("(%p, %d, %p)\n", src, ns, dst);
415 
416     while (ns--) {
417 	W16(dst, C816(*src++));	dst += 2;
418 	W16(dst, C816(*src++));	dst += 2;
419     }
420 }
421 
422 static	void cvtMM168K(const unsigned char* src, int ns, unsigned char* dst)
423 {
424     TRACE("(%p, %d, %p)\n", src, ns, dst);
425 
426     while (ns--) {
427 	*dst++ = C168(R16(src));	src += 2;
428     }
429 }
430 
431 static	void cvtSS168K(const unsigned char* src, int ns, unsigned char* dst)
432 {
433     TRACE("(%p, %d, %p)\n", src, ns, dst);
434 
435     while (ns--) {
436 	*dst++ = C168(R16(src));	src += 2;
437 	*dst++ = C168(R16(src));	src += 2;
438     }
439 }
440 
441 static	void cvtMS248K(const unsigned char* src, int ns, unsigned char* dst)
442 {
443     unsigned char v;
444     TRACE("(%p, %d, %p)\n", src, ns, dst);
445 
446     while (ns--) {
447 	v = C248(R24(src));	src += 3;
448 	*dst++ = v;
449 	*dst++ = v;
450     }
451 }
452 
453 static	void cvtSM248K(const unsigned char* src, int ns, unsigned char* dst)
454 {
455     TRACE("(%p, %d, %p)\n", src, ns, dst);
456 
457     while (ns--) {
458 	*dst++ = C248(M24(R24(src), R24(src + 3)));
459 	src += 6;
460     }
461 }
462 
463 static	void cvtMM248K(const unsigned char* src, int ns, unsigned char* dst)
464 {
465     TRACE("(%p, %d, %p)\n", src, ns, dst);
466 
467     while (ns--) {
468 	*dst++ = C248(R24(src));	src += 3;
469     }
470 }
471 
472 static	void cvtSS248K(const unsigned char* src, int ns, unsigned char* dst)
473 {
474     TRACE("(%p, %d, %p)\n", src, ns, dst);
475 
476     while (ns--) {
477 	*dst++ = C248(R24(src));	src += 3;
478 	*dst++ = C248(R24(src));	src += 3;
479     }
480 }
481 
482 static	void cvtMS2416K(const unsigned char* src, int ns, unsigned char* dst)
483 {
484     short v;
485     TRACE("(%p, %d, %p)\n", src, ns, dst);
486 
487     while (ns--) {
488 	v = C2416(R24(src));	src += 3;
489 	W16(dst, v);	dst += 2;
490 	W16(dst, v);	dst += 2;
491     }
492 }
493 
494 static	void cvtSM2416K(const unsigned char* src, int ns, unsigned char* dst)
495 {
496     TRACE("(%p, %d, %p)\n", src, ns, dst);
497 
498     while (ns--) {
499 	W16(dst, C2416(M24(R24(src), R24(src + 3))));
500 	dst += 2;
501 	src += 6;
502     }
503 }
504 
505 static	void cvtMM2416K(const unsigned char* src, int ns, unsigned char* dst)
506 {
507     TRACE("(%p, %d, %p)\n", src, ns, dst);
508 
509     while (ns--) {
510 	W16(dst, C2416(R24(src)));	dst += 2; src += 3;
511     }
512 }
513 
514 static	void cvtSS2416K(const unsigned char* src, int ns, unsigned char* dst)
515 {
516     TRACE("(%p, %d, %p)\n", src, ns, dst);
517 
518     while (ns--) {
519 	W16(dst, C2416(R24(src)));	dst += 2; src += 3;
520 	W16(dst, C2416(R24(src)));	dst += 2; src += 3;
521     }
522 }
523 
524 
525 static const PCM_CONVERT_KEEP_RATE PCM_ConvertKeepRate[] = {
526     cvtSS88K,	cvtSM88K,   cvtMS88K,   cvtMM88K,
527     cvtSS816K,	cvtSM816K,  cvtMS816K,  cvtMM816K,
528     NULL, NULL, NULL, NULL, /* TODO: 8->24 */
529     cvtSS168K,	cvtSM168K,  cvtMS168K,  cvtMM168K,
530     cvtSS1616K, cvtSM1616K, cvtMS1616K, cvtMM1616K,
531     NULL, NULL, NULL, NULL, /* TODO: 16->24 */
532     cvtSS248K, cvtSM248K, cvtMS248K, cvtMM248K,
533     cvtSS2416K, cvtSM2416K, cvtMS2416K, cvtMM2416K,
534     NULL, NULL, NULL, NULL, /* TODO: 24->24 */
535 };
536 
537 /* the conversion routines with rate conversion are labelled cvt<X><Y><N><M>C
538  * where :
539  * <X> is the (M)ono/(S)tereo configuration of  input channel
540  * <Y> is the (M)ono/(S)tereo configuration of output channel
541  * <N> is the number of bits of  input channel (8 or 16)
542  * <M> is the number of bits of output channel (8 or 16)
543  *
544  */
545 
546 static void cvtSS88C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
547                      const DWORD dstRate, unsigned char *dst, DWORD *ndst)
548 {
549     DWORD error = srcRate / 2;
550     DWORD maxSrc = *nsrc, maxDst = *ndst;
551     *ndst = 0;
552     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
553         error += dstRate;
554         while (error > srcRate) {
555             if (*ndst == maxDst)
556                 return;
557             (*ndst)++;
558             error -= srcRate;
559 
560             *dst++ = src[0];
561             *dst++ = src[1];
562         }
563         src += 2;
564     }
565 }
566 
567 static void cvtSM88C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
568                      const DWORD dstRate, unsigned char *dst, DWORD *ndst)
569 {
570     DWORD error = srcRate / 2;
571     DWORD maxSrc = *nsrc, maxDst = *ndst;
572     *ndst = 0;
573     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
574         error += dstRate;
575         while (error > srcRate) {
576             if (*ndst == maxDst)
577                 return;
578             (*ndst)++;
579             error -= srcRate;
580 
581             *dst++ = M8(src[0], src[1]);
582         }
583         src += 2;
584     }
585 }
586 
587 static void cvtMS88C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
588                      const DWORD dstRate, unsigned char *dst, DWORD *ndst)
589 {
590     DWORD error = srcRate / 2;
591     DWORD maxSrc = *nsrc, maxDst = *ndst;
592     *ndst = 0;
593     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
594         error += dstRate;
595         while (error > srcRate) {
596             if (*ndst == maxDst)
597                 return;
598             (*ndst)++;
599             error -= srcRate;
600 
601             *dst++ = src[0];
602             *dst++ = src[0];
603         }
604         src += 1;
605     }
606 }
607 
608 static void cvtMM88C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
609                      const DWORD dstRate, unsigned char *dst, DWORD *ndst)
610 {
611     DWORD error = srcRate / 2;
612     DWORD maxSrc = *nsrc, maxDst = *ndst;
613     *ndst = 0;
614     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
615         error += dstRate;
616         while (error > srcRate) {
617             if (*ndst == maxDst)
618                 return;
619             (*ndst)++;
620             error -= srcRate;
621 
622             *dst++ = src[0];
623         }
624         src += 1;
625     }
626 }
627 
628 static void cvtSS816C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
629                       const DWORD dstRate, unsigned char *dst, DWORD *ndst)
630 {
631     DWORD error = srcRate / 2;
632     DWORD maxSrc = *nsrc, maxDst = *ndst;
633     *ndst = 0;
634     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
635         error += dstRate;
636         while (error > srcRate) {
637             if (*ndst == maxDst)
638                 return;
639             (*ndst)++;
640             error -= srcRate;
641 
642             W16(dst, C816(src[0])); dst += 2;
643             W16(dst, C816(src[1])); dst += 2;
644         }
645         src += 2;
646     }
647 }
648 
649 static void cvtSM816C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
650                       const DWORD dstRate, unsigned char *dst, DWORD *ndst)
651 {
652     DWORD error = srcRate / 2;
653     DWORD maxSrc = *nsrc, maxDst = *ndst;
654     *ndst = 0;
655     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
656         error += dstRate;
657         while (error > srcRate) {
658             if (*ndst == maxDst)
659                 return;
660             (*ndst)++;
661             error -= srcRate;
662 
663             W16(dst, M16(C816(src[0]), C816(src[1]))); dst += 2;
664         }
665         src += 2;
666     }
667 }
668 
669 static void cvtMS816C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
670                       const DWORD dstRate, unsigned char *dst, DWORD *ndst)
671 {
672     DWORD error = srcRate / 2;
673     DWORD maxSrc = *nsrc, maxDst = *ndst;
674     *ndst = 0;
675     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
676         error += dstRate;
677         while (error > srcRate) {
678             if (*ndst == maxDst)
679                 return;
680             (*ndst)++;
681             error -= srcRate;
682 
683             W16(dst, C816(src[0])); dst += 2;
684             W16(dst, C816(src[0])); dst += 2;
685         }
686         src += 1;
687     }
688 }
689 
690 static void cvtMM816C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
691                       const DWORD dstRate, unsigned char *dst, DWORD *ndst)
692 {
693     DWORD error = srcRate / 2;
694     DWORD maxSrc = *nsrc, maxDst = *ndst;
695     *ndst = 0;
696     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
697         error += dstRate;
698         while (error > srcRate) {
699             if (*ndst == maxDst)
700                 return;
701             (*ndst)++;
702             error -= srcRate;
703 
704             W16(dst, C816(src[0])); dst += 2;
705         }
706         src += 1;
707     }
708 }
709 
710 static void cvtSS168C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
711                       const DWORD dstRate, unsigned char *dst, DWORD *ndst)
712 {
713     DWORD error = srcRate / 2;
714     DWORD maxSrc = *nsrc, maxDst = *ndst;
715     *ndst = 0;
716     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
717         error += dstRate;
718         while (error > srcRate) {
719             if (*ndst == maxDst)
720                 return;
721             (*ndst)++;
722             error -= srcRate;
723 
724             *dst++ = C168(R16(src));
725             *dst++ = C168(R16(src + 2));
726         }
727         src += 4;
728     }
729 }
730 
731 static void cvtSM168C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
732                       const DWORD dstRate, unsigned char *dst, DWORD *ndst)
733 {
734     DWORD error = srcRate / 2;
735     DWORD maxSrc = *nsrc, maxDst = *ndst;
736     *ndst = 0;
737     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
738         error += dstRate;
739         while (error > srcRate) {
740             if (*ndst == maxDst)
741                 return;
742             (*ndst)++;
743             error -= srcRate;
744 
745             *dst++ = C168(M16(R16(src), R16(src + 2)));
746         }
747         src += 4;
748     }
749 }
750 
751 static void cvtMS168C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
752                       const DWORD dstRate, unsigned char *dst, DWORD *ndst)
753 {
754     DWORD error = srcRate / 2;
755     DWORD maxSrc = *nsrc, maxDst = *ndst;
756     *ndst = 0;
757     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
758         error += dstRate;
759         while (error > srcRate) {
760             if (*ndst == maxDst)
761                 return;
762             (*ndst)++;
763             error -= srcRate;
764 
765             *dst++ = C168(R16(src));
766             *dst++ = C168(R16(src));
767         }
768         src += 2;
769     }
770 }
771 
772 static void cvtMM168C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
773                       const DWORD dstRate, unsigned char *dst, DWORD *ndst)
774 {
775     DWORD error = srcRate / 2;
776     DWORD maxSrc = *nsrc, maxDst = *ndst;
777     *ndst = 0;
778     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
779         error += dstRate;
780         while (error > srcRate) {
781             if (*ndst == maxDst)
782                 return;
783             (*ndst)++;
784             error -= srcRate;
785 
786             *dst++ = C168(R16(src));
787         }
788         src += 2;
789     }
790 }
791 
792 static void cvtSS1616C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
793                        const DWORD dstRate, unsigned char *dst, DWORD *ndst)
794 {
795     DWORD error = srcRate / 2;
796     DWORD maxSrc = *nsrc, maxDst = *ndst;
797     *ndst = 0;
798     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
799         error += dstRate;
800         while (error > srcRate) {
801             if (*ndst == maxDst)
802                 return;
803             (*ndst)++;
804             error -= srcRate;
805 
806             W16(dst, R16(src)); dst += 2;
807             W16(dst, R16(src + 2)); dst += 2;
808         }
809         src += 4;
810     }
811 }
812 
813 static void cvtSM1616C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
814                        const DWORD dstRate, unsigned char *dst, DWORD *ndst)
815 {
816     DWORD error = srcRate / 2;
817     DWORD maxSrc = *nsrc, maxDst = *ndst;
818     *ndst = 0;
819     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
820         error += dstRate;
821         while (error > srcRate) {
822             if (*ndst == maxDst)
823                 return;
824             (*ndst)++;
825             error -= srcRate;
826 
827             W16(dst, M16(R16(src), R16(src + 2))); dst += 2;
828         }
829         src += 4;
830     }
831 }
832 
833 static void cvtMS1616C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
834                        const DWORD dstRate, unsigned char *dst, DWORD *ndst)
835 {
836     DWORD error = srcRate / 2;
837     DWORD maxSrc = *nsrc, maxDst = *ndst;
838     *ndst = 0;
839     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
840         error += dstRate;
841         while (error > srcRate) {
842             if (*ndst == maxDst)
843                 return;
844             (*ndst)++;
845             error -= srcRate;
846 
847             W16(dst, R16(src)); dst += 2;
848             W16(dst, R16(src)); dst += 2;
849         }
850         src += 2;
851     }
852 }
853 
854 static void cvtMM1616C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
855                        const DWORD dstRate, unsigned char *dst, DWORD *ndst)
856 {
857     DWORD error = srcRate / 2;
858     DWORD maxSrc = *nsrc, maxDst = *ndst;
859     *ndst = 0;
860     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
861         error += dstRate;
862         while (error > srcRate) {
863             if (*ndst == maxDst)
864                 return;
865             (*ndst)++;
866             error -= srcRate;
867 
868             W16(dst, R16(src)); dst += 2;
869         }
870         src += 2;
871     }
872 }
873 
874 static void cvtSS2424C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
875                        const DWORD dstRate, unsigned char *dst, DWORD *ndst)
876 {
877     DWORD error = srcRate / 2;
878     DWORD maxSrc = *nsrc, maxDst = *ndst;
879     *ndst = 0;
880     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
881         error += dstRate;
882         while (error > srcRate) {
883             if (*ndst == maxDst)
884                 return;
885             (*ndst)++;
886             error -= srcRate;
887 
888             W24(dst, R24(src)); dst += 3;
889             W24(dst, R24(src + 3)); dst += 3;
890         }
891         src += 6;
892     }
893 }
894 
895 static void cvtSM2424C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
896                        const DWORD dstRate, unsigned char *dst, DWORD *ndst)
897 {
898     DWORD error = srcRate / 2;
899     DWORD maxSrc = *nsrc, maxDst = *ndst;
900     *ndst = 0;
901     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
902         error += dstRate;
903         while (error > srcRate) {
904             if (*ndst == maxDst)
905                 return;
906             (*ndst)++;
907             error -= srcRate;
908 
909             W24(dst, M24(R24(src), R24(src + 3))); dst += 3;
910         }
911         src += 6;
912     }
913 }
914 
915 static void cvtMS2424C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
916                        const DWORD dstRate, unsigned char *dst, DWORD *ndst)
917 {
918     DWORD error = srcRate / 2;
919     DWORD maxSrc = *nsrc, maxDst = *ndst;
920     *ndst = 0;
921     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
922         error += dstRate;
923         while (error > srcRate) {
924             if (*ndst == maxDst)
925                 return;
926             (*ndst)++;
927             error -= srcRate;
928 
929             W24(dst, R24(src)); dst += 3;
930             W24(dst, R24(src)); dst += 3;
931         }
932         src += 3;
933     }
934 }
935 
936 static void cvtMM2424C(const DWORD srcRate, const unsigned char *src, DWORD *nsrc,
937                        const DWORD dstRate, unsigned char *dst, DWORD *ndst)
938 {
939     DWORD error = srcRate / 2;
940     DWORD maxSrc = *nsrc, maxDst = *ndst;
941     *ndst = 0;
942     for (*nsrc = 0; *nsrc < maxSrc; (*nsrc)++) {
943         error += dstRate;
944         while (error > srcRate) {
945             if (*ndst == maxDst)
946                 return;
947             (*ndst)++;
948             error -= srcRate;
949 
950             W24(dst, R24(src)); dst += 3;
951         }
952         src += 3;
953     }
954 }
955 
956 static const PCM_CONVERT_CHANGE_RATE PCM_ConvertChangeRate[] = {
957     cvtSS88C,   cvtSM88C,   cvtMS88C,   cvtMM88C,
958     cvtSS816C,	cvtSM816C,  cvtMS816C,  cvtMM816C,
959     NULL, NULL, NULL, NULL, /* TODO: 8->24 */
960     cvtSS168C,	cvtSM168C,  cvtMS168C,  cvtMM168C,
961     cvtSS1616C, cvtSM1616C, cvtMS1616C, cvtMM1616C,
962     NULL, NULL, NULL, NULL, /* TODO: 16->24 */
963     NULL, NULL, NULL, NULL, /* TODO: 24->8 */
964     NULL, NULL, NULL, NULL, /* TODO: 24->16 */
965     cvtSS2424C, cvtSM2424C, cvtMS2424C, cvtMM2424C,
966 };
967 
968 /***********************************************************************
969  *           PCM_DriverDetails
970  *
971  */
972 static	LRESULT PCM_DriverDetails(PACMDRIVERDETAILSW add)
973 {
974     TRACE("(%p)\n", add);
975 
976     add->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
977     add->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
978     add->wMid = MM_MICROSOFT;
979     add->wPid = MM_MSFT_ACM_PCM;
980     add->vdwACM = 0x01000000;
981     add->vdwDriver = 0x01000000;
982     add->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER;
983     add->cFormatTags = 1;
984     add->cFilterTags = 0;
985     add->hicon = NULL;
986     MultiByteToWideChar(CP_ACP, 0, "MS-PCM", -1, add->szShortName, ARRAY_SIZE(add->szShortName));
987     MultiByteToWideChar(CP_ACP, 0, "Wine PCM converter", -1,
988                         add->szLongName, ARRAY_SIZE(add->szLongName));
989     MultiByteToWideChar(CP_ACP, 0, "Brought to you by the Wine team...", -1,
990                         add->szCopyright, ARRAY_SIZE(add->szCopyright));
991     MultiByteToWideChar(CP_ACP, 0, "Refer to LICENSE file", -1,
992                         add->szLicensing, ARRAY_SIZE(add->szLicensing) );
993     add->szFeatures[0] = 0;
994 
995     return MMSYSERR_NOERROR;
996 }
997 
998 /***********************************************************************
999  *           PCM_FormatTagDetails
1000  *
1001  */
1002 static	LRESULT	PCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
1003 {
1004     TRACE("(%p, %08x)\n", aftd, dwQuery);
1005 
1006     switch (dwQuery) {
1007     case ACM_FORMATTAGDETAILSF_INDEX:
1008 	if (aftd->dwFormatTagIndex != 0) {
1009             WARN("not possible\n");
1010             return ACMERR_NOTPOSSIBLE;
1011         }
1012 	break;
1013     case ACM_FORMATTAGDETAILSF_FORMATTAG:
1014 	if (aftd->dwFormatTag != WAVE_FORMAT_PCM) {
1015             WARN("not possible\n");
1016             return ACMERR_NOTPOSSIBLE;
1017         }
1018 	break;
1019     case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
1020 	if (aftd->dwFormatTag != WAVE_FORMAT_UNKNOWN &&
1021 	    aftd->dwFormatTag != WAVE_FORMAT_PCM) {
1022             WARN("not possible\n");
1023 	    return ACMERR_NOTPOSSIBLE;
1024         }
1025 	break;
1026     default:
1027 	WARN("Unsupported query %08x\n", dwQuery);
1028 	return MMSYSERR_NOTSUPPORTED;
1029     }
1030 
1031     aftd->dwFormatTagIndex = 0;
1032     aftd->dwFormatTag = WAVE_FORMAT_PCM;
1033     aftd->cbFormatSize = sizeof(PCMWAVEFORMAT);
1034     aftd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER;
1035     aftd->cStandardFormats = ARRAY_SIZE(PCM_Formats);
1036     aftd->szFormatTag[0] = 0;
1037 
1038     return MMSYSERR_NOERROR;
1039 }
1040 
1041 /***********************************************************************
1042  *           PCM_FormatDetails
1043  *
1044  */
1045 static	LRESULT	PCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
1046 {
1047     TRACE("(%p, %08x)\n", afd, dwQuery);
1048 
1049     switch (dwQuery) {
1050     case ACM_FORMATDETAILSF_FORMAT:
1051 	if (PCM_GetFormatIndex(afd->pwfx) == 0xFFFFFFFF) {
1052             WARN("not possible\n");
1053             return ACMERR_NOTPOSSIBLE;
1054         }
1055 	break;
1056     case ACM_FORMATDETAILSF_INDEX:
1057 	assert(afd->dwFormatIndex < ARRAY_SIZE(PCM_Formats));
1058 	afd->pwfx->wFormatTag = WAVE_FORMAT_PCM;
1059 	afd->pwfx->nChannels = PCM_Formats[afd->dwFormatIndex].nChannels;
1060 	afd->pwfx->nSamplesPerSec = PCM_Formats[afd->dwFormatIndex].rate;
1061 	afd->pwfx->wBitsPerSample = PCM_Formats[afd->dwFormatIndex].nBits;
1062 	/* native MSACM uses a PCMWAVEFORMAT structure, so cbSize is not
1063 	 * accessible afd->pwfx->cbSize = 0;
1064 	 */
1065 	afd->pwfx->nBlockAlign =
1066 	    (afd->pwfx->nChannels * afd->pwfx->wBitsPerSample) / 8;
1067 	afd->pwfx->nAvgBytesPerSec =
1068 	    afd->pwfx->nSamplesPerSec * afd->pwfx->nBlockAlign;
1069 	break;
1070     default:
1071 	WARN("Unsupported query %08x\n", dwQuery);
1072 	return MMSYSERR_NOTSUPPORTED;
1073     }
1074 
1075     afd->dwFormatTag = WAVE_FORMAT_PCM;
1076     afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER;
1077     afd->szFormat[0] = 0; /* let MSACM format this for us... */
1078     afd->cbwfx = sizeof(PCMWAVEFORMAT);
1079 
1080     return MMSYSERR_NOERROR;
1081 }
1082 
1083 /***********************************************************************
1084  *           PCM_FormatSuggest
1085  *
1086  */
1087 static	LRESULT	PCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
1088 {
1089     TRACE("(%p)\n", adfs);
1090 
1091     /* some tests ... */
1092     if (adfs->cbwfxSrc < sizeof(PCMWAVEFORMAT) ||
1093         adfs->cbwfxDst < sizeof(PCMWAVEFORMAT) ||
1094         PCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) {
1095             WARN("not possible\n");
1096             return ACMERR_NOTPOSSIBLE;
1097     }
1098 
1099     /* is no suggestion for destination, then copy source value */
1100     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS)) {
1101         adfs->pwfxDst->nChannels = adfs->pwfxSrc->nChannels;
1102     }
1103     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NSAMPLESPERSEC)) {
1104         adfs->pwfxDst->nSamplesPerSec = adfs->pwfxSrc->nSamplesPerSec;
1105     }
1106     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WBITSPERSAMPLE)) {
1107         adfs->pwfxDst->wBitsPerSample = adfs->pwfxSrc->wBitsPerSample;
1108     }
1109     if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_WFORMATTAG)) {
1110         if (adfs->pwfxSrc->wFormatTag != WAVE_FORMAT_PCM) {
1111             WARN("source format 0x%x not supported\n", adfs->pwfxSrc->wFormatTag);
1112             return ACMERR_NOTPOSSIBLE;
1113         }
1114         adfs->pwfxDst->wFormatTag = adfs->pwfxSrc->wFormatTag;
1115     } else {
1116         if (adfs->pwfxDst->wFormatTag != WAVE_FORMAT_PCM) {
1117             WARN("destination format 0x%x not supported\n", adfs->pwfxDst->wFormatTag);
1118             return ACMERR_NOTPOSSIBLE;
1119         }
1120     }
1121     /* check if result is ok */
1122     if (PCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) {
1123         WARN("not possible\n");
1124         return ACMERR_NOTPOSSIBLE;
1125     }
1126 
1127     /* recompute other values */
1128     adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
1129     adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
1130 
1131     return MMSYSERR_NOERROR;
1132 }
1133 
1134 /***********************************************************************
1135  *           PCM_StreamOpen
1136  *
1137  */
1138 static	LRESULT	PCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
1139 {
1140     AcmPcmData* apd;
1141     int idx;
1142     DWORD flags;
1143 
1144     TRACE("(%p)\n", adsi);
1145 
1146     assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
1147 
1148     switch(adsi->pwfxSrc->wBitsPerSample){
1149     case 8:
1150         idx = 0;
1151         break;
1152     case 16:
1153         idx = 12;
1154         break;
1155     case 24:
1156         if (adsi->pwfxSrc->nBlockAlign != 3 * adsi->pwfxSrc->nChannels) {
1157             FIXME("Source: 24-bit samples must be packed\n");
1158             return MMSYSERR_NOTSUPPORTED;
1159         }
1160         idx = 24;
1161         break;
1162     default:
1163         FIXME("Unsupported source bit depth: %u\n", adsi->pwfxSrc->wBitsPerSample);
1164         return MMSYSERR_NOTSUPPORTED;
1165     }
1166 
1167     switch(adsi->pwfxDst->wBitsPerSample){
1168     case 8:
1169         break;
1170     case 16:
1171         idx += 4;
1172         break;
1173     case 24:
1174         if (adsi->pwfxDst->nBlockAlign != 3 * adsi->pwfxDst->nChannels) {
1175             FIXME("Destination: 24-bit samples must be packed\n");
1176             return MMSYSERR_NOTSUPPORTED;
1177         }
1178         idx += 8;
1179         break;
1180     default:
1181         FIXME("Unsupported destination bit depth: %u\n", adsi->pwfxDst->wBitsPerSample);
1182         return MMSYSERR_NOTSUPPORTED;
1183     }
1184 
1185     if (adsi->pwfxSrc->nChannels      == 1)  idx += 2;
1186 
1187     if (adsi->pwfxDst->nChannels      == 1)  idx += 1;
1188 
1189     apd = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmPcmData));
1190     if (!apd)
1191         return MMSYSERR_NOMEM;
1192 
1193     if (adsi->pwfxSrc->nSamplesPerSec == adsi->pwfxDst->nSamplesPerSec) {
1194         flags = 0;
1195         apd->cvt.cvtKeepRate = PCM_ConvertKeepRate[idx];
1196     } else {
1197         flags = PCM_RESAMPLE;
1198         apd->cvt.cvtChangeRate = PCM_ConvertChangeRate[idx];
1199     }
1200 
1201     if(!apd->cvt.cvtChangeRate && !apd->cvt.cvtKeepRate){
1202         FIXME("Unimplemented conversion from %u -> %u bps\n",
1203             adsi->pwfxSrc->wBitsPerSample,
1204             adsi->pwfxDst->wBitsPerSample);
1205         HeapFree(GetProcessHeap(), 0, apd);
1206         return MMSYSERR_NOTSUPPORTED;
1207     }
1208 
1209     adsi->dwDriver = (DWORD_PTR)apd;
1210     adsi->fdwDriver = flags;
1211 
1212     return MMSYSERR_NOERROR;
1213 }
1214 
1215 /***********************************************************************
1216  *           PCM_StreamClose
1217  *
1218  */
1219 static	LRESULT	PCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
1220 {
1221     TRACE("(%p)\n", adsi);
1222 
1223     HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
1224     return MMSYSERR_NOERROR;
1225 }
1226 
1227 /***********************************************************************
1228  *           PCM_round
1229  *
1230  */
1231 static	inline DWORD	PCM_round(DWORD a, DWORD b, DWORD c)
1232 {
1233     assert(c);
1234     /* to be sure, always return an entire number of c... */
1235     return ((double)a * (double)b + (double)c - 1) / (double)c;
1236 }
1237 
1238 /***********************************************************************
1239  *           PCM_StreamSize
1240  *
1241  */
1242 static	LRESULT PCM_StreamSize(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMSIZE adss)
1243 {
1244     DWORD	srcMask = ~(adsi->pwfxSrc->nBlockAlign - 1);
1245     DWORD	dstMask = ~(adsi->pwfxDst->nBlockAlign - 1);
1246 
1247     TRACE("(%p, %p)\n", adsi, adss);
1248 
1249     switch (adss->fdwSize) {
1250     case ACM_STREAMSIZEF_DESTINATION:
1251 	/* cbDstLength => cbSrcLength */
1252 	adss->cbSrcLength = PCM_round(adss->cbDstLength & dstMask,
1253 				      adsi->pwfxSrc->nAvgBytesPerSec,
1254 				      adsi->pwfxDst->nAvgBytesPerSec) & srcMask;
1255 	break;
1256     case ACM_STREAMSIZEF_SOURCE:
1257 	/* cbSrcLength => cbDstLength */
1258 	adss->cbDstLength =  PCM_round(adss->cbSrcLength & srcMask,
1259 				       adsi->pwfxDst->nAvgBytesPerSec,
1260 				       adsi->pwfxSrc->nAvgBytesPerSec) & dstMask;
1261 	break;
1262     default:
1263 	WARN("Unsupported query %08x\n", adss->fdwSize);
1264 	return MMSYSERR_NOTSUPPORTED;
1265     }
1266     return MMSYSERR_NOERROR;
1267 }
1268 
1269 /***********************************************************************
1270  *           PCM_StreamConvert
1271  *
1272  */
1273 static LRESULT PCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
1274 {
1275     AcmPcmData*	apd = (AcmPcmData*)adsi->dwDriver;
1276     DWORD	nsrc = NUM_OF(adsh->cbSrcLength, adsi->pwfxSrc->nBlockAlign);
1277     DWORD	ndst = NUM_OF(adsh->cbDstLength, adsi->pwfxDst->nBlockAlign);
1278 
1279     TRACE("(%p, %p)\n", adsi, adsh);
1280 
1281     TRACE("nsrc=%d,adsh->cbSrcLength=%d\n", nsrc, adsh->cbSrcLength);
1282     TRACE("ndst=%d,adsh->cbDstLength=%d\n", ndst, adsh->cbDstLength);
1283     TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
1284           adsi->pwfxSrc->wFormatTag, adsi->pwfxSrc->nChannels, adsi->pwfxSrc->nSamplesPerSec, adsi->pwfxSrc->nAvgBytesPerSec,
1285           adsi->pwfxSrc->nBlockAlign, adsi->pwfxSrc->wBitsPerSample, adsi->pwfxSrc->cbSize);
1286     TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
1287           adsi->pwfxDst->wFormatTag, adsi->pwfxDst->nChannels, adsi->pwfxDst->nSamplesPerSec, adsi->pwfxDst->nAvgBytesPerSec,
1288           adsi->pwfxDst->nBlockAlign, adsi->pwfxDst->wBitsPerSample, adsi->pwfxDst->cbSize);
1289 
1290     if (adsh->fdwConvert &
1291 	~(ACM_STREAMCONVERTF_BLOCKALIGN|
1292 	  ACM_STREAMCONVERTF_END|
1293 	  ACM_STREAMCONVERTF_START)) {
1294 	FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert);
1295     }
1296     /* ACM_STREAMCONVERTF_BLOCKALIGN
1297      *	currently all conversions are block aligned, so do nothing for this flag
1298      * ACM_STREAMCONVERTF_END
1299      *	no pending data, so do nothing for this flag
1300      */
1301     if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START) &&
1302 	(adsi->fdwDriver & PCM_RESAMPLE)) {
1303     }
1304 
1305     /* do the job */
1306     if (adsi->fdwDriver & PCM_RESAMPLE) {
1307         apd->cvt.cvtChangeRate(adsi->pwfxSrc->nSamplesPerSec, adsh->pbSrc, &nsrc,
1308                                adsi->pwfxDst->nSamplesPerSec, adsh->pbDst, &ndst);
1309     } else {
1310 	if (nsrc < ndst) ndst = nsrc; else nsrc = ndst;
1311 
1312 	/* nsrc is now equal to ndst */
1313 	apd->cvt.cvtKeepRate(adsh->pbSrc, nsrc, adsh->pbDst);
1314     }
1315 
1316     adsh->cbSrcLengthUsed = nsrc * adsi->pwfxSrc->nBlockAlign;
1317     adsh->cbDstLengthUsed = ndst * adsi->pwfxDst->nBlockAlign;
1318 
1319     return MMSYSERR_NOERROR;
1320 }
1321 
1322 /**************************************************************************
1323  * 			DriverProc (MSACM32.@)
1324  */
1325 LRESULT CALLBACK PCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
1326 				       LPARAM dwParam1, LPARAM dwParam2)
1327 {
1328     TRACE("(%08lx %p %u %08lx %08lx);\n",
1329           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1330 
1331     switch (wMsg) {
1332     case DRV_LOAD:		return 1;
1333     case DRV_FREE:		return 1;
1334     case DRV_OPEN:		return PCM_drvOpen((LPSTR)dwParam1, (PACMDRVOPENDESCW)dwParam2);
1335     case DRV_CLOSE:		return PCM_drvClose(dwDevID);
1336     case DRV_ENABLE:		return 1;
1337     case DRV_DISABLE:		return 1;
1338     case DRV_QUERYCONFIGURE:	return 1;
1339     case DRV_CONFIGURE:		MessageBoxA(0, "MSACM PCM filter !", "Wine Driver", MB_OK); return 1;
1340     case DRV_INSTALL:		return DRVCNF_RESTART;
1341     case DRV_REMOVE:		return DRVCNF_RESTART;
1342 
1343     case ACMDM_DRIVER_NOTIFY:
1344 	/* no caching from other ACM drivers is done so far */
1345 	return MMSYSERR_NOERROR;
1346 
1347     case ACMDM_DRIVER_DETAILS:
1348 	return PCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
1349 
1350     case ACMDM_FORMATTAG_DETAILS:
1351 	return PCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
1352 
1353     case ACMDM_FORMAT_DETAILS:
1354 	return PCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
1355 
1356     case ACMDM_FORMAT_SUGGEST:
1357 	return PCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
1358 
1359     case ACMDM_STREAM_OPEN:
1360 	return PCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
1361 
1362     case ACMDM_STREAM_CLOSE:
1363 	return PCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
1364 
1365     case ACMDM_STREAM_SIZE:
1366 	return PCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
1367 
1368     case ACMDM_STREAM_CONVERT:
1369 	return PCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
1370 
1371     case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
1372     case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
1373 	/* this converter is not a hardware driver */
1374     case ACMDM_FILTERTAG_DETAILS:
1375     case ACMDM_FILTER_DETAILS:
1376 	/* this converter is not a filter */
1377     case ACMDM_STREAM_RESET:
1378 	/* only needed for asynchronous driver... we aren't, so just say it */
1379     case ACMDM_STREAM_PREPARE:
1380     case ACMDM_STREAM_UNPREPARE:
1381 	/* nothing special to do here... so don't do anything */
1382 	return MMSYSERR_NOTSUPPORTED;
1383 
1384     default:
1385 	return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1386     }
1387 }
1388