aboutsummaryrefslogtreecommitdiff
path: root/sound/rate.cpp
diff options
context:
space:
mode:
authorMax Horn2007-06-16 17:09:54 +0000
committerMax Horn2007-06-16 17:09:54 +0000
commite44b518c23a30cd9800bae527fd2fd192f9ec9a2 (patch)
tree8ed615ba6f86ced5362629c47dd23e4ed838670d /sound/rate.cpp
parent2f127122b3405aa70df2c149dd0c40fe231de979 (diff)
downloadscummvm-rg350-e44b518c23a30cd9800bae527fd2fd192f9ec9a2.tar.gz
scummvm-rg350-e44b518c23a30cd9800bae527fd2fd192f9ec9a2.tar.bz2
scummvm-rg350-e44b518c23a30cd9800bae527fd2fd192f9ec9a2.zip
Patch #1717419: Optimisation for sound rate conversion code
svn-id: r27470
Diffstat (limited to 'sound/rate.cpp')
-rw-r--r--sound/rate.cpp186
1 files changed, 140 insertions, 46 deletions
diff --git a/sound/rate.cpp b/sound/rate.cpp
index 7d1a7b51cf..54efd07998 100644
--- a/sound/rate.cpp
+++ b/sound/rate.cpp
@@ -55,6 +55,105 @@ namespace Audio {
/**
+ * 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,13 +172,10 @@ protected:
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;
-
- /** position in the input stream (integer) */
- unsigned long ipos;
+ long opos_inc, opos_inc_frac;
/** last sample(s) in the input stream (left/right channel) */
st_sample_t ilast[2];
@@ -119,8 +215,6 @@ LinearRateConverter<stereo, reverseStereo>::LinearRateConverter(st_rate_t inrate
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 @@ int LinearRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_samp
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,25 +244,25 @@ int LinearRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_samp
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));
-
- if (stereo) {
- // interpolate
- out[reverseStereo ? 0 : 1] = (st_sample_t)(ilast[1] + (((icur[1] - ilast[1]) * 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]);
// output left channel
clampedAdd(*obuf++, (out[0] * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
@@ -180,7 +271,7 @@ int LinearRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_samp
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 @@ int LinearRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_samp
goto the_end;
}
}
-
the_end:
return (ST_SUCCESS);
}
@@ -232,25 +322,20 @@ public:
// 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 @@ public:
*/
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)