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