Make the PCM conversion routines of msacm produce identical results to
the native dll. Allow any PCM to PCM conversion, not just advertised ones.
This commit is contained in:
parent
97b7e0dec7
commit
20f8397321
|
@ -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);
|
||||
DWORD error = dstRate / 2;
|
||||
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, 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)--;
|
||||
}
|
||||
}
|
||||
|
||||
static void cvtMS88C(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->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)--;
|
||||
}
|
||||
}
|
||||
|
||||
static void cvtMM88C(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->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)--;
|
||||
}
|
||||
}
|
||||
|
||||
static void cvtSS816C(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 */
|
||||
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,
|
||||
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)--;
|
||||
}
|
||||
}
|
||||
|
||||
static void cvtMS816C(AcmPcmData* apd, const unsigned char* src, LPDWORD nsrc,
|
||||
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)--;
|
||||
}
|
||||
}
|
||||
|
||||
static void cvtMM816C(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->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)--;
|
||||
}
|
||||
}
|
||||
|
||||
static void cvtSS168C(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].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);
|
||||
while ((*ndst)--) {
|
||||
*dst++ = *src;
|
||||
*dst++ = *src;
|
||||
error = error + srcRate;
|
||||
while (error > dstRate) {
|
||||
src += 2;
|
||||
(*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 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);
|
||||
DWORD error = dstRate / 2;
|
||||
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, 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)--;
|
||||
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 cvtMS168C(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);
|
||||
DWORD error = dstRate / 2;
|
||||
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, 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)--;
|
||||
while ((*ndst)--) {
|
||||
*dst++ = *src;
|
||||
*dst++ = *src;
|
||||
error = error + srcRate;
|
||||
while (error > dstRate) {
|
||||
src++;
|
||||
(*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 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);
|
||||
DWORD error = dstRate / 2;
|
||||
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, 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)--;
|
||||
while ((*ndst)--) {
|
||||
*dst++ = *src;
|
||||
error = error + srcRate;
|
||||
while (error > dstRate) {
|
||||
src++;
|
||||
(*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 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);
|
||||
DWORD error = dstRate / 2;
|
||||
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, 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)--;
|
||||
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 cvtSM1616C(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;
|
||||
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst);
|
||||
DWORD error = dstRate / 2;
|
||||
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, 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)--;
|
||||
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 cvtMS1616C(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;
|
||||
short v;
|
||||
TRACE("(%p, %p, %p, %p, %p)\n", apd, src, nsrc, dst, ndst);
|
||||
DWORD error = dstRate / 2;
|
||||
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, 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)--;
|
||||
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 cvtMM1616C(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);
|
||||
DWORD error = dstRate / 2;
|
||||
TRACE("(%ld, %p, %p, %ld, %p, %p)\n", srcRate, src, nsrc, dstRate, 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)--;
|
||||
while ((*ndst)--) {
|
||||
W16(dst, C816(*src)); dst += 2;
|
||||
error = error + srcRate;
|
||||
while (error > dstRate) {
|
||||
src++;
|
||||
(*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 cvtSS168C(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 + 2));
|
||||
error = error + srcRate;
|
||||
while (error > dstRate) {
|
||||
src += 4;
|
||||
(*nsrc)--;
|
||||
if (*nsrc==0)
|
||||
return;
|
||||
error = error - dstRate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cvtSM168C(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(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(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));
|
||||
error = error + srcRate;
|
||||
while (error > dstRate) {
|
||||
src += 2;
|
||||
(*nsrc)--;
|
||||
if (*nsrc == 0)
|
||||
return;
|
||||
error = error - dstRate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cvtSS1616C(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)--) {
|
||||
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(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)--) {
|
||||
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(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)--) {
|
||||
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(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)--) {
|
||||
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])(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)) {
|
||||
|
@ -977,26 +871,6 @@ static LRESULT PCM_FormatSuggest(PACMDRVFORMATSUGGEST adfs)
|
|||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* 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 {
|
||||
|
|
Loading…
Reference in New Issue