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