[MSACM32] Sync with Wine Staging 1.7.55. CORE-10536
[reactos.git] / reactos / 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 = MM_MICROSOFT;
708 add->wPid = MM_MSFT_ACM_PCM;
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, "MS-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("source format 0x%x not supported\n", adfs->pwfxSrc->wFormatTag);
842 return ACMERR_NOTPOSSIBLE;
843 }
844 adfs->pwfxDst->wFormatTag = adfs->pwfxSrc->wFormatTag;
845 } else {
846 if (adfs->pwfxDst->wFormatTag != WAVE_FORMAT_PCM) {
847 WARN("destination format 0x%x not supported\n", adfs->pwfxDst->wFormatTag);
848 return ACMERR_NOTPOSSIBLE;
849 }
850 }
851 /* check if result is ok */
852 if (PCM_GetFormatIndex(adfs->pwfxDst) == 0xFFFFFFFF) {
853 WARN("not possible\n");
854 return ACMERR_NOTPOSSIBLE;
855 }
856
857 /* recompute other values */
858 adfs->pwfxDst->nBlockAlign = (adfs->pwfxDst->nChannels * adfs->pwfxDst->wBitsPerSample) / 8;
859 adfs->pwfxDst->nAvgBytesPerSec = adfs->pwfxDst->nSamplesPerSec * adfs->pwfxDst->nBlockAlign;
860
861 return MMSYSERR_NOERROR;
862 }
863
864 /***********************************************************************
865 * PCM_StreamOpen
866 *
867 */
868 static LRESULT PCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
869 {
870 AcmPcmData* apd;
871 int idx = 0;
872
873 TRACE("(%p)\n", adsi);
874
875 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
876
877 apd = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmPcmData));
878 if (apd == 0) {
879 WARN("no memory\n");
880 return MMSYSERR_NOMEM;
881 }
882
883 adsi->dwDriver = (DWORD_PTR)apd;
884 adsi->fdwDriver = 0;
885
886 if (adsi->pwfxSrc->wBitsPerSample == 16) idx += 8;
887 if (adsi->pwfxDst->wBitsPerSample == 16) idx += 4;
888 if (adsi->pwfxSrc->nChannels == 1) idx += 2;
889 if (adsi->pwfxDst->nChannels == 1) idx += 1;
890
891 if (adsi->pwfxSrc->nSamplesPerSec == adsi->pwfxDst->nSamplesPerSec) {
892 apd->cvt.cvtKeepRate = PCM_ConvertKeepRate[idx];
893 } else {
894 adsi->fdwDriver |= PCM_RESAMPLE;
895 apd->cvt.cvtChangeRate = PCM_ConvertChangeRate[idx];
896 }
897
898 return MMSYSERR_NOERROR;
899 }
900
901 /***********************************************************************
902 * PCM_StreamClose
903 *
904 */
905 static LRESULT PCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
906 {
907 TRACE("(%p)\n", adsi);
908
909 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
910 return MMSYSERR_NOERROR;
911 }
912
913 /***********************************************************************
914 * PCM_round
915 *
916 */
917 static inline DWORD PCM_round(DWORD a, DWORD b, DWORD c)
918 {
919 assert(c);
920 /* to be sure, always return an entire number of c... */
921 return ((double)a * (double)b + (double)c - 1) / (double)c;
922 }
923
924 /***********************************************************************
925 * PCM_StreamSize
926 *
927 */
928 static LRESULT PCM_StreamSize(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMSIZE adss)
929 {
930 DWORD srcMask = ~(adsi->pwfxSrc->nBlockAlign - 1);
931 DWORD dstMask = ~(adsi->pwfxDst->nBlockAlign - 1);
932
933 TRACE("(%p, %p)\n", adsi, adss);
934
935 switch (adss->fdwSize) {
936 case ACM_STREAMSIZEF_DESTINATION:
937 /* cbDstLength => cbSrcLength */
938 adss->cbSrcLength = PCM_round(adss->cbDstLength & dstMask,
939 adsi->pwfxSrc->nAvgBytesPerSec,
940 adsi->pwfxDst->nAvgBytesPerSec) & srcMask;
941 break;
942 case ACM_STREAMSIZEF_SOURCE:
943 /* cbSrcLength => cbDstLength */
944 adss->cbDstLength = PCM_round(adss->cbSrcLength & srcMask,
945 adsi->pwfxDst->nAvgBytesPerSec,
946 adsi->pwfxSrc->nAvgBytesPerSec) & dstMask;
947 break;
948 default:
949 WARN("Unsupported query %08x\n", adss->fdwSize);
950 return MMSYSERR_NOTSUPPORTED;
951 }
952 return MMSYSERR_NOERROR;
953 }
954
955 /***********************************************************************
956 * PCM_StreamConvert
957 *
958 */
959 static LRESULT PCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
960 {
961 AcmPcmData* apd = (AcmPcmData*)adsi->dwDriver;
962 DWORD nsrc = NUM_OF(adsh->cbSrcLength, adsi->pwfxSrc->nBlockAlign);
963 DWORD ndst = NUM_OF(adsh->cbDstLength, adsi->pwfxDst->nBlockAlign);
964
965 TRACE("(%p, %p)\n", adsi, adsh);
966
967 TRACE("nsrc=%d,adsh->cbSrcLength=%d\n", nsrc, adsh->cbSrcLength);
968 TRACE("ndst=%d,adsh->cbDstLength=%d\n", ndst, adsh->cbDstLength);
969 TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
970 adsi->pwfxSrc->wFormatTag, adsi->pwfxSrc->nChannels, adsi->pwfxSrc->nSamplesPerSec, adsi->pwfxSrc->nAvgBytesPerSec,
971 adsi->pwfxSrc->nBlockAlign, adsi->pwfxSrc->wBitsPerSample, adsi->pwfxSrc->cbSize);
972 TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
973 adsi->pwfxDst->wFormatTag, adsi->pwfxDst->nChannels, adsi->pwfxDst->nSamplesPerSec, adsi->pwfxDst->nAvgBytesPerSec,
974 adsi->pwfxDst->nBlockAlign, adsi->pwfxDst->wBitsPerSample, adsi->pwfxDst->cbSize);
975
976 if (adsh->fdwConvert &
977 ~(ACM_STREAMCONVERTF_BLOCKALIGN|
978 ACM_STREAMCONVERTF_END|
979 ACM_STREAMCONVERTF_START)) {
980 FIXME("Unsupported fdwConvert (%08x), ignoring it\n", adsh->fdwConvert);
981 }
982 /* ACM_STREAMCONVERTF_BLOCKALIGN
983 * currently all conversions are block aligned, so do nothing for this flag
984 * ACM_STREAMCONVERTF_END
985 * no pending data, so do nothing for this flag
986 */
987 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START) &&
988 (adsi->fdwDriver & PCM_RESAMPLE)) {
989 }
990
991 /* do the job */
992 if (adsi->fdwDriver & PCM_RESAMPLE) {
993 DWORD nsrc2 = nsrc;
994 DWORD ndst2 = ndst;
995 apd->cvt.cvtChangeRate(adsi->pwfxSrc->nSamplesPerSec, adsh->pbSrc, &nsrc2,
996 adsi->pwfxDst->nSamplesPerSec, adsh->pbDst, &ndst2);
997 nsrc -= nsrc2;
998 ndst -= ndst2;
999 } else {
1000 if (nsrc < ndst) ndst = nsrc; else nsrc = ndst;
1001
1002 /* nsrc is now equal to ndst */
1003 apd->cvt.cvtKeepRate(adsh->pbSrc, nsrc, adsh->pbDst);
1004 }
1005
1006 adsh->cbSrcLengthUsed = nsrc * adsi->pwfxSrc->nBlockAlign;
1007 adsh->cbDstLengthUsed = ndst * adsi->pwfxDst->nBlockAlign;
1008
1009 return MMSYSERR_NOERROR;
1010 }
1011
1012 /**************************************************************************
1013 * DriverProc (MSACM32.@)
1014 */
1015 LRESULT CALLBACK PCM_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
1016 LPARAM dwParam1, LPARAM dwParam2)
1017 {
1018 TRACE("(%08lx %p %u %08lx %08lx);\n",
1019 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1020
1021 switch (wMsg) {
1022 case DRV_LOAD: return 1;
1023 case DRV_FREE: return 1;
1024 case DRV_OPEN: return PCM_drvOpen((LPSTR)dwParam1, (PACMDRVOPENDESCW)dwParam2);
1025 case DRV_CLOSE: return PCM_drvClose(dwDevID);
1026 case DRV_ENABLE: return 1;
1027 case DRV_DISABLE: return 1;
1028 case DRV_QUERYCONFIGURE: return 1;
1029 case DRV_CONFIGURE: MessageBoxA(0, "MSACM PCM filter !", "Wine Driver", MB_OK); return 1;
1030 case DRV_INSTALL: return DRVCNF_RESTART;
1031 case DRV_REMOVE: return DRVCNF_RESTART;
1032
1033 case ACMDM_DRIVER_NOTIFY:
1034 /* no caching from other ACM drivers is done so far */
1035 return MMSYSERR_NOERROR;
1036
1037 case ACMDM_DRIVER_DETAILS:
1038 return PCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
1039
1040 case ACMDM_FORMATTAG_DETAILS:
1041 return PCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
1042
1043 case ACMDM_FORMAT_DETAILS:
1044 return PCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
1045
1046 case ACMDM_FORMAT_SUGGEST:
1047 return PCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
1048
1049 case ACMDM_STREAM_OPEN:
1050 return PCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
1051
1052 case ACMDM_STREAM_CLOSE:
1053 return PCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
1054
1055 case ACMDM_STREAM_SIZE:
1056 return PCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
1057
1058 case ACMDM_STREAM_CONVERT:
1059 return PCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
1060
1061 case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
1062 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
1063 /* this converter is not a hardware driver */
1064 case ACMDM_FILTERTAG_DETAILS:
1065 case ACMDM_FILTER_DETAILS:
1066 /* this converter is not a filter */
1067 case ACMDM_STREAM_RESET:
1068 /* only needed for asynchronous driver... we aren't, so just say it */
1069 case ACMDM_STREAM_PREPARE:
1070 case ACMDM_STREAM_UNPREPARE:
1071 /* nothing special to do here... so don't do anything */
1072 return MMSYSERR_NOTSUPPORTED;
1073
1074 default:
1075 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1076 }
1077 }