Index: sound/rate.cpp =================================================================== --- sound/rate.cpp (revision 27465) +++ sound/rate.cpp (working copy) @@ -55,6 +55,106 @@ /** + * Audio rate converter based on simple resampling. Used when no + * interpolation is required. + * + * Limited to sampling frequency <= 65535 Hz. + */ +template +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 +SimpleRateConverter::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 +int SimpleRateConverter::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 +173,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 +216,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 +231,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 +245,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 +272,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 +281,6 @@ goto the_end; } } - the_end: return (ST_SUCCESS); } @@ -232,22 +323,17 @@ // 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--; - } + while (len > 0) { + 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); + len -= (stereo ? 2 : 1); } return (ST_SUCCESS); } @@ -265,14 +351,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(inrate, outrate); - else - return new LinearRateConverter(inrate, outrate); - } else - return new LinearRateConverter(inrate, outrate); - //return new ResampleRateConverter(inrate, outrate, 1); + if ((inrate % outrate) == 0) { + if (stereo) { + if (reverseStereo) + return new SimpleRateConverter(inrate, outrate); + else + return new SimpleRateConverter(inrate, outrate); + } else + return new SimpleRateConverter(inrate, outrate); + } else { + if (stereo) { + if (reverseStereo) + return new LinearRateConverter(inrate, outrate); + else + return new LinearRateConverter(inrate, outrate); + } else + return new LinearRateConverter(inrate, outrate); + } } else { if (stereo) { if (reverseStereo)