diff options
author | Max Horn | 2007-06-16 17:09:54 +0000 |
---|---|---|
committer | Max Horn | 2007-06-16 17:09:54 +0000 |
commit | e44b518c23a30cd9800bae527fd2fd192f9ec9a2 (patch) | |
tree | 8ed615ba6f86ced5362629c47dd23e4ed838670d | |
parent | 2f127122b3405aa70df2c149dd0c40fe231de979 (diff) | |
download | scummvm-rg350-e44b518c23a30cd9800bae527fd2fd192f9ec9a2.tar.gz scummvm-rg350-e44b518c23a30cd9800bae527fd2fd192f9ec9a2.tar.bz2 scummvm-rg350-e44b518c23a30cd9800bae527fd2fd192f9ec9a2.zip |
Patch #1717419: Optimisation for sound rate conversion code
svn-id: r27470
-rw-r--r-- | sound/rate.cpp | 186 |
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) |