common/chainresampler: hide more implementation

This commit is contained in:
sinamas 2013-04-28 15:17:48 +02:00
parent 9bd975961a
commit 694c76c886
3 changed files with 78 additions and 104 deletions

View File

@ -17,26 +17,36 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/ ***************************************************************************/
#include "chainresampler.h" #include "chainresampler.h"
#include "defined_ptr.h" #include <cassert>
#include <algorithm> #include <cmath>
float ChainResampler::get2ChainMidRatio(float ratio, float finalRollOffLen, float midRollOffStartPlusEnd) { static float get1ChainCost(float ratio, float finalRollOffLen) {
return ratio / finalRollOffLen;
}
static float get2ChainMidRatio(float ratio, float finalRollOffLen, float midRollOffStartPlusEnd) {
return 0.5f * ( std::sqrt(ratio * midRollOffStartPlusEnd * finalRollOffLen) return 0.5f * ( std::sqrt(ratio * midRollOffStartPlusEnd * finalRollOffLen)
+ midRollOffStartPlusEnd); + midRollOffStartPlusEnd);
} }
float ChainResampler::get2ChainCost(float ratio, float finalRollOffLen, float midRatio, static float get2ChainCost(float ratio, float finalRollOffLen, float midRatio,
float midRollOffStartPlusEnd) float midRollOffStartPlusEnd)
{ {
float midRollOffLen = midRatio * 2 - midRollOffStartPlusEnd; float midRollOffLen = midRatio * 2 - midRollOffStartPlusEnd;
return midRatio * ratio / midRollOffLen return midRatio * ratio / midRollOffLen
+ get1ChainCost(midRatio, finalRollOffLen); + get1ChainCost(midRatio, finalRollOffLen);
} }
float ChainResampler::get3ChainRatio1(float ratio1, float const finalRollOffLen, float const ratio, static float get3ChainRatio2(float ratio1,
float const midRollOffStartPlusEnd) float finalRollOffLen,
float midRollOffStartPlusEnd) {
return get2ChainMidRatio(ratio1, finalRollOffLen, midRollOffStartPlusEnd);
}
static float get3ChainRatio1(float ratio1, float const finalRollOffLen, float const ratio,
float const midRollOffStartPlusEnd)
{ {
for (unsigned n = 8; n--;) { for (int n = 8; n--;) {
float ratio2 = get3ChainRatio2(ratio1, finalRollOffLen, midRollOffStartPlusEnd); float ratio2 = get3ChainRatio2(ratio1, finalRollOffLen, midRollOffStartPlusEnd);
ratio1 = ( std::sqrt(ratio * midRollOffStartPlusEnd * (2 - midRollOffStartPlusEnd / ratio2)) ratio1 = ( std::sqrt(ratio * midRollOffStartPlusEnd * (2 - midRollOffStartPlusEnd / ratio2))
+ midRollOffStartPlusEnd) * 0.5f; + midRollOffStartPlusEnd) * 0.5f;
@ -45,16 +55,20 @@ float ChainResampler::get3ChainRatio1(float ratio1, float const finalRollOffLen,
return ratio1; return ratio1;
} }
float ChainResampler::get3ChainCost(float ratio, float finalRollOffLen, static float get3ChainCost(float ratio, float finalRollOffLen,
float ratio1, float ratio2, float midRollOffStartPlusEnd) float ratio1, float ratio2, float midRollOffStartPlusEnd)
{ {
float firstRollOffLen = ratio1 * 2 - midRollOffStartPlusEnd; float firstRollOffLen = ratio1 * 2 - midRollOffStartPlusEnd;
return ratio1 * ratio / firstRollOffLen return ratio1 * ratio / firstRollOffLen
+ get2ChainCost(ratio1, finalRollOffLen, ratio2, midRollOffStartPlusEnd); + get2ChainCost(ratio1, finalRollOffLen, ratio2, midRollOffStartPlusEnd);
} }
ChainResampler::ChainResampler() ChainResampler::ChainResampler(long inRate, long outRate, std::size_t periodSize)
: bigSinc_(0), buffer2_(0), periodSize_(0) : Resampler(inRate, outRate)
, bigSinc_(0)
, buffer2_(0)
, periodSize_(periodSize)
, maxOut_(0)
{ {
} }
@ -121,26 +135,25 @@ void ChainResampler::downinitAddSincResamplers(double ratio,
list_.push_back(bigSinc_); list_.push_back(bigSinc_);
} }
std::size_t ChainResampler::reallocateBuffer() { void ChainResampler::reallocateBuffer() {
std::size_t bufSz[2] = { 0, 0 }; std::size_t bufSize[2] = { 0, 0 };
std::size_t inSz = periodSize_; std::size_t inSize = periodSize_;
int i = -1; int i = -1;
for (List::iterator it = list_.begin(); it != list_.end(); ++it) { for (List::iterator it = list_.begin(); it != list_.end(); ++it) {
inSz = (inSz * (*it)->mul() - 1) / (*it)->div() + 1; inSize = (inSize * (*it)->mul() - 1) / (*it)->div() + 1;
++i; ++i;
if (inSz > bufSz[i & 1]) if (inSize > bufSize[i & 1])
bufSz[i & 1] = inSz; bufSize[i & 1] = inSize;
} }
if (inSz >= bufSz[i & 1]) if (inSize >= bufSize[i & 1])
bufSz[i & 1] = 0; bufSize[i & 1] = 0;
if (buffer_.size() < (bufSz[0] + bufSz[1]) * channels) if (buffer_.size() < (bufSize[0] + bufSize[1]) * channels)
buffer_.reset((bufSz[0] + bufSz[1]) * channels); buffer_.reset((bufSize[0] + bufSize[1]) * channels);
buffer2_ = bufSz[1] ? buffer_ + bufSz[0] * channels : 0; buffer2_ = bufSize[1] ? buffer_ + bufSize[0] * channels : 0;
maxOut_ = inSize;
return (maxOut_ = inSz);
} }
void ChainResampler::adjustRate(long const inRate, long const outRate) { void ChainResampler::adjustRate(long const inRate, long const outRate) {
@ -180,11 +193,6 @@ std::size_t ChainResampler::resample(short *const out, short const *const in, st
return inlen; return inlen;
} }
void ChainResampler::uninit() { ChainResampler::~ChainResampler() {
buffer2_ = 0;
buffer_.reset();
periodSize_ = 0;
bigSinc_ = 0;
std::for_each(list_.begin(), list_.end(), defined_delete<SubResampler>); std::for_each(list_.begin(), list_.end(), defined_delete<SubResampler>);
list_.clear();
} }

View File

@ -22,31 +22,28 @@
#include "../resampler.h" #include "../resampler.h"
#include "../resamplerinfo.h" #include "../resamplerinfo.h"
#include "array.h" #include "array.h"
#include "subresampler.h" #include "transfer_ptr.h"
#include "upsampler.h" #include "upsampler.h"
#include <cassert> #include <algorithm>
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <list> #include <list>
class SubResampler;
class ChainResampler : public Resampler { class ChainResampler : public Resampler {
public: public:
enum { channels = ResamplerInfo::channels }; enum { channels = ResamplerInfo::channels };
ChainResampler(); template<template<unsigned, unsigned> class Sinc>
virtual ~ChainResampler() { uninit(); } static Resampler * create(long inRate, long outRate, std::size_t periodSize);
virtual ~ChainResampler();
virtual void adjustRate(long inRate, long outRate); virtual void adjustRate(long inRate, long outRate);
virtual void exactRatio(unsigned long &mul, unsigned long &div) const; virtual void exactRatio(unsigned long &mul, unsigned long &div) const;
virtual std::size_t maxOut(std::size_t /*inlen*/) const { return maxOut_; } virtual std::size_t maxOut(std::size_t /*inlen*/) const { return maxOut_; }
virtual std::size_t resample(short *out, short const *in, std::size_t inlen); virtual std::size_t resample(short *out, short const *in, std::size_t inlen);
template<template<unsigned,unsigned> class Sinc>
std::size_t init(long inRate, long outRate, std::size_t periodSize);
void uninit();
private: private:
typedef std::list<SubResampler*> List; typedef std::list<SubResampler *> List;
typedef SubResampler * (*CreateSinc)(unsigned div, float rollOffStart, typedef SubResampler * (*CreateSinc)(unsigned div, float rollOffStart,
float rollOffWidth, double gain); float rollOffWidth, double gain);
@ -54,32 +51,14 @@ private:
SubResampler *bigSinc_; SubResampler *bigSinc_;
Array<short> buffer_; Array<short> buffer_;
short *buffer2_; short *buffer2_;
std::size_t periodSize_; std::size_t const periodSize_;
std::size_t maxOut_; std::size_t maxOut_;
static float get1ChainCost(float ratio, float finalRollOffLen) { ChainResampler(long inRate, long outRate, std::size_t periodSize);
return ratio / finalRollOffLen;
}
static float get2ChainMidRatio(float ratio, float finalRollOffLen,
float midRollOffStartPlusEnd);
static float get2ChainCost(float ratio, float finalRollOffLen, float midRatio,
float midRollOffStartPlusEnd);
static float get3ChainRatio2(float ratio1,
float finalRollOffLen,
float midRollOffStartPlusEnd) {
return get2ChainMidRatio(ratio1, finalRollOffLen, midRollOffStartPlusEnd);
}
static float get3ChainRatio1(float ratio1, float finalRollOffLen, float ratio,
float midRollOffStartPlusEnd);
static float get3ChainCost(float ratio, float finalRollOffLen, float ratio1, float ratio2,
float midRollOffStartPlusEnd);
void downinitAddSincResamplers(double ratio, float outRate, void downinitAddSincResamplers(double ratio, float outRate,
CreateSinc createBigSinc, CreateSinc createSmallSinc, CreateSinc createBigSinc, CreateSinc createSmallSinc,
unsigned bigSincMul, unsigned smallSincMul, double gain); unsigned bigSincMul, unsigned smallSincMul, double gain);
void reallocateBuffer();
template<class Sinc> template<class Sinc>
static SubResampler * createSinc(unsigned div, static SubResampler * createSinc(unsigned div,
@ -87,33 +66,29 @@ private:
return new Sinc(div, typename Sinc::RollOff(rollOffStart, rollOffWidth), gain); return new Sinc(div, typename Sinc::RollOff(rollOffStart, rollOffWidth), gain);
} }
template<template<unsigned,unsigned> class Sinc> template<template<unsigned, unsigned> class Sinc>
std::size_t downinit(long inRate, long outRate, std::size_t periodSize); void downinit(long inRate, long outRate);
template<template<unsigned,unsigned> class Sinc> template<template<unsigned, unsigned> class Sinc>
std::size_t upinit(long inRate, long outRate, std::size_t periodSize); void upinit(long inRate, long outRate);
std::size_t reallocateBuffer();
}; };
template<template<unsigned,unsigned> class Sinc> template<template<unsigned, unsigned> class Sinc>
std::size_t ChainResampler::init(long inRate, long outRate, std::size_t periodSize) { Resampler * ChainResampler::create(long inRate, long outRate, std::size_t periodSize) {
setRate(inRate, outRate); transfer_ptr<ChainResampler> r(new ChainResampler(inRate, outRate, periodSize));
if (outRate > inRate) if (outRate > inRate)
return upinit<Sinc>(inRate, outRate, periodSize); r->upinit<Sinc>(inRate, outRate);
else else
return downinit<Sinc>(inRate, outRate, periodSize); r->downinit<Sinc>(inRate, outRate);
return r.release();
} }
template<template<unsigned,unsigned> class Sinc> template<template<unsigned, unsigned> class Sinc>
std::size_t ChainResampler::downinit(long const inRate, void ChainResampler::downinit(long const inRate,
long const outRate, long const outRate) {
std::size_t const periodSize) {
typedef Sinc<channels, 2048> BigSinc; typedef Sinc<channels, 2048> BigSinc;
typedef Sinc<channels, 32> SmallSinc; typedef Sinc<channels, 32> SmallSinc;
uninit();
periodSize_ = periodSize;
double ratio = static_cast<double>(inRate) / outRate; double ratio = static_cast<double>(inRate) / outRate;
double gain = 1.0; double gain = 1.0;
@ -125,19 +100,17 @@ std::size_t ChainResampler::downinit(long const inRate,
gain *= 1.0 / BigSinc::Cic::gain(div); gain *= 1.0 / BigSinc::Cic::gain(div);
} }
downinitAddSincResamplers(ratio, outRate, createSinc<BigSinc>, downinitAddSincResamplers(ratio, outRate,
createSinc<SmallSinc>, BigSinc::MUL, SmallSinc::MUL, gain); createSinc<BigSinc>, createSinc<SmallSinc>,
return reallocateBuffer(); BigSinc::MUL, SmallSinc::MUL, gain);
reallocateBuffer();
} }
template<template<unsigned,unsigned> class Sinc> template<template<unsigned, unsigned> class Sinc>
std::size_t ChainResampler::upinit(long const inRate, void ChainResampler::upinit(long const inRate,
long const outRate, long const outRate) {
std::size_t const periodSize) {
typedef Sinc<channels, 2048> BigSinc; typedef Sinc<channels, 2048> BigSinc;
typedef Sinc<channels, 32> SmallSinc; typedef Sinc<channels, 32> SmallSinc;
uninit();
periodSize_ = periodSize;
double ratio = static_cast<double>(outRate) / inRate; double ratio = static_cast<double>(outRate) / inRate;
// Spectral images above 20 kHz assumed inaudible // Spectral images above 20 kHz assumed inaudible
@ -155,7 +128,7 @@ std::size_t ChainResampler::upinit(long const inRate,
typename BigSinc::RollOff(0.5f * (1 - rollOff), 0.5f * rollOff), typename BigSinc::RollOff(0.5f * (1 - rollOff), 0.5f * rollOff),
1.0); 1.0);
list_.push_front(bigSinc_); // note: inserted at the front list_.push_front(bigSinc_); // note: inserted at the front
return reallocateBuffer(); reallocateBuffer();
} }
#endif #endif

View File

@ -29,20 +29,13 @@ static Resampler * createLinint(long inRate, long outRate, std::size_t ) {
return new Linint<ResamplerInfo::channels>(inRate, outRate); return new Linint<ResamplerInfo::channels>(inRate, outRate);
} }
template<template<unsigned, unsigned> class T>
static Resampler * createChainResampler(long inRate, long outRate, std::size_t periodSize) {
ChainResampler *r = new ChainResampler;
r->init<T>(inRate, outRate, periodSize);
return r;
}
ResamplerInfo const ResamplerInfo::resamplers_[] = { ResamplerInfo const ResamplerInfo::resamplers_[] = {
{ "Fast", createLinint }, { "Fast", createLinint },
{ "High quality (polyphase FIR)", createChainResampler<RectSinc> }, { "High quality (polyphase FIR)", ChainResampler::create<RectSinc> },
// { "Hamming windowed sinc (~50 dB SNR)", createChainResampler<HammingSinc> }, // { "Hamming windowed sinc (~50 dB SNR)", ChainResampler::create<HammingSinc> },
// { "Blackman windowed sinc (~70 dB SNR)", createChainResampler<BlackmanSinc> }, // { "Blackman windowed sinc (~70 dB SNR)", ChainResampler::create<BlackmanSinc> },
{ "Very high quality (polyphase FIR)", createChainResampler<Kaiser50Sinc> }, { "Very high quality (polyphase FIR)", ChainResampler::create<Kaiser50Sinc> },
{ "Highest quality (polyphase FIR)", createChainResampler<Kaiser70Sinc> }, { "Highest quality (polyphase FIR)", ChainResampler::create<Kaiser70Sinc> },
}; };
std::size_t const ResamplerInfo::num_ = std::size_t const ResamplerInfo::num_ =