diff options
Diffstat (limited to 'sound/rate.cpp')
-rw-r--r-- | sound/rate.cpp | 98 |
1 files changed, 37 insertions, 61 deletions
diff --git a/sound/rate.cpp b/sound/rate.cpp index 6a51f3d5d5..6e8e83f9a6 100644 --- a/sound/rate.cpp +++ b/sound/rate.cpp @@ -35,15 +35,11 @@ #include "sound/audiostream.h" #include "sound/rate.h" #include "sound/mixer.h" +#include "common/frac.h" #include "common/util.h" namespace Audio { -/** - * The precision of the fractional computations used by the rate converter. - * Normally you should never have to modify this value. - */ -#define FRAC_BITS 16 /** * The size of the intermediate input cache. Bigger values may increase @@ -88,12 +84,8 @@ public: */ 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"); + error("Input rate must be a multiple of output rate to use rate effect"); } if (inrate >= 65536 || outrate >= 65536) { @@ -174,10 +166,10 @@ protected: int inLen; /** fractional position of the output stream in input stream unit */ - long opos, opos_frac; + frac_t opos; /** fractional position increment in the output stream */ - long opos_inc, opos_inc_frac; + frac_t opos_inc; /** last sample(s) in the input stream (left/right channel) */ st_sample_t ilast0, ilast1; @@ -198,24 +190,18 @@ public: */ template<bool stereo, bool reverseStereo> LinearRateConverter<stereo, reverseStereo>::LinearRateConverter(st_rate_t inrate, st_rate_t outrate) { - unsigned long incr; - - if (inrate == outrate) { - error("Input and Output rates must be different to use rate effect"); - } - if (inrate >= 65536 || outrate >= 65536) { error("rate effect can only handle rates < 65536"); } - opos_frac = 0; - opos = 1; - - /* increment */ - incr = (inrate << FRAC_BITS) / outrate; + opos = FRAC_ONE; - opos_inc_frac = incr & ((1UL << FRAC_BITS) - 1); - opos_inc = incr >> FRAC_BITS; + // Compute the linear interpolation increment. + // This will overflow if inrate >= 2^16, and underflow if outrate >= 2^16. + // Also, if the quotient of the two rate becomes too small / too big, that + // would cause problems, but since we rarely scale from 1 to 65536 Hz or vice + // versa, I think we can live with that limiation ;-). + opos_inc = (inrate << FRAC_BITS) / outrate; ilast0 = ilast1 = 0; icur0 = icur1 = 0; @@ -236,8 +222,8 @@ int LinearRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_samp while (obuf < oend) { - // read enough input samples so that opos <= 0 - while (0 <= opos) { + // read enough input samples so that opos < 0 + while (FRAC_ONE <= opos) { // Check if we have to refill the buffer if (inLen == 0) { inPtr = inBuf; @@ -252,17 +238,17 @@ int LinearRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_samp ilast1 = icur1; icur1 = *inPtr++; } - opos--; + opos -= FRAC_ONE; } // Loop as long as the outpos trails behind, and as long as there is // still space in the output buffer. - while (0 > opos && obuf < oend) { + while (opos < FRAC_ONE && obuf < oend) { // interpolate st_sample_t out0, out1; - out0 = (st_sample_t)(ilast0 + (((icur0 - ilast0) * opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS)); + out0 = (st_sample_t)(ilast0 + (((icur0 - ilast0) * opos + FRAC_HALF) >> FRAC_BITS)); out1 = (stereo ? - (st_sample_t)(ilast1 + (((icur1 - ilast1) * opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS)) : + (st_sample_t)(ilast1 + (((icur1 - ilast1) * opos + FRAC_HALF) >> FRAC_BITS)) : out0); // output left channel @@ -274,9 +260,7 @@ int LinearRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_samp obuf += 2; // Increment output position - long tmp = opos_frac + opos_inc_frac; - opos += opos_inc + (tmp >> FRAC_BITS); - opos_frac = tmp & ((1UL << FRAC_BITS) - 1); + opos += opos_inc; } } return ST_SUCCESS; @@ -344,38 +328,30 @@ public: #pragma mark - - -/** - * Create and return a RateConverter object for the specified input and output rates. - */ -RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo, bool reverseStereo) { +template<bool stereo, bool reverseStereo> +RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate) { if (inrate != outrate) { 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); + return new SimpleRateConverter<stereo, reverseStereo>(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); - } + return new LinearRateConverter<stereo, reverseStereo>(inrate, outrate); + } } else { - if (stereo) { - if (reverseStereo) - return new CopyRateConverter<true, true>(); - else - return new CopyRateConverter<true, false>(); - } else - return new CopyRateConverter<false, false>(); + return new CopyRateConverter<stereo, reverseStereo>(); } } +/** + * Create and return a RateConverter object for the specified input and output rates. + */ +RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo, bool reverseStereo) { + if (stereo) { + if (reverseStereo) + return makeRateConverter<true, true>(inrate, outrate); + else + return makeRateConverter<true, false>(inrate, outrate); + } else + return makeRateConverter<false, false>(inrate, outrate); +} + } // End of namespace Audio |