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