source: trunk/src/msacm32/pcmconverter.c

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

restored old version

File size: 27.8 KB
RevLine 
[5434]1/* -*- tab-width: 8; c-basic-offset: 4 -*- */
[6712]2
[5434]3/*
4 * MSACM32 library
5 *
[6712]6 * Copyright 2000 Eric Pouech
[5434]7 *
[6712]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
[5434]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 */
[6712]37static DWORD PCM_drvOpen(LPCSTR str)
[5434]38{
39 return 1;
40}
41
42/***********************************************************************
43 * PCM_drvClose
44 */
[6712]45static DWORD PCM_drvClose(DWORD dwDevID)
[5434]46{
47 return 1;
48}
49
[6712]50#define NUM_PCM_FORMATS (sizeof(PCM_Formats) / sizeof(PCM_Formats[0]))
51#define NUM_OF(a,b) (((a)+(b)-1)/(b))
[5434]52
53/* flags for fdwDriver */
[6712]54#define PCM_RESAMPLE 1
[5434]55
56/* data used while converting */
57typedef struct tagAcmPcmData {
58 /* conversion routine, depending if rate conversion is required */
59 union {
[6712]60 void (*cvtKeepRate)(const unsigned char*, int, unsigned char*);
61 void (*cvtChangeRate)(struct tagAcmPcmData*, const unsigned char*,
62 LPDWORD, unsigned char*, LPDWORD);
[5434]63 } cvt;
64 /* the following fields are used only with rate conversion) */
[6712]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 */
[5434]69 /* last source stream value read */
70 union {
[6712]71 unsigned char b; /* 8 bit value */
72 short s; /* 16 bit value */
[5434]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 */
[6712]79static struct {
80 int nChannels;
81 int nBits;
82 int rate;
[5434]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 */
[6712]93static DWORD PCM_GetFormatIndex(LPWAVEFORMATEX wfx)
[5434]94{
95 int i;
[6712]96
[5434]97 for (i = 0; i < NUM_PCM_FORMATS; i++) {
[6712]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;
[5434]102 }
103 return 0xFFFFFFFF;
104}
105
106/* PCM Conversions:
107 *
108 * parameters:
[6712]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)
[5434]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
[6712]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
[5434]120 */
121
122/***********************************************************************
123 * C816
124 *
125 * Converts a 8 bit sample to a 16 bit one
126 */
[6712]127static inline short C816(unsigned char b)
[5434]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 */
[6712]137static inline unsigned char C168(short s)
[5434]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 *
[6712]166 * Convert the (l,r) 16 bit stereo sample into a 16 bit mono
[5434]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 *
[6712]177 * Convert the (l,r) 8 bit stereo sample into a 8 bit mono
[5434]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
[6712]196static void cvtMM88K(const unsigned char* src, int ns, unsigned char* dst)
[5434]197{
198 memcpy(dst, src, ns);
199}
200
[6712]201static void cvtSS88K(const unsigned char* src, int ns, unsigned char* dst)
[5434]202{
203 memcpy(dst, src, ns * 2);
204}
205
[6712]206static void cvtMM1616K(const unsigned char* src, int ns, unsigned char* dst)
[5434]207{
208 memcpy(dst, src, ns * 2);
209}
210
[6712]211static void cvtSS1616K(const unsigned char* src, int ns, unsigned char* dst)
[5434]212{
213 memcpy(dst, src, ns * 4);
214}
215
[6712]216static void cvtMS88K(const unsigned char* src, int ns, unsigned char* dst)
[5434]217{
218 while (ns--) {
[6712]219 *dst++ = *src;
220 *dst++ = *src++;
[5434]221 }
222}
223
[6712]224static void cvtMS816K(const unsigned char* src, int ns, unsigned char* dst)
[5434]225{
[6712]226 short v;
227
[5434]228 while (ns--) {
[6712]229 v = C816(*src++);
230 W16(dst, v); dst += 2;
231 W16(dst, v); dst += 2;
[5434]232 }
233}
234
[6712]235static void cvtMS168K(const unsigned char* src, int ns, unsigned char* dst)
[5434]236{
237 unsigned char v;
[6712]238
[5434]239 while (ns--) {
[6712]240 v = C168(R16(src)); src += 2;
241 *dst++ = v;
242 *dst++ = v;
[5434]243 }
244}
245
[6712]246static void cvtMS1616K(const unsigned char* src, int ns, unsigned char* dst)
[5434]247{
[6712]248 short v;
[5434]249
250 while (ns--) {
[6712]251 v = R16(src); src += 2;
252 W16(dst, v); dst += 2;
253 W16(dst, v); dst += 2;
[5434]254 }
255}
256
[6712]257static void cvtSM88K(const unsigned char* src, int ns, unsigned char* dst)
[5434]258{
259 while (ns--) {
[6712]260 *dst++ = M8(src[0], src[1]);
261 src += 2;
[5434]262 }
263}
264
[6712]265static void cvtSM816K(const unsigned char* src, int ns, unsigned char* dst)
[5434]266{
[6712]267 short v;
268
[5434]269 while (ns--) {
[6712]270 v = M16(C816(src[0]), C816(src[1]));
271 src += 2;
272 W16(dst, v); dst += 2;
[5434]273 }
274}
275
[6712]276static void cvtSM168K(const unsigned char* src, int ns, unsigned char* dst)
[5434]277{
278 while (ns--) {
[6712]279 *dst++ = C168(M16(R16(src), R16(src + 2)));
280 src += 4;
[5434]281 }
282}
283
[6712]284static void cvtSM1616K(const unsigned char* src, int ns, unsigned char* dst)
[5434]285{
286 while (ns--) {
[6712]287 W16(dst, M16(R16(src),R16(src+2))); dst += 2;
288 src += 4;
[5434]289 }
290}
291
[6712]292static void cvtMM816K(const unsigned char* src, int ns, unsigned char* dst)
[5434]293{
294 while (ns--) {
[6712]295 W16(dst, C816(*src++)); dst += 2;
[5434]296 }
297}
298
[6712]299static void cvtSS816K(const unsigned char* src, int ns, unsigned char* dst)
[5434]300{
301 while (ns--) {
[6712]302 W16(dst, C816(*src++)); dst += 2;
303 W16(dst, C816(*src++)); dst += 2;
[5434]304 }
305}
306
[6712]307static void cvtMM168K(const unsigned char* src, int ns, unsigned char* dst)
[5434]308{
309 while (ns--) {
[6712]310 *dst++ = C168(R16(src)); src += 2;
[5434]311 }
312}
313
[6712]314static void cvtSS168K(const unsigned char* src, int ns, unsigned char* dst)
[5434]315{
316 while (ns--) {
[6712]317 *dst++ = C168(R16(src)); src += 2;
318 *dst++ = C168(R16(src)); src += 2;
[5434]319 }
320}
321
[6712]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,
[5434]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 */
[6712]335static inline double I(double v1, double v2, double r)
[5434]336{
337 if (0.0 >= r || r > 1.0) FIXME("r!! %f\n", r);
338 return (1.0 - r) * v1 + r * v2;
339}
340
[6712]341static void cvtSS88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
342 unsigned char* dst, LPDWORD ndst)
[5434]343{
[6712]344 double r;
[5434]345
346 while (*nsrc != 0 && *ndst != 0) {
[6712]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)--;
[5434]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 */
[6712]370static void cvtSM88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
371 unsigned char* dst, LPDWORD ndst)
[5434]372{
[6712]373 double r;
[5434]374
375 while (*nsrc != 0 && *ndst != 0) {
[6712]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)--;
[5434]387 }
388}
389
[6712]390static void cvtMS88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
391 unsigned char* dst, LPDWORD ndst)
[5434]392{
[6712]393 double r;
[5434]394
395 while (*nsrc != 0 && *ndst != 0) {
[6712]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)--;
[5434]407 }
408}
409
[6712]410static void cvtMM88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
411 unsigned char* dst, LPDWORD ndst)
[5434]412{
[6712]413 double r;
[5434]414
415 while (*nsrc != 0 && *ndst != 0) {
[6712]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)--;
[5434]426 }
427}
428
[6712]429static void cvtSS816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
430 unsigned char* dst, LPDWORD ndst)
[5434]431{
[6712]432 double r;
433
[5434]434 while (*nsrc != 0 && *ndst != 0) {
[6712]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)--;
[5434]447 }
448}
449
[6712]450static void cvtSM816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
451 unsigned char* dst, LPDWORD ndst)
[5434]452{
[6712]453 double r;
[5434]454
455 while (*nsrc != 0 && *ndst != 0) {
[6712]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)--;
[5434]469 }
470}
471
[6712]472static void cvtMS816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
473 unsigned char* dst, LPDWORD ndst)
[5434]474{
[6712]475 double r;
476 short v;
[5434]477
478 while (*nsrc != 0 && *ndst != 0) {
[6712]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)--;
[5434]491 }
492}
493
[6712]494static void cvtMM816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
495 unsigned char* dst, LPDWORD ndst)
[5434]496{
[6712]497 double r;
[5434]498
499 while (*nsrc != 0 && *ndst != 0) {
[6712]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)--;
[5434]511 }
512}
513
[6712]514static void cvtSS168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
515 unsigned char* dst, LPDWORD ndst)
[5434]516{
[6712]517 double r;
[5434]518
519 while (*nsrc != 0 && *ndst != 0) {
[6712]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)--;
[5434]532 }
533}
534
[6712]535static void cvtSM168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
536 unsigned char* dst, LPDWORD ndst)
[5434]537{
[6712]538 double r;
[5434]539
540 while (*nsrc != 0 && *ndst != 0) {
[6712]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)--;
[5434]553 }
554}
555
556
[6712]557static void cvtMS168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
558 unsigned char* dst, LPDWORD ndst)
[5434]559{
[6712]560 double r;
[5434]561
562 while (*nsrc != 0 && *ndst != 0) {
[6712]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)--;
[5434]573 }
574}
575
576
[6712]577static void cvtMM168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
578 unsigned char* dst, LPDWORD ndst)
[5434]579{
[6712]580 double r;
[5434]581
582 while (*nsrc != 0 && *ndst != 0) {
[6712]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)--;
[5434]593 }
594}
595
[6712]596static void cvtSS1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
597 unsigned char* dst, LPDWORD ndst)
[5434]598{
[6712]599 double r;
[5434]600
601 while (*nsrc != 0 && *ndst != 0) {
[6712]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)--;
[5434]614 }
615}
616
[6712]617static void cvtSM1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
618 unsigned char* dst, LPDWORD ndst)
[5434]619{
[6712]620 double r;
[5434]621
622 while (*nsrc != 0 && *ndst != 0) {
[6712]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)--;
[5434]636 }
637}
638
[6712]639static void cvtMS1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
640 unsigned char* dst, LPDWORD ndst)
[5434]641{
[6712]642 double r;
643 short v;
[5434]644
645 while (*nsrc != 0 && *ndst != 0) {
[6712]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)--;
[5434]658 }
659}
660
[6712]661static void cvtMM1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
662 unsigned char* dst, LPDWORD ndst)
[5434]663{
[6712]664 double r;
[5434]665
666 while (*nsrc != 0 && *ndst != 0) {
[6712]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)--;
[5434]677 }
678}
679
[6712]680static void (*PCM_ConvertChangeRate[16])(AcmPcmData* apd,
681 const unsigned char* src, LPDWORD nsrc,
682 unsigned char* dst, LPDWORD ndst) = {
[5434]683 cvtSS88C, cvtSM88C, cvtMS88C, cvtMM88C,
[6712]684 cvtSS816C, cvtSM816C, cvtMS816C, cvtMM816C,
685 cvtSS168C, cvtSM168C, cvtMS168C, cvtMM168C,
[5434]686 cvtSS1616C, cvtSM1616C, cvtMS1616C, cvtMM1616C,
687};
688
689/***********************************************************************
690 * PCM_DriverDetails
691 *
692 */
[6712]693static LRESULT PCM_DriverDetails(PACMDRIVERDETAILSW add)
[5434]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;
[6712]714
[5434]715 return MMSYSERR_NOERROR;
716}
717
718/***********************************************************************
719 * PCM_FormatTagDetails
720 *
721 */
[6712]722static LRESULT PCM_FormatTagDetails(PACMFORMATTAGDETAILSW aftd, DWORD dwQuery)
[5434]723{
724 switch (dwQuery) {
725 case ACM_FORMATTAGDETAILSF_INDEX:
[6712]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;
[5434]731 case ACM_FORMATTAGDETAILSF_LARGESTSIZE:
[6712]732 if (aftd->dwFormatTag != WAVE_FORMAT_UNKNOWN &&
733 aftd->dwFormatTag != WAVE_FORMAT_UNKNOWN)
734 return ACMERR_NOTPOSSIBLE;
735 break;
[5434]736 default:
[6712]737 WARN("Unsupported query %08lx\n", dwQuery);
738 return MMSYSERR_NOTSUPPORTED;
[5434]739 }
[6712]740
[5434]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;
[6712]747
[5434]748 return MMSYSERR_NOERROR;
749}
750
751/***********************************************************************
752 * PCM_FormatDetails
753 *
754 */
[6712]755static LRESULT PCM_FormatDetails(PACMFORMATDETAILSW afd, DWORD dwQuery)
[5434]756{
757 switch (dwQuery) {
758 case ACM_FORMATDETAILSF_FORMAT:
[6712]759 afd->dwFormatIndex = PCM_GetFormatIndex(afd->pwfx);
760 if (afd->dwFormatIndex == 0xFFFFFFFF) return ACMERR_NOTPOSSIBLE;
761 break;
[5434]762 case ACM_FORMATDETAILSF_INDEX:
[6712]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;
[5434]776 default:
[6712]777 WARN("Unsupported query %08lx\n", dwQuery);
778 return MMSYSERR_NOTSUPPORTED;
[5434]779 }
[6712]780
[5434]781 afd->dwFormatTag = WAVE_FORMAT_PCM;
782 afd->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER;
783 afd->szFormat[0] = 0; /* let MSACM format this for us... */
[6712]784
[5434]785 return MMSYSERR_NOERROR;
786}
787
788/***********************************************************************
789 * PCM_FormatSuggest
790 *
791 */
[6712]792static LRESULT PCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
[5434]793{
794 FIXME("(%p);\n", adfs);
795 return MMSYSERR_NOTSUPPORTED;
796}
797
798/***********************************************************************
799 * PCM_Reset
800 *
801 */
[6712]802static void PCM_Reset(AcmPcmData* apd, int srcNumBits)
[5434]803{
804 apd->srcPos = 0;
805 apd->dstPos = 0;
806 /* initialize with neutral value */
807 if (srcNumBits == 16) {
[6712]808 apd->last[0].s = 0;
809 apd->last[1].s = 0;
[5434]810 } else {
[6712]811 apd->last[0].b = (BYTE)0x80;
812 apd->last[1].b = (BYTE)0x80;
[5434]813 }
814}
815
816/***********************************************************************
817 * PCM_StreamOpen
818 *
819 */
[6712]820static LRESULT PCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
[5434]821{
[6712]822 AcmPcmData* apd;
823 int idx = 0;
[5434]824
825 assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
[6712]826
[5434]827 if (PCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
[6712]828 PCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF)
829 return ACMERR_NOTPOSSIBLE;
[5434]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;
[6712]836
[5434]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) {
[6712]843 apd->cvt.cvtKeepRate = PCM_ConvertKeepRate[idx];
[5434]844 } else {
[6712]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];
[5434]850 }
851
852 return MMSYSERR_NOERROR;
853}
854
855/***********************************************************************
856 * PCM_StreamClose
857 *
858 */
[6712]859static LRESULT PCM_StreamClose(PACMDRVSTREAMINSTANCE adsi)
[5434]860{
861 HeapFree(GetProcessHeap(), 0, (void*)adsi->dwDriver);
862 return MMSYSERR_NOERROR;
863}
864
865/***********************************************************************
866 * PCM_round
867 *
868 */
[6712]869static inline DWORD PCM_round(DWORD a, DWORD b, DWORD c)
[5434]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 */
[6712]880static LRESULT PCM_StreamSize(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMSIZE adss)
[5434]881{
882 switch (adss->fdwSize) {
883 case ACM_STREAMSIZEF_DESTINATION:
[6712]884 /* cbDstLength => cbSrcLength */
885 adss->cbSrcLength = PCM_round(adss->cbDstLength,
886 adsi->pwfxSrc->nAvgBytesPerSec,
887 adsi->pwfxDst->nAvgBytesPerSec);
888 break;
[5434]889 case ACM_STREAMSIZEF_SOURCE:
[6712]890 /* cbSrcLength => cbDstLength */
891 adss->cbDstLength = PCM_round(adss->cbSrcLength,
892 adsi->pwfxDst->nAvgBytesPerSec,
893 adsi->pwfxSrc->nAvgBytesPerSec);
894 break;
[5434]895 default:
[6712]896 WARN("Unsupported query %08lx\n", adss->fdwSize);
897 return MMSYSERR_NOTSUPPORTED;
[5434]898 }
899 return MMSYSERR_NOERROR;
900}
901
902/***********************************************************************
903 * PCM_StreamConvert
904 *
905 */
906static LRESULT PCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER adsh)
907{
[6712]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);
[5434]911
[6712]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);
[5434]917 }
918 /* ACM_STREAMCONVERTF_BLOCKALIGN
[6712]919 * currently all conversions are block aligned, so do nothing for this flag
[5434]920 * ACM_STREAMCONVERTF_END
[6712]921 * no pending data, so do nothing for this flag
[5434]922 */
[6712]923 if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START) &&
924 (adsi->fdwDriver & PCM_RESAMPLE)) {
925 PCM_Reset(apd, adsi->pwfxSrc->wBitsPerSample);
[5434]926 }
927
928 /* do the job */
929 if (adsi->fdwDriver & PCM_RESAMPLE) {
[6712]930 DWORD nsrc2 = nsrc;
931 DWORD ndst2 = ndst;
[5434]932
[6712]933 apd->cvt.cvtChangeRate(apd, adsh->pbSrc, &nsrc2, adsh->pbDst, &ndst2);
934 nsrc -= nsrc2;
935 ndst -= ndst2;
[5434]936 } else {
[6712]937 if (nsrc < ndst) ndst = nsrc; else nsrc = ndst;
[5434]938
[6712]939 /* nsrc is now equal to ndst */
940 apd->cvt.cvtKeepRate(adsh->pbSrc, nsrc, adsh->pbDst);
[5434]941 }
942
943 adsh->cbSrcLengthUsed = nsrc * adsi->pwfxSrc->nBlockAlign;
944 adsh->cbDstLengthUsed = ndst * adsi->pwfxDst->nBlockAlign;
945
946 return MMSYSERR_NOERROR;
947}
948
949/**************************************************************************
[6712]950 * PCM_DriverProc [exported]
[5434]951 */
[6712]952LRESULT CALLBACK PCM_DriverProc(DWORD dwDevID, HDRVR hDriv, UINT wMsg,
953 LPARAM dwParam1, LPARAM dwParam2)
[5434]954{
[6712]955 TRACE("(%08lx %08lx %u %08lx %08lx);\n",
956 dwDevID, (DWORD)hDriv, wMsg, dwParam1, dwParam2);
957
[5434]958 switch (wMsg) {
[6712]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
[5434]970 case ACMDM_DRIVER_NOTIFY:
[6712]971 /* no caching from other ACM drivers is done so far */
972 return MMSYSERR_NOERROR;
973
[5434]974 case ACMDM_DRIVER_DETAILS:
[6712]975 return PCM_DriverDetails((PACMDRIVERDETAILSW)dwParam1);
976
[5434]977 case ACMDM_FORMATTAG_DETAILS:
[6712]978 return PCM_FormatTagDetails((PACMFORMATTAGDETAILSW)dwParam1, dwParam2);
979
[5434]980 case ACMDM_FORMAT_DETAILS:
[6712]981 return PCM_FormatDetails((PACMFORMATDETAILSW)dwParam1, dwParam2);
982
[5434]983 case ACMDM_FORMAT_SUGGEST:
[6712]984 return PCM_FormatSuggest((PACMDRVFORMATSUGGEST)dwParam1);
985
[5434]986 case ACMDM_STREAM_OPEN:
[6712]987 return PCM_StreamOpen((PACMDRVSTREAMINSTANCE)dwParam1);
988
[5434]989 case ACMDM_STREAM_CLOSE:
[6712]990 return PCM_StreamClose((PACMDRVSTREAMINSTANCE)dwParam1);
991
[5434]992 case ACMDM_STREAM_SIZE:
[6712]993 return PCM_StreamSize((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMSIZE)dwParam2);
994
[5434]995 case ACMDM_STREAM_CONVERT:
[6712]996 return PCM_StreamConvert((PACMDRVSTREAMINSTANCE)dwParam1, (PACMDRVSTREAMHEADER)dwParam2);
997
[5434]998 case ACMDM_HARDWARE_WAVE_CAPS_INPUT:
999 case ACMDM_HARDWARE_WAVE_CAPS_OUTPUT:
[6712]1000 /* this converter is not a hardware driver */
[5434]1001 case ACMDM_FILTERTAG_DETAILS:
1002 case ACMDM_FILTER_DETAILS:
[6712]1003 /* this converter is not a filter */
[5434]1004 case ACMDM_STREAM_RESET:
[6712]1005 /* only needed for asynchronous driver... we aren't, so just say it */
[5434]1006 case ACMDM_STREAM_PREPARE:
1007 case ACMDM_STREAM_UNPREPARE:
[6712]1008 /* nothing special to do here... so don't do anything */
1009 return MMSYSERR_NOTSUPPORTED;
1010
[5434]1011 default:
[6712]1012 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
[5434]1013 }
1014 return 0;
1015}
Note: See TracBrowser for help on using the repository browser.