[Scummvm-cvs-logs] SF.net SVN: scummvm: [27470] scummvm/trunk/sound/rate.cpp

fingolfin at users.sourceforge.net fingolfin at users.sourceforge.net
Sat Jun 16 19:09:55 CEST 2007


Revision: 27470
          http://scummvm.svn.sourceforge.net/scummvm/?rev=27470&view=rev
Author:   fingolfin
Date:     2007-06-16 10:09:54 -0700 (Sat, 16 Jun 2007)

Log Message:
-----------
Patch #1717419: Optimisation for sound rate conversion code

Modified Paths:
--------------
    scummvm/trunk/sound/rate.cpp

Modified: scummvm/trunk/sound/rate.cpp
===================================================================
--- scummvm/trunk/sound/rate.cpp	2007-06-16 16:54:28 UTC (rev 27469)
+++ scummvm/trunk/sound/rate.cpp	2007-06-16 17:09:54 UTC (rev 27470)
@@ -55,6 +55,105 @@
 
 
 /**
+ * Audio rate converter based on simple resampling. Used when no
+ * interpolation is required.
+ *
+ * Limited to sampling frequency <= 65535 Hz.
+ */
+template<bool stereo, bool reverseStereo>
+class SimpleRateConverter : public RateConverter {
+protected:
+	st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
+	const st_sample_t *inPtr;
+	int inLen;
+
+	/** position of how far output is ahead of input */
+	/** Holds what would have been opos-ipos */
+	long opos;
+
+	/** fractional position increment in the output stream */
+	long opos_inc;
+
+public:
+	SimpleRateConverter(st_rate_t inrate, st_rate_t outrate);
+	int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
+	int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
+		return (ST_SUCCESS);
+	}
+};
+
+
+/*
+ * Prepare processing.
+ */
+template<bool stereo, bool reverseStereo>
+SimpleRateConverter<stereo, reverseStereo>::SimpleRateConverter(st_rate_t inrate, st_rate_t outrate) {
+	if (inrate == outrate) {
+		error("Input and Output rates must be different to use rate effect");
+	}
+
+	if ((inrate % outrate) != 0) {
+		error("Input rate must be a multiple of Output rate to use rate effect");
+	}
+
+	if (inrate >= 65536 || outrate >= 65536) {
+		error("rate effect can only handle rates < 65536");
+	}
+
+	opos = 1;
+
+	/* increment */
+	opos_inc = inrate / outrate;
+
+	inLen = 0;
+}
+
+/*
+ * Processed signed long samples from ibuf to obuf.
+ * Return number of samples processed.
+ */
+template<bool stereo, bool reverseStereo>
+int SimpleRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
+	st_sample_t *ostart, *oend;
+	st_sample_t out[2];
+
+	ostart = obuf;
+	oend = obuf + osamp * 2;
+
+	while (obuf < oend) {
+
+		// read enough input samples so that opos >= 0
+		do {
+			// Check if we have to refill the buffer
+			if (inLen == 0) {
+				inPtr = inBuf;
+				inLen = input.readBuffer(inBuf, ARRAYSIZE(inBuf));
+				if (inLen <= 0)
+					goto the_end;
+			}
+			inLen -= (stereo ? 2 : 1);
+			opos--;
+			if (opos >= 0) {
+				inPtr += (stereo ? 2 : 1);
+			}
+		} while (opos >= 0);
+		out[reverseStereo    ] = *inPtr++;
+		out[reverseStereo ^ 1] = (stereo ? *inPtr++ : out[reverseStereo]);
+
+		// Increment output position
+		opos += opos_inc;
+
+		// output left channel
+		clampedAdd(*obuf++, (out[0] * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
+
+		// output right channel
+		clampedAdd(*obuf++, (out[1] * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
+	}
+the_end:
+	return (ST_SUCCESS);
+}
+
+/**
  * Audio rate converter based on simple linear Interpolation.
  *
  * The use of fractional increment allows us to use no buffer. It
@@ -73,14 +172,11 @@
 	int inLen;
 
 	/** fractional position of the output stream in input stream unit */
-	unsigned long opos, opos_frac;
+	long opos, opos_frac;
 
 	/** fractional position increment in the output stream */
-	unsigned long opos_inc, opos_inc_frac;
+	long opos_inc, opos_inc_frac;
 
-	/** position in the input stream (integer) */
-	unsigned long ipos;
-
 	/** last sample(s) in the input stream (left/right channel) */
 	st_sample_t ilast[2];
 	/** current sample(s) in the input stream (left/right channel) */
@@ -119,8 +215,6 @@
 	opos_inc_frac = incr & ((1UL << FRAC_BITS) - 1);
 	opos_inc = incr >> FRAC_BITS;
 
-	ipos = 0;
-
 	ilast[0] = ilast[1] = 0;
 	icur[0] = icur[1] = 0;
 
@@ -136,16 +230,13 @@
 	st_sample_t *ostart, *oend;
 	st_sample_t out[2];
 
-	const int numChannels = stereo ? 2 : 1;
-	int i;
-
 	ostart = obuf;
 	oend = obuf + osamp * 2;
 
 	while (obuf < oend) {
 
-		// read enough input samples so that ipos > opos
-		while (ipos <= opos) {
+		// read enough input samples so that opos <= 0
+		while (0 <= opos) {
 			// Check if we have to refill the buffer
 			if (inLen == 0) {
 				inPtr = inBuf;
@@ -153,26 +244,26 @@
 				if (inLen <= 0)
 					goto the_end;
 			}
-			for (i = 0; i < numChannels; i++) {
-				ilast[i] = icur[i];
-				icur[i] = *inPtr++;
-				inLen--;
+			inLen -= (stereo ? 2 : 1);
+			ilast[0] = icur[0];
+			icur[0] = *inPtr++;
+			if (stereo) {
+				ilast[1] = icur[1];
+				icur[1] = *inPtr++;
 			}
-			ipos++;
+			opos--;
 		}
 
 		// Loop as long as the outpos trails behind, and as long as there is
 		// still space in the output buffer.
-		while (ipos > opos) {
+		while (0 > opos) {
 
 			// interpolate
-			out[0] = out[1] = (st_sample_t)(ilast[0] + (((icur[0] - ilast[0]) * opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS));
+			out[reverseStereo    ] =  (st_sample_t)(ilast[0] + (((icur[0] - ilast[0]) * opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS));
+			out[reverseStereo ^ 1] = (stereo ?
+						  (st_sample_t)(ilast[1] + (((icur[1] - ilast[1]) * opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS)) :
+						  out[reverseStereo]);
 
-			if (stereo) {
-				// interpolate
-				out[reverseStereo ? 0 : 1] = (st_sample_t)(ilast[1] + (((icur[1] - ilast[1]) * opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS));
-			}
-
 			// output left channel
 			clampedAdd(*obuf++, (out[0] * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
 
@@ -180,7 +271,7 @@
 			clampedAdd(*obuf++, (out[1] * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
 
 			// Increment output position
-			unsigned long tmp = opos_frac + opos_inc_frac;
+			long tmp = opos_frac + opos_inc_frac;
 			opos += opos_inc + (tmp >> FRAC_BITS);
 			opos_frac = tmp & ((1UL << FRAC_BITS) - 1);
 
@@ -189,7 +280,6 @@
 				goto the_end;
 		}
 	}
-
 the_end:
 	return (ST_SUCCESS);
 }
@@ -232,25 +322,20 @@
 
 		// Mix the data into the output buffer
 		ptr = _buffer;
-		while (len-- > 0) {
-			st_sample_t tmp0, tmp1;
-			tmp0 = tmp1 = *ptr++;
-			if (stereo) {
-				if (reverseStereo)
-					tmp0 = *ptr++;
-				else
-					tmp1 = *ptr++;
-				len--;
-			}
+		for (; len > 0; len -= (stereo ? 2 : 1)) {
+			st_sample_t tmp[2];
+			tmp[reverseStereo    ] = *ptr++;
+			tmp[reverseStereo ^ 1] = (stereo ? *ptr++ : tmp[reverseStereo]);
 
 			// output left channel
-			clampedAdd(*obuf++, (tmp0 * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
+			clampedAdd(*obuf++, (tmp[0] * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
 
 			// output right channel
-			clampedAdd(*obuf++, (tmp1 * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
+			clampedAdd(*obuf++, (tmp[1] * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
 		}
 		return (ST_SUCCESS);
 	}
+
 	virtual int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
 		return (ST_SUCCESS);
 	}
@@ -265,14 +350,23 @@
  */
 RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo, bool reverseStereo) {
 	if (inrate != outrate) {
-		if (stereo) {
-			if (reverseStereo)
-				return new LinearRateConverter<true, true>(inrate, outrate);
-			else
-				return new LinearRateConverter<true, false>(inrate, outrate);
-		} else
-			return new LinearRateConverter<false, false>(inrate, outrate);
-		//return new ResampleRateConverter(inrate, outrate, 1);
+		if ((inrate % outrate) == 0) {
+			if (stereo) {
+				if (reverseStereo)
+					return new SimpleRateConverter<true, true>(inrate, outrate);
+				else
+					return new SimpleRateConverter<true, false>(inrate, outrate);
+			} else
+				return new SimpleRateConverter<false, false>(inrate, outrate);
+		} else {
+			if (stereo) {
+				if (reverseStereo)
+					return new LinearRateConverter<true, true>(inrate, outrate);
+				else
+					return new LinearRateConverter<true, false>(inrate, outrate);
+			} else
+				return new LinearRateConverter<false, false>(inrate, outrate);
+		 }
 	} else {
 		if (stereo) {
 			if (reverseStereo)


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list