From: <m97...@us...> - 2010-03-23 19:05:03
|
Revision: 11357 http://openmsx.svn.sourceforge.net/openmsx/?rev=11357&view=rev Author: m9710797 Date: 2010-03-23 19:03:41 +0000 (Tue, 23 Mar 2010) Log Message: ----------- Also implement upsampling in the fast resampler. Before this patch, the ResampleLQ class could only convert a audio stream from a high to a lower sample rate (=down-sampling). All MSX device have a native sample rate bigger than 48kHz. Except for one: the cassette player. So using the cassette player in combination with the fast resampler resulted in a crash. Fixed by teaching the ResampleLQ how to do up-sampling (low quality algorithm). Modified Paths: -------------- openmsx/trunk/src/sound/Resample.cc openmsx/trunk/src/sound/ResampleLQ.cc openmsx/trunk/src/sound/ResampleLQ.hh Modified: openmsx/trunk/src/sound/Resample.cc =================================================================== --- openmsx/trunk/src/sound/Resample.cc 2010-03-23 18:33:36 UTC (rev 11356) +++ openmsx/trunk/src/sound/Resample.cc 2010-03-23 19:03:41 UTC (rev 11357) @@ -56,9 +56,9 @@ break; case RESAMPLE_LQ: if (channels == 1) { - algo.reset(new ResampleLQ<1>(*this, ratio)); + algo = ResampleLQ<1>::create(*this, ratio); } else { - algo.reset(new ResampleLQ<2>(*this, ratio)); + algo = ResampleLQ<2>::create(*this, ratio); } break; case RESAMPLE_BLIP: Modified: openmsx/trunk/src/sound/ResampleLQ.cc =================================================================== --- openmsx/trunk/src/sound/ResampleLQ.cc 2010-03-23 18:33:36 UTC (rev 11356) +++ openmsx/trunk/src/sound/ResampleLQ.cc 2010-03-23 19:03:41 UTC (rev 11357) @@ -11,18 +11,32 @@ static const int BUFSIZE = 16384; ALIGNED(static int bufferInt[BUFSIZE + 4], 16); +//// + +template<unsigned CHANNELS> +std::auto_ptr<ResampleLQ<CHANNELS> > ResampleLQ<CHANNELS>::create( + Resample& input, double ratio) +{ + std::auto_ptr<ResampleLQ<CHANNELS> > result; + if (ratio < 1.0) { + result.reset(new ResampleLQUp <CHANNELS>(input, ratio)); + } else { + result.reset(new ResampleLQDown<CHANNELS>(input, ratio)); + } + return result; +} + template <unsigned CHANNELS> ResampleLQ<CHANNELS>::ResampleLQ(Resample& input_, double ratio) : input(input_), pos(0), step(ratio) { - assert(step >= Pos(1)); // can only do downsampling for (unsigned j = 0; j < CHANNELS; ++j) { lastInput[j] = 0; } } template <unsigned CHANNELS> -bool ResampleLQ<CHANNELS>::generateOutput(int* __restrict dataOut, unsigned num) +bool ResampleLQ<CHANNELS>::fetchData(unsigned num) { Pos end = pos + step * num; int numInput = end.toInt(); @@ -44,6 +58,54 @@ buffer[j] = lastInput[j]; lastInput[j] = buffer[numInput * CHANNELS + j]; } + return true; +} + +//// + +template <unsigned CHANNELS> +ResampleLQUp<CHANNELS>::ResampleLQUp(Resample& input, double ratio) + : ResampleLQ<CHANNELS>(input, ratio) +{ + assert(ratio < 1.0); // only upsampling +} + +template <unsigned CHANNELS> +bool ResampleLQUp<CHANNELS>::generateOutput(int* __restrict dataOut, unsigned num) +{ + if (!this->fetchData(num)) return false; + + // this is currently only used to upsample cassette player sound, + // sound quality is not so important here, so use 0-th order + // interpolation (instead of 1st-order). + int* buffer = &bufferInt[4 - CHANNELS]; + for (unsigned i = 0; i < num; ++i) { + int p0 = this->pos.toInt(); + for (unsigned j = 0; j < CHANNELS; ++j) { + dataOut[i * CHANNELS + j] = buffer[p0 * CHANNELS + j]; + } + this->pos += this->step; + } + + this->pos = this->pos.fract(); + return true; +} + +//// + +template <unsigned CHANNELS> +ResampleLQDown<CHANNELS>::ResampleLQDown(Resample& input, double ratio) + : ResampleLQ<CHANNELS>(input, ratio) +{ + assert(ratio > 1.0); // can only do downsampling +} + +template <unsigned CHANNELS> +bool ResampleLQDown<CHANNELS>::generateOutput(int* __restrict dataOut, unsigned num) +{ + if (!this->fetchData(num)) return false; + + int* buffer = &bufferInt[4 - CHANNELS]; #ifdef __arm__ if (CHANNELS == 1) { unsigned dummy; @@ -132,35 +194,36 @@ "subs %[n],%[n],#4\n\t" "bgt 0b\n\t" - : [p] "=r" (pos) + : [p] "=r" (this->pos) , [t] "=&r" (dummy) - : "[p]" (pos) + : "[p]" (this->pos) , [buf] "r" (buffer) , [out] "r" (dataOut) - , [s] "r" (step) + , [s] "r" (this->step) , [n] "r" (num) : "r9" ); } else { #endif for (unsigned i = 0; i < num; ++i) { - int p = pos.toInt(); - Pos fract = pos.fract(); + int p = this->pos.toInt(); + typename ResampleLQ<CHANNELS>::Pos fract = this->pos.fract(); for (unsigned j = 0; j < CHANNELS; ++j) { int s0 = buffer[(p + 0) * CHANNELS + j]; int s1 = buffer[(p + 1) * CHANNELS + j]; int out = s0 + (fract * (s1 - s0)).toInt(); dataOut[i * CHANNELS + j] = out; } - pos += step; + this->pos += this->step; } #ifdef __arm__ } #endif - pos = pos.fract(); + this->pos = this->pos.fract(); return true; } + // Force template instantiation. template class ResampleLQ<1>; template class ResampleLQ<2>; Modified: openmsx/trunk/src/sound/ResampleLQ.hh =================================================================== --- openmsx/trunk/src/sound/ResampleLQ.hh 2010-03-23 18:33:36 UTC (rev 11356) +++ openmsx/trunk/src/sound/ResampleLQ.hh 2010-03-23 19:03:41 UTC (rev 11357) @@ -5,19 +5,23 @@ #include "ResampleAlgo.hh" #include "FixedPoint.hh" +#include <memory> namespace openmsx { class Resample; template <unsigned CHANNELS> -class ResampleLQ : public ResampleAlgo +class ResampleLQ: public ResampleAlgo { public: + static std::auto_ptr<ResampleLQ<CHANNELS> > create( + Resample& input, double ratio); + +protected: ResampleLQ(Resample& input, double ratio); - virtual bool generateOutput(int* dataOut, unsigned num); + bool fetchData(unsigned num); -private: Resample& input; typedef FixedPoint<16> Pos; Pos pos; @@ -25,6 +29,24 @@ int lastInput[CHANNELS]; }; +template <unsigned CHANNELS> +class ResampleLQDown : public ResampleLQ<CHANNELS> +{ +private: + ResampleLQDown(Resample& input, double ratio); + virtual bool generateOutput(int* dataOut, unsigned num); + friend class ResampleLQ<CHANNELS>; +}; + +template <unsigned CHANNELS> +class ResampleLQUp : public ResampleLQ<CHANNELS> +{ +private: + ResampleLQUp(Resample& input, double ratio); + virtual bool generateOutput(int* dataOut, unsigned num); + friend class ResampleLQ<CHANNELS>; +}; + } // namespace openmsx #endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |