Commit 20f83973 authored by Robert Reif's avatar Robert Reif Committed by Alexandre Julliard

Make the PCM conversion routines of msacm produce identical results to

the native dll. Allow any PCM to PCM conversion, not just advertised ones.
parent 97b7e0de
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* MSACM32 library * MSACM32 library
* *
* Copyright 2000 Eric Pouech * Copyright 2000 Eric Pouech
* Copyright 2004 Robert Reif
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
...@@ -20,10 +21,6 @@ ...@@ -20,10 +21,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* FIXME / TODO list * FIXME / TODO list
* + most of the computation should be done in fixed point arithmetic
* instead of floating point (16 bits for integral part, and 16 bits
* for fractional part for example)
* + implement PCM_FormatSuggest function
* + get rid of hack for PCM_DriverProc (msacm32.dll shouldn't export * + get rid of hack for PCM_DriverProc (msacm32.dll shouldn't export
* a DriverProc, but this would require implementing a generic * a DriverProc, but this would require implementing a generic
* embedded driver handling scheme in msacm32.dll which isn't done yet * embedded driver handling scheme in msacm32.dll which isn't done yet
...@@ -75,7 +72,7 @@ static DWORD PCM_drvClose(DWORD dwDevID) ...@@ -75,7 +72,7 @@ static DWORD PCM_drvClose(DWORD dwDevID)
} }
#define NUM_PCM_FORMATS (sizeof(PCM_Formats) / sizeof(PCM_Formats[0])) #define NUM_PCM_FORMATS (sizeof(PCM_Formats) / sizeof(PCM_Formats[0]))
#define NUM_OF(a,b) (((a)+(b)-1)/(b)) #define NUM_OF(a,b) ((a)/(b))
/* flags for fdwDriver */ /* flags for fdwDriver */
#define PCM_RESAMPLE 1 #define PCM_RESAMPLE 1
...@@ -85,19 +82,9 @@ typedef struct tagAcmPcmData { ...@@ -85,19 +82,9 @@ typedef struct tagAcmPcmData {
/* conversion routine, depending if rate conversion is required */ /* conversion routine, depending if rate conversion is required */
union { union {
void (*cvtKeepRate)(const unsigned char*, int, unsigned char*); void (*cvtKeepRate)(const unsigned char*, int, unsigned char*);
void (*cvtChangeRate)(struct tagAcmPcmData*, const unsigned char*, void (*cvtChangeRate)(DWORD, const unsigned char*, LPDWORD,
LPDWORD, unsigned char*, LPDWORD); DWORD, unsigned char*, LPDWORD);
} cvt; } cvt;
/* the following fields are used only with rate conversion) */
DWORD srcPos; /* position in source stream */
double dstPos; /* position in destination stream */
double dstIncr; /* value to increment dst stream when src stream
is incremented by 1 */
/* last source stream value read */
union {
unsigned char b; /* 8 bit value */
short s; /* 16 bit value */
} last[2]; /* two channels max (stereo) */
} AcmPcmData; } AcmPcmData;
/* table to list all supported formats... those are the basic ones. this /* table to list all supported formats... those are the basic ones. this
...@@ -142,11 +129,7 @@ static DWORD PCM_GetFormatIndex(LPWAVEFORMATEX wfx) ...@@ -142,11 +129,7 @@ static DWORD PCM_GetFormatIndex(LPWAVEFORMATEX wfx)
* shall work in all cases) * shall work in all cases)
* *
* mono => stereo: copy the same sample on Left & Right channels * mono => stereo: copy the same sample on Left & Right channels
* stereo =) mono: use the average value of samples from Left & Right channels * stereo => mono: use the sum of Left & Right channels
* resampling; we lookup for each destination sample the two source adjacent
* samples were src <= dst < src+1 (dst is increased by a fractional
* value which is equivalent to the increment by one on src); then we
* use a linear interpolation between src and src+1
*/ */
/*********************************************************************** /***********************************************************************
...@@ -156,7 +139,7 @@ static DWORD PCM_GetFormatIndex(LPWAVEFORMATEX wfx) ...@@ -156,7 +139,7 @@ static DWORD PCM_GetFormatIndex(LPWAVEFORMATEX wfx)
*/ */
static inline short C816(unsigned char b) static inline short C816(unsigned char b)
{ {
return (short)((b+(b << 8))-32768); return (b - 128) << 8;
} }
/*********************************************************************** /***********************************************************************
...@@ -194,22 +177,40 @@ static inline void W16(unsigned char* dst, short s) ...@@ -194,22 +177,40 @@ static inline void W16(unsigned char* dst, short s)
* M16 * M16
* *
* Convert the (l,r) 16 bit stereo sample into a 16 bit mono * Convert the (l,r) 16 bit stereo sample into a 16 bit mono
* (takes the mid-point of the two values) * (takes the sum of the two values)
*/ */
static inline short M16(short l, short r) static inline short M16(short l, short r)
{ {
return (l + r) / 2; int sum = l + r;
/* clip sum to saturation */
if (sum > 32767)
sum = 32767;
else if (sum < -32768)
sum = -32768;
return sum;
} }
/*********************************************************************** /***********************************************************************
* M8 * M8
* *
* Convert the (l,r) 8 bit stereo sample into a 8 bit mono * Convert the (l,r) 8 bit stereo sample into a 8 bit mono
* (takes the mid-point of the two values) * (takes the sum of the two values)
*/ */
static inline unsigned char M8(unsigned char a, unsigned char b) static inline unsigned char M8(unsigned char a, unsigned char b)
{ {
return (unsigned char)((a + b) / 2); int l = a - 128;
int r = b - 128;
int sum = (l + r) + 128;
/* clip sum to saturation */
if (sum > 0xff)
sum = 0xff;
else if (sum < 0)
sum = 0;
return sum;
} }
/* the conversion routines without rate conversion are labelled cvt<X><Y><N><M>K /* the conversion routines without rate conversion are labelled cvt<X><Y><N><M>K
...@@ -275,7 +276,7 @@ static void cvtMS168K(const unsigned char* src, int ns, unsigned char* dst) ...@@ -275,7 +276,7 @@ static void cvtMS168K(const unsigned char* src, int ns, unsigned char* dst)
TRACE("(%p, %d, %p)\n", src, ns, dst); TRACE("(%p, %d, %p)\n", src, ns, dst);
while (ns--) { while (ns--) {
v = C168(R16(src)); src += 2; v = C168(R16(src)); src += 2;
*dst++ = v; *dst++ = v;
*dst++ = v; *dst++ = v;
} }
...@@ -380,40 +381,6 @@ static void (*PCM_ConvertKeepRate[16])(const unsigned char*, int, unsigned char* ...@@ -380,40 +381,6 @@ static void (*PCM_ConvertKeepRate[16])(const unsigned char*, int, unsigned char*
cvtSS1616K, cvtSM1616K, cvtMS1616K, cvtMM1616K, cvtSS1616K, cvtSM1616K, cvtMS1616K, cvtMM1616K,
}; };
/***********************************************************************
* I
*
* Interpolate the value at r (r in ]0, 1]) between the two points v1 and v2
* Linear interpolation is used
*/
static inline double I(double v1, double v2, double r)
{
if (0.0 >= r || r > 1.0) FIXME("r!! %f\n", r);
return (1.0 - r) * v1 + r * v2;
}
static void cvtSS88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
{
double r;
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst);
while (*nsrc != 0 && *ndst != 0) {
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
if (*nsrc == 0) return;
apd->last[0].b = *src++;
apd->last[1].b = *src++;
apd->srcPos++;
(*nsrc)--;
}
/* now do the interpolation */
*dst++ = I(apd->last[0].b, src[0], r);
*dst++ = I(apd->last[1].b, src[1], r);
apd->dstPos += apd->dstIncr;
(*ndst)--;
}
}
/* the conversion routines with rate conversion are labelled cvt<X><Y><N><M>C /* the conversion routines with rate conversion are labelled cvt<X><Y><N><M>C
* where : * where :
* <X> is the (M)ono/(S)tereo configuration of input channel * <X> is the (M)ono/(S)tereo configuration of input channel
...@@ -422,393 +389,320 @@ static void cvtSS88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, ...@@ -422,393 +389,320 @@ static void cvtSS88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
* <M> is the number of bits of output channel (8 or 16) * <M> is the number of bits of output channel (8 or 16)
* *
*/ */
static void cvtSM88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, static void cvtSS88C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst) DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{ {
double r; DWORD error = dstRate / 2;
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while (*nsrc != 0 && *ndst != 0) { while ((*ndst)--) {
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { *dst++ = *src;
if (*nsrc == 0) return; *dst++ = *src;
apd->last[0].b = *src++; error = error + srcRate;
apd->last[1].b = *src++; while (error > dstRate) {
apd->srcPos++; src += 2;
(*nsrc)--; (*nsrc)--;
} if (*nsrc == 0)
/* now do the interpolation */ return;
if (*nsrc) /* don't go off end of data */ error = error - dstRate;
*dst++ = I(M8(apd->last[0].b, apd->last[1].b), M8(src[0], src[1]), r); }
else
*dst++ = M8(apd->last[0].b, apd->last[1].b);
apd->dstPos += apd->dstIncr;
(*ndst)--;
} }
} }
static void cvtMS88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, static void cvtSM88C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst) DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{ {
double r; DWORD error = dstRate / 2;
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while (*nsrc != 0 && *ndst != 0) { while ((*ndst)--) {
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { *dst++ = M8(src[0], src[1]);
if (*nsrc == 0) return; error = error + srcRate;
apd->last[0].b = *src++; while (error > dstRate) {
apd->srcPos++; src += 2;
(*nsrc)--; (*nsrc)--;
} if (*nsrc == 0)
/* now do the interpolation */ return;
if (*nsrc) /* don't go off end of data */ error = error - dstRate;
dst[0] = dst[1] = I(apd->last[0].b, src[0], r); }
else
dst[0] = dst[1] = apd->last[0].b;
dst += 2;
apd->dstPos += apd->dstIncr;
(*ndst)--;
} }
} }
static void cvtMM88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, static void cvtMS88C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst) DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{ {
double r; DWORD error = dstRate / 2;
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while (*nsrc != 0 && *ndst != 0) { while ((*ndst)--) {
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { *dst++ = *src;
if (*nsrc == 0) return; *dst++ = *src;
apd->last[0].b = *src++; error = error + srcRate;
apd->srcPos++; while (error > dstRate) {
(*nsrc)--; src++;
} (*nsrc)--;
/* now do the interpolation */ if (*nsrc == 0)
if (*nsrc) /* don't go off end of data */ return;
*dst++ = I(apd->last[0].b, src[0], r); error = error - dstRate;
else }
*dst++ = apd->last[0].b;
apd->dstPos += apd->dstIncr;
(*ndst)--;
} }
} }
static void cvtSS816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, static void cvtMM88C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst) DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{ {
double r; DWORD error = dstRate / 2;
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while (*nsrc != 0 && *ndst != 0) { while ((*ndst)--) {
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { *dst++ = *src;
if (*nsrc == 0) return; error = error + srcRate;
apd->last[0].b = *src++; while (error > dstRate) {
apd->last[1].b = *src++; src++;
apd->srcPos++; (*nsrc)--;
(*nsrc)--; if (*nsrc==0)
} return;
/* now do the interpolation */ error = error - dstRate;
if (*nsrc) /* don't go off end of data */ }
W16(dst, I(C816(apd->last[0].b), C816(src[0]), r));
else
W16(dst, C816(apd->last[0].b));
dst += 2;
if (*nsrc) /* don't go off end of data */
W16(dst, I(C816(apd->last[1].b), C816(src[1]), r));
else
W16(dst, C816(apd->last[1].b));
dst += 2;
apd->dstPos += apd->dstIncr;
(*ndst)--;
} }
} }
static void cvtSM816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, static void cvtSS816C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst) DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{ {
double r; DWORD error = dstRate / 2;
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while (*nsrc != 0 && *ndst != 0) { while ((*ndst)--) {
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { W16(dst, C816(src[0])); dst += 2;
if (*nsrc == 0) return; W16(dst, C816(src[1])); dst += 2;
apd->last[0].b = *src++; error = error + srcRate;
apd->last[1].b = *src++; while (error > dstRate) {
apd->srcPos++; src += 2;
(*nsrc)--; (*nsrc)--;
} if (*nsrc==0)
/* now do the interpolation */ return;
if (*nsrc) /* don't go off end of data */ error = error - dstRate;
W16(dst, I(M16(C816(apd->last[0].b), C816(apd->last[1].b)), }
M16(C816(src[0]), C816(src[1])), r));
else
W16(dst, M16(C816(apd->last[0].b), C816(apd->last[1].b)));
dst += 2;
apd->dstPos += apd->dstIncr;
(*ndst)--;
} }
} }
static void cvtMS816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, static void cvtSM816C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst) DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{ {
double r; DWORD error = dstRate / 2;
short v; TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
TRACE("(%p, %p, %p->(%ld), %p, %p->(%ld))\n", apd, src, nsrc, *nsrc, dst, ndst, *ndst);
while ((*ndst)--) {
while (*nsrc != 0 && *ndst != 0) { W16(dst, M16(C816(src[0]), C816(src[1]))); dst += 2;
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { error = error + srcRate;
if (*nsrc == 0) return; while (error > dstRate) {
apd->last[0].b = *src++; src += 2;
apd->srcPos++; (*nsrc)--;
(*nsrc)--; if (*nsrc==0)
} return;
/* now do the interpolation */ error = error - dstRate;
if (*nsrc) /* don't go off end of data */ }
v = I(C816(apd->last[0].b), C816(src[0]), r);
else
v = C816(apd->last[0].b);
W16(dst, v); dst += 2;
W16(dst, v); dst += 2;
apd->dstPos += apd->dstIncr;
(*ndst)--;
} }
} }
static void cvtMM816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, static void cvtMS816C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst) DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{ {
double r; DWORD error = dstRate / 2;
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while (*nsrc != 0 && *ndst != 0) { while ((*ndst)--) {
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { W16(dst, C816(*src)); dst += 2;
if (*nsrc == 0) return; W16(dst, C816(*src)); dst += 2;
apd->last[0].b = *src++; error = error + srcRate;
apd->srcPos++; while (error > dstRate) {
(*nsrc)--; src++;
} (*nsrc)--;
/* now do the interpolation */ if (*nsrc==0)
if (*nsrc) /* don't go off end of data */ return;
W16(dst, I(C816(apd->last[0].b), C816(src[0]), r)); error = error - dstRate;
else }
W16(dst, C816(apd->last[0].b));
dst += 2;
apd->dstPos += apd->dstIncr;
(*ndst)--;
} }
} }
static void cvtSS168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, static void cvtMM816C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst) DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{ {
double r; DWORD error = dstRate / 2;
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while (*nsrc != 0 && *ndst != 0) { while ((*ndst)--) {
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { W16(dst, C816(*src)); dst += 2;
if (*nsrc == 0) return; error = error + srcRate;
apd->last[0].s = R16(src); src += 2; while (error > dstRate) {
apd->last[1].s = R16(src); src += 2; src++;
apd->srcPos++; (*nsrc)--;
(*nsrc)--; if (*nsrc==0)
} return;
/* now do the interpolation */ error = error - dstRate;
if (*nsrc) { /* don't go off end of data */
*dst++ = C168(I(apd->last[0].s, R16(src) , r));
*dst++ = C168(I(apd->last[1].s, R16(src+2), r));
} else {
*dst++ = C168(apd->last[0].s);
*dst++ = C168(apd->last[1].s);
} }
apd->dstPos += apd->dstIncr;
(*ndst)--;
} }
} }
static void cvtSM168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, static void cvtSS168C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst) DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{ {
double r; DWORD error = dstRate / 2;
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while (*nsrc != 0 && *ndst != 0) { while ((*ndst)--) {
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { *dst++ = C168(R16(src));
if (*nsrc == 0) return; *dst++ = C168(R16(src + 2));
apd->last[0].s = R16(src); src += 2; error = error + srcRate;
apd->last[1].s = R16(src); src += 2; while (error > dstRate) {
apd->srcPos++; src += 4;
(*nsrc)--; (*nsrc)--;
} if (*nsrc==0)
/* now do the interpolation */ return;
if (*nsrc) /* don't go off end of data */ error = error - dstRate;
*dst++ = C168(I(M16(apd->last[0].s, apd->last[1].s), }
M16(R16(src), R16(src + 2)), r));
else
*dst++ = C168(M16(apd->last[0].s, apd->last[1].s));
apd->dstPos += apd->dstIncr;
(*ndst)--;
} }
} }
static void cvtSM168C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
static void cvtMS168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, DWORD dstRate, unsigned char* dst, LPDWORD ndst)
unsigned char* dst, LPDWORD ndst)
{ {
double r; DWORD error = dstRate / 2;
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while (*nsrc != 0 && *ndst != 0) { while ((*ndst)--) {
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { *dst++ = C168(M16(R16(src), R16(src + 2)));
if (*nsrc == 0) return; error = error + srcRate;
apd->last[0].s = R16(src); src += 2; while (error > dstRate) {
apd->srcPos++; src += 4;
(*nsrc)--; (*nsrc)--;
} if (*nsrc==0)
/* now do the interpolation */ return;
if (*nsrc) /* don't go off end of data */ error = error - dstRate;
dst[0] = dst[1] = C168(I(apd->last[0].s, R16(src), r)); }
else
dst[0] = dst[1] = C168(apd->last[0].s);
dst += 2;
apd->dstPos += apd->dstIncr;
(*ndst)--;
} }
} }
static void cvtMS168C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{
DWORD error = dstRate / 2;
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while ((*ndst)--) {
*dst++ = C168(R16(src));
*dst++ = C168(R16(src));
error = error + srcRate;
while (error > dstRate) {
src += 2;
(*nsrc)--;
if (*nsrc==0)
return;
error = error - dstRate;
}
}
}
static void cvtMM168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, static void cvtMM168C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst) DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{ {
double r; DWORD error = dstRate / 2;
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while (*nsrc != 0 && *ndst != 0) { while ((*ndst)--) {
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { *dst++ = C168(R16(src));
if (*nsrc == 0) return; error = error + srcRate;
apd->last[0].s = R16(src); src += 2; while (error > dstRate) {
apd->srcPos++; src += 2;
(*nsrc)--; (*nsrc)--;
} if (*nsrc == 0)
/* now do the interpolation */ return;
if (*nsrc) /* don't go off end of data */ error = error - dstRate;
*dst++ = C168(I(apd->last[0].s, R16(src), r)); }
else
*dst++ = C168(apd->last[0].s);
apd->dstPos += apd->dstIncr;
(*ndst)--;
} }
} }
static void cvtSS1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, static void cvtSS1616C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst) DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{ {
double r; DWORD error = dstRate / 2;
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while (*nsrc != 0 && *ndst != 0) { while ((*ndst)--) {
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { W16(dst, R16(src)); dst += 2;
if (*nsrc == 0) return; W16(dst, R16(src)); dst += 2;
apd->last[0].s = R16(src); src += 2; error = error + srcRate;
apd->last[1].s = R16(src); src += 2; while (error > dstRate) {
apd->srcPos++; src += 4;
(*nsrc)--; (*nsrc)--;
} if (*nsrc == 0)
/* now do the interpolation */ return;
if (*nsrc) /* don't go off end of data */ error = error - dstRate;
W16(dst, I(apd->last[0].s, R16(src), r)); }
else
W16(dst, apd->last[0].s);
dst += 2;
if (*nsrc) /* don't go off end of data */
W16(dst, I(apd->last[1].s, R16(src+2), r));
else
W16(dst, apd->last[1].s);
dst += 2;
apd->dstPos += apd->dstIncr;
(*ndst)--;
} }
} }
static void cvtSM1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, static void cvtSM1616C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst) DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{ {
double r; DWORD error = dstRate / 2;
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while (*nsrc != 0 && *ndst != 0) { while ((*ndst)--) {
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { W16(dst, M16(R16(src), R16(src + 2))); dst += 2;
if (*nsrc == 0) return; error = error + srcRate;
apd->last[0].s = R16(src); src += 2; while (error > dstRate) {
apd->last[1].s = R16(src); src += 2; src += 4;
apd->srcPos++; (*nsrc)--;
(*nsrc)--; if (*nsrc == 0)
} return;
/* now do the interpolation */ error = error - dstRate;
if (*nsrc) /* don't go off end of data */ }
W16(dst, I(M16(apd->last[0].s, apd->last[1].s),
M16(R16(src), R16(src+2)), r));
else
W16(dst, M16(apd->last[0].s, apd->last[1].s));
dst += 2;
apd->dstPos += apd->dstIncr;
(*ndst)--;
} }
} }
static void cvtMS1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, static void cvtMS1616C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst) DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{ {
double r; DWORD error = dstRate / 2;
short v; TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst);
while((*ndst)--) {
while (*nsrc != 0 && *ndst != 0) { W16(dst, R16(src)); dst += 2;
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { W16(dst, R16(src)); dst += 2;
if (*nsrc == 0) return; error = error + srcRate;
apd->last[0].s = R16(src); src += 2; while (error > dstRate) {
apd->srcPos++; src += 2;
(*nsrc)--; (*nsrc)--;
} if (*nsrc == 0)
/* now do the interpolation */ return;
if (*nsrc) /* don't go off end of data */ error = error - dstRate;
v = I(apd->last[0].s, R16(src), r); }
else
v = apd->last[0].s;
W16(dst, v); dst += 2;
W16(dst, v); dst += 2;
apd->dstPos += apd->dstIncr;
(*ndst)--;
} }
} }
static void cvtMM1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc, static void cvtMM1616C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst) DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{ {
double r; DWORD error = dstRate / 2;
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst); TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while (*nsrc != 0 && *ndst != 0) { while ((*ndst)--) {
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) { W16(dst, R16(src)); dst += 2;
if (*nsrc == 0) return; error = error + srcRate;
apd->last[0].s = R16(src); src += 2; while (error > dstRate) {
apd->srcPos++; src += 2;
(*nsrc)--; (*nsrc)--;
} if (*nsrc == 0)
/* now do the interpolation */ return;
if (*nsrc) /* don't go off end of data */ error = error - dstRate;
W16(dst, I(apd->last[0].s, R16(src), r)); }
else
W16(dst, apd->last[0].s);
dst += 2;
apd->dstPos += apd->dstIncr;
(*ndst)--;
} }
} }
static void (*PCM_ConvertChangeRate[16])(AcmPcmData* apd, static void (*PCM_ConvertChangeRate[16])(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
const unsigned char* src, LPDWORD nsrc, DWORD dstRate, unsigned char* dst, LPDWORD ndst) = {
unsigned char* dst, LPDWORD ndst) = {
cvtSS88C, cvtSM88C, cvtMS88C, cvtMM88C, cvtSS88C, cvtSM88C, cvtMS88C, cvtMM88C,
cvtSS816C, cvtSM816C, cvtMS816C, cvtMM816C, cvtSS816C, cvtSM816C, cvtMS816C, cvtMM816C,
cvtSS168C, cvtSM168C, cvtMS168C, cvtMM168C, cvtSS168C, cvtSM168C, cvtMS168C, cvtMM168C,
...@@ -945,7 +839,7 @@ static LRESULT PCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs) ...@@ -945,7 +839,7 @@ static LRESULT PCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
PCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) { PCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) {
WARN("not possible\n"); WARN("not possible\n");
return ACMERR_NOTPOSSIBLE; return ACMERR_NOTPOSSIBLE;
} }
/* is no suggestion for destination, then copy source value */ /* is no suggestion for destination, then copy source value */
if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS)) { if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS)) {
...@@ -978,26 +872,6 @@ static LRESULT PCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs) ...@@ -978,26 +872,6 @@ static LRESULT PCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
} }
/*********************************************************************** /***********************************************************************
* PCM_Reset
*
*/
static void PCM_Reset(AcmPcmData* apd, int srcNumBits)
{
TRACE("(%p, %d)\n", apd, srcNumBits);
apd->srcPos = 0;
apd->dstPos = 0;
/* initialize with neutral value */
if (srcNumBits == 16) {
apd->last[0].s = 0;
apd->last[1].s = 0;
} else {
apd->last[0].b = (BYTE)0x80;
apd->last[1].b = (BYTE)0x80;
}
}
/***********************************************************************
* PCM_StreamOpen * PCM_StreamOpen
* *
*/ */
...@@ -1010,12 +884,6 @@ static LRESULT PCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi) ...@@ -1010,12 +884,6 @@ static LRESULT PCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC)); assert(!(adsi->fdwOpen & ACM_STREAMOPENF_ASYNC));
if (PCM_GetFormatIndex(adsi->pwfxSrc) == 0xFFFFFFFF ||
PCM_GetFormatIndex(adsi->pwfxDst) == 0xFFFFFFFF) {
WARN("not possible\n");
return ACMERR_NOTPOSSIBLE;
}
apd = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmPcmData)); apd = HeapAlloc(GetProcessHeap(), 0, sizeof(AcmPcmData));
if (apd == 0) { if (apd == 0) {
WARN("no memory\n"); WARN("no memory\n");
...@@ -1034,9 +902,6 @@ static LRESULT PCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi) ...@@ -1034,9 +902,6 @@ static LRESULT PCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
apd->cvt.cvtKeepRate = PCM_ConvertKeepRate[idx]; apd->cvt.cvtKeepRate = PCM_ConvertKeepRate[idx];
} else { } else {
adsi->fdwDriver |= PCM_RESAMPLE; adsi->fdwDriver |= PCM_RESAMPLE;
apd->dstIncr = (double)(adsi->pwfxSrc->nSamplesPerSec) /
(double)(adsi->pwfxDst->nSamplesPerSec);
PCM_Reset(apd, adsi->pwfxSrc->wBitsPerSample);
apd->cvt.cvtChangeRate = PCM_ConvertChangeRate[idx]; apd->cvt.cvtChangeRate = PCM_ConvertChangeRate[idx];
} }
...@@ -1131,15 +996,14 @@ static LRESULT PCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER ...@@ -1131,15 +996,14 @@ static LRESULT PCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER
*/ */
if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START) && if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START) &&
(adsi->fdwDriver & PCM_RESAMPLE)) { (adsi->fdwDriver & PCM_RESAMPLE)) {
PCM_Reset(apd, adsi->pwfxSrc->wBitsPerSample);
} }
/* do the job */ /* do the job */
if (adsi->fdwDriver & PCM_RESAMPLE) { if (adsi->fdwDriver & PCM_RESAMPLE) {
DWORD nsrc2 = nsrc; DWORD nsrc2 = nsrc;
DWORD ndst2 = ndst; DWORD ndst2 = ndst;
apd->cvt.cvtChangeRate((DWORD)adsi->pwfxSrc->nSamplesPerSec, adsh->pbSrc, &nsrc2,
apd->cvt.cvtChangeRate(apd, adsh->pbSrc, &nsrc2, adsh->pbDst, &ndst2); (DWORD)adsi->pwfxDst->nSamplesPerSec, adsh->pbDst, &ndst2);
nsrc -= nsrc2; nsrc -= nsrc2;
ndst -= ndst2; ndst -= ndst2;
} else { } else {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment