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