source: trunk/src/msacm32/pcmconverter.c@ 9095

Last change on this file since 9095 was 6712, checked in by sandervl, 24 years ago

restored old version

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