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 @@
* MSACM32 library
*
* Copyright 2000 Eric Pouech
* Copyright 2004 Robert Reif
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -20,10 +21,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* 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
* a DriverProc, but this would require implementing a generic
* embedded driver handling scheme in msacm32.dll which isn't done yet
......@@ -75,7 +72,7 @@ static DWORD PCM_drvClose(DWORD dwDevID)
}
#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 */
#define PCM_RESAMPLE 1
......@@ -85,19 +82,9 @@ typedef struct tagAcmPcmData {
/* conversion routine, depending if rate conversion is required */
union {
void (*cvtKeepRate)(const unsigned char*, int, unsigned char*);
void (*cvtChangeRate)(struct tagAcmPcmData*, const unsigned char*,
LPDWORD, unsigned char*, LPDWORD);
void (*cvtChangeRate)(DWORD, const unsigned char*, LPDWORD,
DWORD, unsigned char*, LPDWORD);
} 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;
/* table to list all supported formats... those are the basic ones. this
......@@ -142,11 +129,7 @@ static DWORD PCM_GetFormatIndex(LPWAVEFORMATEX wfx)
* shall work in all cases)
*
* mono => stereo: copy the same sample on Left & Right channels
* stereo =) mono: use the average value of samples from 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
* stereo => mono: use the sum of Left & Right channels
*/
/***********************************************************************
......@@ -156,7 +139,7 @@ static DWORD PCM_GetFormatIndex(LPWAVEFORMATEX wfx)
*/
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)
* M16
*
* 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)
{
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
*
* 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)
{
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
......@@ -275,7 +276,7 @@ static void cvtMS168K(const unsigned char* src, int ns, unsigned char* dst)
TRACE("(%p, %d, %p)\n", src, ns, dst);
while (ns--) {
v = C168(R16(src)); src += 2;
v = C168(R16(src)); src += 2;
*dst++ = v;
*dst++ = v;
}
......@@ -380,40 +381,6 @@ static void (*PCM_ConvertKeepRate[16])(const unsigned char*, int, unsigned char*
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
* where :
* <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,
* <M> is the number of bits of output channel (8 or 16)
*
*/
static void cvtSM88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
static void cvtSS88C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, 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 */
if (*nsrc) /* don't go off end of data */
*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)--;
DWORD error = dstRate / 2;
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while ((*ndst)--) {
*dst++ = *src;
*dst++ = *src;
error = error + srcRate;
while (error > dstRate) {
src += 2;
(*nsrc)--;
if (*nsrc == 0)
return;
error = error - dstRate;
}
}
}
static void cvtMS88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
static void cvtSM88C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, 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->srcPos++;
(*nsrc)--;
}
/* now do the interpolation */
if (*nsrc) /* don't go off end of data */
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)--;
DWORD error = dstRate / 2;
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while ((*ndst)--) {
*dst++ = M8(src[0], src[1]);
error = error + srcRate;
while (error > dstRate) {
src += 2;
(*nsrc)--;
if (*nsrc == 0)
return;
error = error - dstRate;
}
}
}
static void cvtMM88C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
static void cvtMS88C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, 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->srcPos++;
(*nsrc)--;
}
/* now do the interpolation */
if (*nsrc) /* don't go off end of data */
*dst++ = I(apd->last[0].b, src[0], r);
else
*dst++ = apd->last[0].b;
apd->dstPos += apd->dstIncr;
(*ndst)--;
DWORD error = dstRate / 2;
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while ((*ndst)--) {
*dst++ = *src;
*dst++ = *src;
error = error + srcRate;
while (error > dstRate) {
src++;
(*nsrc)--;
if (*nsrc == 0)
return;
error = error - dstRate;
}
}
}
static void cvtSS816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
static void cvtMM88C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, 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 */
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)--;
DWORD error = dstRate / 2;
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while ((*ndst)--) {
*dst++ = *src;
error = error + srcRate;
while (error > dstRate) {
src++;
(*nsrc)--;
if (*nsrc==0)
return;
error = error - dstRate;
}
}
}
static void cvtSM816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
static void cvtSS816C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, 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 */
if (*nsrc) /* don't go off end of data */
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)--;
DWORD error = dstRate / 2;
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while ((*ndst)--) {
W16(dst, C816(src[0])); dst += 2;
W16(dst, C816(src[1])); dst += 2;
error = error + srcRate;
while (error > dstRate) {
src += 2;
(*nsrc)--;
if (*nsrc==0)
return;
error = error - dstRate;
}
}
}
static void cvtMS816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
static void cvtSM816C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{
double r;
short v;
TRACE("(%p, %p, %p->(%ld), %p, %p->(%ld))\n", apd, src, nsrc, *nsrc, dst, ndst, *ndst);
while (*nsrc != 0 && *ndst != 0) {
while ((r = (double)apd->srcPos - apd->dstPos) <= 0) {
if (*nsrc == 0) return;
apd->last[0].b = *src++;
apd->srcPos++;
(*nsrc)--;
}
/* now do the interpolation */
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)--;
DWORD error = dstRate / 2;
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while ((*ndst)--) {
W16(dst, M16(C816(src[0]), C816(src[1]))); dst += 2;
error = error + srcRate;
while (error > dstRate) {
src += 2;
(*nsrc)--;
if (*nsrc==0)
return;
error = error - dstRate;
}
}
}
static void cvtMM816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
static void cvtMS816C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, 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->srcPos++;
(*nsrc)--;
}
/* now do the interpolation */
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;
apd->dstPos += apd->dstIncr;
(*ndst)--;
DWORD error = dstRate / 2;
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while ((*ndst)--) {
W16(dst, C816(*src)); dst += 2;
W16(dst, C816(*src)); dst += 2;
error = error + srcRate;
while (error > dstRate) {
src++;
(*nsrc)--;
if (*nsrc==0)
return;
error = error - dstRate;
}
}
}
static void cvtSS168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
static void cvtMM816C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, 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].s = R16(src); src += 2;
apd->last[1].s = R16(src); src += 2;
apd->srcPos++;
(*nsrc)--;
}
/* now do the interpolation */
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);
DWORD error = dstRate / 2;
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while ((*ndst)--) {
W16(dst, C816(*src)); dst += 2;
error = error + srcRate;
while (error > dstRate) {
src++;
(*nsrc)--;
if (*nsrc==0)
return;
error = error - dstRate;
}
apd->dstPos += apd->dstIncr;
(*ndst)--;
}
}
static void cvtSM168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
static void cvtSS168C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, 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].s = R16(src); src += 2;
apd->last[1].s = R16(src); src += 2;
apd->srcPos++;
(*nsrc)--;
}
/* now do the interpolation */
if (*nsrc) /* don't go off end of data */
*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)--;
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 + 2));
error = error + srcRate;
while (error > dstRate) {
src += 4;
(*nsrc)--;
if (*nsrc==0)
return;
error = error - dstRate;
}
}
}
static void cvtMS168C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
static void cvtSM168C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, 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].s = R16(src); src += 2;
apd->srcPos++;
(*nsrc)--;
}
/* now do the interpolation */
if (*nsrc) /* don't go off end of data */
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)--;
DWORD error = dstRate / 2;
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while ((*ndst)--) {
*dst++ = C168(M16(R16(src), R16(src + 2)));
error = error + srcRate;
while (error > dstRate) {
src += 4;
(*nsrc)--;
if (*nsrc==0)
return;
error = error - dstRate;
}
}
}
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,
unsigned char* dst, LPDWORD ndst)
static void cvtMM168C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, 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].s = R16(src); src += 2;
apd->srcPos++;
(*nsrc)--;
}
/* now do the interpolation */
if (*nsrc) /* don't go off end of data */
*dst++ = C168(I(apd->last[0].s, R16(src), r));
else
*dst++ = C168(apd->last[0].s);
apd->dstPos += apd->dstIncr;
(*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));
error = error + srcRate;
while (error > dstRate) {
src += 2;
(*nsrc)--;
if (*nsrc == 0)
return;
error = error - dstRate;
}
}
}
static void cvtSS1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
static void cvtSS1616C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, 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].s = R16(src); src += 2;
apd->last[1].s = R16(src); src += 2;
apd->srcPos++;
(*nsrc)--;
}
/* now do the interpolation */
if (*nsrc) /* don't go off end of data */
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)--;
DWORD error = dstRate / 2;
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while ((*ndst)--) {
W16(dst, R16(src)); dst += 2;
W16(dst, R16(src)); dst += 2;
error = error + srcRate;
while (error > dstRate) {
src += 4;
(*nsrc)--;
if (*nsrc == 0)
return;
error = error - dstRate;
}
}
}
static void cvtSM1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
static void cvtSM1616C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, 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].s = R16(src); src += 2;
apd->last[1].s = R16(src); src += 2;
apd->srcPos++;
(*nsrc)--;
}
/* now do the interpolation */
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)--;
DWORD error = dstRate / 2;
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while ((*ndst)--) {
W16(dst, M16(R16(src), R16(src + 2))); dst += 2;
error = error + srcRate;
while (error > dstRate) {
src += 4;
(*nsrc)--;
if (*nsrc == 0)
return;
error = error - dstRate;
}
}
}
static void cvtMS1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
static void cvtMS1616C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, unsigned char* dst, LPDWORD ndst)
{
double r;
short v;
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].s = R16(src); src += 2;
apd->srcPos++;
(*nsrc)--;
}
/* now do the interpolation */
if (*nsrc) /* don't go off end of data */
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)--;
DWORD error = dstRate / 2;
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while((*ndst)--) {
W16(dst, R16(src)); dst += 2;
W16(dst, R16(src)); dst += 2;
error = error + srcRate;
while (error > dstRate) {
src += 2;
(*nsrc)--;
if (*nsrc == 0)
return;
error = error - dstRate;
}
}
}
static void cvtMM1616C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst)
static void cvtMM1616C(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, 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].s = R16(src); src += 2;
apd->srcPos++;
(*nsrc)--;
}
/* now do the interpolation */
if (*nsrc) /* don't go off end of data */
W16(dst, I(apd->last[0].s, R16(src), r));
else
W16(dst, apd->last[0].s);
dst += 2;
apd->dstPos += apd->dstIncr;
(*ndst)--;
DWORD error = dstRate / 2;
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, dst, ndst);
while ((*ndst)--) {
W16(dst, R16(src)); dst += 2;
error = error + srcRate;
while (error > dstRate) {
src += 2;
(*nsrc)--;
if (*nsrc == 0)
return;
error = error - dstRate;
}
}
}
static void (*PCM_ConvertChangeRate[16])(AcmPcmData* apd,
const unsigned char* src, LPDWORD nsrc,
unsigned char* dst, LPDWORD ndst) = {
static void (*PCM_ConvertChangeRate[16])(DWORD srcRate, const unsigned char* src, LPDWORD nsrc,
DWORD dstRate, unsigned char* dst, LPDWORD ndst) = {
cvtSS88C, cvtSM88C, cvtMS88C, cvtMM88C,
cvtSS816C, cvtSM816C, cvtMS816C, cvtMM816C,
cvtSS168C, cvtSM168C, cvtMS168C, cvtMM168C,
......@@ -945,7 +839,7 @@ static LRESULT PCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
PCM_GetFormatIndex(adfs->pwfxSrc) == 0xFFFFFFFF) {
WARN("not possible\n");
return ACMERR_NOTPOSSIBLE;
}
}
/* is no suggestion for destination, then copy source value */
if (!(adfs->fdwSuggest & ACM_FORMATSUGGESTF_NCHANNELS)) {
......@@ -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
*
*/
......@@ -1010,12 +884,6 @@ static LRESULT PCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
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));
if (apd == 0) {
WARN("no memory\n");
......@@ -1034,9 +902,6 @@ static LRESULT PCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
apd->cvt.cvtKeepRate = PCM_ConvertKeepRate[idx];
} else {
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];
}
......@@ -1131,15 +996,14 @@ static LRESULT PCM_StreamConvert(PACMDRVSTREAMINSTANCE adsi, PACMDRVSTREAMHEADER
*/
if ((adsh->fdwConvert & ACM_STREAMCONVERTF_START) &&
(adsi->fdwDriver & PCM_RESAMPLE)) {
PCM_Reset(apd, adsi->pwfxSrc->wBitsPerSample);
}
/* do the job */
if (adsi->fdwDriver & PCM_RESAMPLE) {
DWORD nsrc2 = nsrc;
DWORD ndst2 = ndst;
apd->cvt.cvtChangeRate(apd, adsh->pbSrc, &nsrc2, adsh->pbDst, &ndst2);
apd->cvt.cvtChangeRate((DWORD)adsi->pwfxSrc->nSamplesPerSec, adsh->pbSrc, &nsrc2,
(DWORD)adsi->pwfxDst->nSamplesPerSec, adsh->pbDst, &ndst2);
nsrc -= nsrc2;
ndst -= ndst2;
} 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