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