msacm: pcm compatibility patch

Robert Reif reif at earthlink.net
Fri Dec 10 17:53:52 CST 2004


Makes the PCM conversion routines of msacm produce identical results to 
the native dll.
Allow any PCM to PCM conversion, not just advertised ones.

The algorithms used by Microsoft in this dll are very crude and
produce an output of much poorer quality than what is currently
in wine.  This is unfortunate but unavoidable if we are to be compatible.

I have a test program that was used to verify compatibility and can
make it available by request.  I hope to integrate some of it into
the regression tests someday.

-------------- next part --------------
Index: dlls/msacm/pcmconverter.c
===================================================================
RCS file: /home/wine/wine/dlls/msacm/pcmconverter.c,v
retrieving revision 1.21
diff -u -r1.21 pcmconverter.c
--- dlls/msacm/pcmconverter.c	8 Sep 2004 01:37:24 -0000	1.21
+++ dlls/msacm/pcmconverter.c	11 Dec 2004 00:26:41 -0000
@@ -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 @@
 }
 
 #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 @@
     /* 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 @@
  *	  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 inline short C816(unsigned char b)
 {
-    return (short)((b+(b << 8))-32768);
+    return (b - 128) << 8;
 }
 
 /***********************************************************************
@@ -194,22 +177,40 @@
  *           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 @@
     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 @@
     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 @@
  * <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)--;
+    while ((*ndst)--) {
+        *dst++ = *src;
+        *dst++ = *src;
+        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 cvtSM88C(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);
+    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->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)--;
+    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 cvtMM816C(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 */
-	    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);
-        }
-	apd->dstPos += apd->dstIncr;
-	(*ndst)--;
-    }
-}
-
-static	void cvtSM168C(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(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 cvtMS168C(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->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)--;
-    }
-}
-
-
-static	void cvtMM168C(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->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)--;
-    }
-}
-
-static	void cvtSS1616C(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 */
-	    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,
-			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)--) {
+        *dst++ = *src;
+        *dst++ = *src;
+        error = error + srcRate;
+        while (error > dstRate) {
+            src++;
+            (*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 cvtMM88C(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)--) {
+        *dst++ = *src;
+        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 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].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, 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 (*PCM_ConvertChangeRate[16])(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)
+{
+    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 cvtMS816C(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, 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 cvtMM816C(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, C816(*src)); dst += 2;
+        error = error + srcRate;
+        while (error > dstRate) {
+            src++;
+            (*nsrc)--;
+            if (*nsrc==0)
+                return;
+            error = error - dstRate;
+        }
+    }
+}
+
+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 @@
 	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 @@
 }
 
 /***********************************************************************
- *           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 @@
 
     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 @@
 	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 @@
      */
     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 {


More information about the wine-patches mailing list