1
0
mirror of https://github.com/RPCS3/soundtouch.git synced 2024-11-09 12:22:51 +01:00

Restructured RateTransposer to allow hosting alternative resampling algorithms.

This commit is contained in:
oparviai 2014-01-05 21:40:22 +00:00
parent 8174f6bc10
commit abfeb3fcc9
6 changed files with 203 additions and 164 deletions

View File

@ -162,6 +162,12 @@ public:
/// Sets number of channels, 1 = mono, 2 = stereo.
void setChannels(int numChannels);
/// Get number of channels
int getChannels()
{
return channels;
}
/// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const;

View File

@ -205,6 +205,31 @@ uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples
}
/// Applies the filter to the given src & dest pipes, so that processed amount of
/// samples get removed from src, and produced amount added to dest
/// Note : The amount of outputted samples is by value of 'filter length'
/// smaller than the amount of input samples.
uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const
{
SAMPLETYPE *pdest;
const SAMPLETYPE *psrc;
uint numSrcSamples;
uint result;
int numChannels = src.getChannels();
assert(numChannels == dest.getChannels());
numSrcSamples = src.numSamples();
psrc = src.ptrBegin();
pdest = dest.ptrEnd(numSrcSamples);
result = pFIR->evaluate(pdest, psrc, numSrcSamples, numChannels);
src.receiveSamples(result);
dest.putSamples(result);
return result;
}
uint AAFilter::getLength() const
{
return pFIR->getLength();

View File

@ -45,6 +45,7 @@
#define AAFilter_H
#include "STTypes.h"
#include "FIFOSampleBuffer.h"
namespace soundtouch
{
@ -84,6 +85,14 @@ public:
const SAMPLETYPE *src,
uint numSamples,
uint numChannels) const;
/// Applies the filter to the given src & dest pipes, so that processed amount of
/// samples get removed from src, and produced amount added to dest
/// Note : The amount of outputted samples is by value of 'filter length'
/// smaller than the amount of input samples.
uint AAFilter::evaluate(FIFOSampleBuffer &dest,
FIFOSampleBuffer &src) const;
};
}

View File

@ -48,9 +48,31 @@
using namespace soundtouch;
/// A linear samplerate transposer class that uses integer arithmetics.
/// for the transposing.
class RateTransposerInteger : public RateTransposer
class LinearTransposerBase: public TransposerBase
{
protected:
virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples) = 0;
virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples) = 0;
virtual int transposeMulti(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples) = 0;
public:
virtual int transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src);
static LinearTransposerBase *newInstance();
};
/// A linear samplerate transposer class that uses integer arithmetics.
/// for the transposing.
class LinearTransposerInteger : public LinearTransposerBase
{
protected:
int iSlopeCount;
@ -67,19 +89,18 @@ protected:
uint numSamples);
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples);
public:
RateTransposerInteger();
virtual ~RateTransposerInteger();
LinearTransposerInteger();
virtual ~LinearTransposerInteger();
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower
/// rate, larger faster rates.
virtual void setRate(float newRate);
};
/// A linear samplerate transposer class that uses floating point arithmetics
/// for the transposing.
class RateTransposerFloat : public RateTransposer
class LinearTransposerFloat : public LinearTransposerBase
{
protected:
float fSlopeCount;
@ -96,28 +117,53 @@ protected:
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples);
public:
RateTransposerFloat();
virtual ~RateTransposerFloat();
LinearTransposerFloat();
virtual ~LinearTransposerFloat();
};
TransposerBase::TransposerBase()
{
numChannels = 0;
rate = 1.0f;
}
TransposerBase::~TransposerBase()
{
}
void TransposerBase::setChannels(int channels)
{
numChannels = channels;
resetRegisters();
}
void TransposerBase::setRate(float newRate)
{
rate = newRate;
}
// Operator 'new' is overloaded so that it automatically creates a suitable instance
// depending on if we've a MMX/SSE/etc-capable CPU available or not.
/*
void * RateTransposer::operator new(size_t s)
{
ST_THROW_RT_ERROR("Error in RateTransoser::new: don't use \"new TDStretch\" directly, use \"newInstance\" to create a new instance instead!");
return newInstance();
}
*/
RateTransposer *RateTransposer::newInstance()
TransposerBase *TransposerBase::newInstance()
{
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
return ::new RateTransposerInteger;
return ::new LinearTransposerInteger;
#else
return ::new RateTransposerFloat;
return ::new LinearTransposerFloat;
#endif
}
@ -125,13 +171,12 @@ RateTransposer *RateTransposer::newInstance()
// Constructor
RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
{
numChannels = 2;
bUseAAFilter = TRUE;
fRate = 0;
// Instantiates the anti-alias filter with default tap length
// of 32
pAAFilter = new AAFilter(32);
pTransposer = TransposerBase::newInstance();
}
@ -139,6 +184,7 @@ RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
RateTransposer::~RateTransposer()
{
delete pAAFilter;
delete pTransposer;
}
@ -170,7 +216,7 @@ void RateTransposer::setRate(float newRate)
{
double fCutoff;
fRate = newRate;
pTransposer->setRate(newRate);
// design a new anti-alias filter
if (newRate > 1.0f)
@ -192,11 +238,11 @@ void RateTransposer::setRate(float newRate)
// It's allowed for 'output' and 'input' parameters to point to the same
// memory position.
/*
void RateTransposer::flushStoreBuffer()
void RateTransposer::flushinputBuffer()
{
if (storeBuffer.isEmpty()) return;
if (inputBuffer.isEmpty()) return;
outputBuffer.moveSamples(storeBuffer);
outputBuffer.moveSamples(inputBuffer);
}
*/
@ -209,70 +255,6 @@ void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples)
}
// Transposes up the sample rate, causing the observed playback 'rate' of the
// sound to decrease
void RateTransposer::upsample(const SAMPLETYPE *src, uint nSamples)
{
uint count, sizeTemp, num;
// If the parameter 'uRate' value is smaller than 'SCALE', first transpose
// the samples and then apply the anti-alias filter to remove aliasing.
// First check that there's enough room in 'storeBuffer'
// (+16 is to reserve some slack in the destination buffer)
sizeTemp = (uint)((float)nSamples / fRate + 16.0f);
// Transpose the samples, store the result into the end of "storeBuffer"
count = transpose(storeBuffer.ptrEnd(sizeTemp), src, nSamples);
storeBuffer.putSamples(count);
// Apply the anti-alias filter to samples in "store output", output the
// result to "dest"
num = storeBuffer.numSamples();
count = pAAFilter->evaluate(outputBuffer.ptrEnd(num),
storeBuffer.ptrBegin(), num, (uint)numChannels);
outputBuffer.putSamples(count);
// Remove the processed samples from "storeBuffer"
storeBuffer.receiveSamples(count);
}
// Transposes down the sample rate, causing the observed playback 'rate' of the
// sound to increase
void RateTransposer::downsample(const SAMPLETYPE *src, uint nSamples)
{
uint count, sizeTemp;
// If the parameter 'uRate' value is larger than 'SCALE', first apply the
// anti-alias filter to remove high frequencies (prevent them from folding
// over the lover frequencies), then transpose.
// Add the new samples to the end of the storeBuffer
storeBuffer.putSamples(src, nSamples);
// Anti-alias filter the samples to prevent folding and output the filtered
// data to tempBuffer. Note : because of the FIR filter length, the
// filtering routine takes in 'filter_length' more samples than it outputs.
assert(tempBuffer.isEmpty());
sizeTemp = storeBuffer.numSamples();
count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp),
storeBuffer.ptrBegin(), sizeTemp, (uint)numChannels);
if (count == 0) return;
// Remove the filtered samples from 'storeBuffer'
storeBuffer.receiveSamples(count);
// Transpose the samples (+16 is to reserve some slack in the destination buffer)
sizeTemp = (uint)((float)nSamples / fRate + 16.0f);
count = transpose(outputBuffer.ptrEnd(sizeTemp), tempBuffer.ptrBegin(), count);
outputBuffer.putSamples(count);
}
// Transposes sample rate by applying anti-alias filter to prevent folding.
// Returns amount of samples returned in the "dest" buffer.
// The maximum amount of samples that can be returned at a time is set by
@ -280,52 +262,77 @@ void RateTransposer::downsample(const SAMPLETYPE *src, uint nSamples)
void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
{
uint count;
uint sizeReq;
if (nSamples == 0) return;
assert(pAAFilter);
// Store samples to input buffer
inputBuffer.putSamples(src, nSamples);
// If anti-alias filter is turned off, simply transpose without applying
// the filter
if (bUseAAFilter == FALSE)
{
sizeReq = (uint)((float)nSamples / fRate + 1.0f);
count = transpose(outputBuffer.ptrEnd(sizeReq), src, nSamples);
outputBuffer.putSamples(count);
count = pTransposer->transpose(outputBuffer, inputBuffer);
return;
}
assert(pAAFilter);
// Transpose with anti-alias filter
if (fRate < 1.0f)
if (pTransposer->rate < 1.0f)
{
upsample(src, nSamples);
// If the parameter 'Rate' value is smaller than 1, first transpose
// the samples and then apply the anti-alias filter to remove aliasing.
// Transpose the samples, store the result to end of "midBuffer"
pTransposer->transpose(midBuffer, inputBuffer);
// Apply the anti-alias filter for transposed samples in midBuffer
pAAFilter->evaluate(outputBuffer, midBuffer);
}
else
{
downsample(src, nSamples);
// If the parameter 'Rate' value is larger than 1, first apply the
// anti-alias filter to remove high frequencies (prevent them from folding
// over the lover frequencies), then transpose.
// Apply the anti-alias filter for samples in inputBuffer
pAAFilter->evaluate(midBuffer, inputBuffer);
// Transpose the AA-filtered samples in "midBuffer"
pTransposer->transpose(outputBuffer, midBuffer);
}
}
// Transposes the sample rate of the given samples using linear interpolation.
// Returns the number of samples returned in the "dest" buffer
inline int RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
int LinearTransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src)
{
int numSrcSamples = src.numSamples();
int sizeDemand = (int)((float)numSrcSamples / rate) + 8;
int numOutput;
SAMPLETYPE *psrc = src.ptrBegin();
SAMPLETYPE *pdest = dest.ptrEnd(sizeDemand);
#ifndef USE_MULTICH_ALWAYS
if (numChannels == 1)
{
return transposeMono(dest, src, nSamples);
numOutput = transposeMono(pdest, psrc, numSrcSamples);
}
else if (numChannels == 2)
{
return transposeStereo(dest, src, nSamples);
numOutput = transposeStereo(pdest, psrc, numSrcSamples);
}
else
#endif // USE_MULTICH_ALWAYS
{
assert(numChannels > 0);
return transposeMulti(dest, src, nSamples);
numOutput = transposeMulti(pdest, psrc, numSrcSamples);
}
dest.putSamples(numOutput);
src.receiveSamples(numOutput);
return numOutput;
}
@ -333,17 +340,13 @@ inline int RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, ui
void RateTransposer::setChannels(int nChannels)
{
assert(nChannels > 0);
if (numChannels == nChannels) return;
// assert(nChannels == 1 || nChannels == 2);
numChannels = nChannels;
if (pTransposer->numChannels == nChannels) return;
pTransposer->setChannels(nChannels);
storeBuffer.setChannels(numChannels);
tempBuffer.setChannels(numChannels);
outputBuffer.setChannels(numChannels);
// Inits the linear interpolation registers
resetRegisters();
inputBuffer.setChannels(nChannels);
midBuffer.setChannels(nChannels);
outputBuffer.setChannels(nChannels);
}
@ -351,7 +354,8 @@ void RateTransposer::setChannels(int nChannels)
void RateTransposer::clear()
{
outputBuffer.clear();
storeBuffer.clear();
midBuffer.clear();
inputBuffer.clear();
}
@ -362,36 +366,36 @@ int RateTransposer::isEmpty() const
res = FIFOProcessor::isEmpty();
if (res == 0) return 0;
return storeBuffer.isEmpty();
return inputBuffer.isEmpty();
}
//////////////////////////////////////////////////////////////////////////////
//
// RateTransposerInteger - integer arithmetic implementation
// LinearTransposerInteger - integer arithmetic implementation
//
/// fixed-point interpolation routine precision
#define SCALE 65536
// Constructor
RateTransposerInteger::RateTransposerInteger() : RateTransposer()
LinearTransposerInteger::LinearTransposerInteger() : LinearTransposerBase()
{
// Notice: use local function calling syntax for sake of clarity,
// to indicate the fact that C++ constructor can't call virtual functions.
sPrevSample=0;
RateTransposerInteger::resetRegisters();
RateTransposerInteger::setRate(1.0f);
resetRegisters();
setRate(1.0f);
}
RateTransposerInteger::~RateTransposerInteger()
LinearTransposerInteger::~LinearTransposerInteger()
{
if (sPrevSample) delete[] sPrevSample;
}
void RateTransposerInteger::resetRegisters()
void LinearTransposerInteger::resetRegisters()
{
iSlopeCount = 0;
delete[] sPrevSample;
@ -404,7 +408,7 @@ void RateTransposerInteger::resetRegisters()
// Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer
int RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
int LinearTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
{
int i, remain;
LONG_SAMPLETYPE temp, vol1;
@ -453,7 +457,7 @@ end:
// Transposes the sample rate of the given samples using linear interpolation.
// 'Stereo' version of the routine. Returns the number of samples returned in
// the "dest" buffer
int RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
int LinearTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
{
int i, remain;
LONG_SAMPLETYPE temp, vol1;
@ -504,7 +508,7 @@ end:
}
int RateTransposerInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
int LinearTransposerInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
{
int i, remaining;
LONG_SAMPLETYPE temp, vol1;
@ -561,37 +565,37 @@ end:
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
// iRate, larger faster iRates.
void RateTransposerInteger::setRate(float newRate)
void LinearTransposerInteger::setRate(float newRate)
{
iRate = (int)(newRate * SCALE + 0.5f);
RateTransposer::setRate(newRate);
TransposerBase::setRate(newRate);
}
//////////////////////////////////////////////////////////////////////////////
//
// RateTransposerFloat - floating point arithmetic implementation
// LinearTransposerFloat - floating point arithmetic implementation
//
//////////////////////////////////////////////////////////////////////////////
// Constructor
RateTransposerFloat::RateTransposerFloat() : RateTransposer()
LinearTransposerFloat::LinearTransposerFloat() : LinearTransposerBase()
{
// Notice: use local function calling syntax for sake of clarity,
// to indicate the fact that C++ constructor can't call virtual functions.
sPrevSample = NULL;
RateTransposerFloat::resetRegisters();
RateTransposerFloat::setRate(1.0f);
resetRegisters();
setRate(1.0f);
}
RateTransposerFloat::~RateTransposerFloat()
LinearTransposerFloat::~LinearTransposerFloat()
{
delete[] sPrevSample;
}
void RateTransposerFloat::resetRegisters()
void LinearTransposerFloat::resetRegisters()
{
fSlopeCount = 0;
delete[] sPrevSample;
@ -604,19 +608,19 @@ void RateTransposerFloat::resetRegisters()
// Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer
int RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
int LinearTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
{
int i, remain;
remain = nSamples - 1;
i = 0;
remain = nSamples - 1;
i = 0;
// Process the last sample saved from the previous call first...
while (fSlopeCount <= 1.0f)
{
dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSample[0] + fSlopeCount * src[0]);
i++;
fSlopeCount += fRate;
fSlopeCount += rate;
}
fSlopeCount -= 1.0f;
@ -633,7 +637,7 @@ int RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src,
}
dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[0] + fSlopeCount * src[1]);
i++;
fSlopeCount += fRate;
fSlopeCount += rate;
}
}
end:
@ -647,7 +651,7 @@ end:
// Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer
int RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
int LinearTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
{
int i, remain;
@ -662,7 +666,7 @@ int RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src
dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSample[0] + fSlopeCount * src[0]);
dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSample[1] + fSlopeCount * src[1]);
i++;
fSlopeCount += fRate;
fSlopeCount += rate;
}
// now always (iSlopeCount > 1.0f)
fSlopeCount -= 1.0f;
@ -685,7 +689,7 @@ int RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src
+ fSlopeCount * src[3]);
i++;
fSlopeCount += fRate;
fSlopeCount += rate;
}
}
end:
@ -696,7 +700,7 @@ end:
return i;
}
int RateTransposerFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
int LinearTransposerFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
{
int i, remaining;
@ -714,7 +718,7 @@ int RateTransposerFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src,
dest ++;
}
i++;
fSlopeCount += fRate;
fSlopeCount += rate;
}
// now always (iSlopeCount > 1.0f)
fSlopeCount -= 1.0f;
@ -737,7 +741,7 @@ int RateTransposerFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src,
}
i++;
fSlopeCount += fRate;
fSlopeCount += rate;
}
end:

View File

@ -55,51 +55,47 @@
namespace soundtouch
{
/// Abstract base class for transposer implementations (linear, advanced vs integer, float etc)
class TransposerBase
{
protected:
virtual void resetRegisters() = 0;
public:
float rate;
int numChannels;
TransposerBase();
virtual ~TransposerBase();
virtual int transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) = 0;
virtual void setRate(float newRate);
virtual void setChannels(int channels);
static TransposerBase *newInstance();
};
/// A common linear samplerate transposer class.
///
/// Note: Use function "RateTransposer::newInstance()" to create a new class
/// instance instead of the "new" operator; that function automatically
/// chooses a correct implementation depending on if integer or floating
/// arithmetics are to be used.
class RateTransposer : public FIFOProcessor
{
protected:
/// Anti-alias filter object
AAFilter *pAAFilter;
float fRate;
int numChannels;
TransposerBase *pTransposer;
/// Buffer for collecting samples to feed the anti-alias filter between
/// two batches
FIFOSampleBuffer storeBuffer;
FIFOSampleBuffer inputBuffer;
/// Buffer for keeping samples between transposing & anti-alias filter
FIFOSampleBuffer tempBuffer;
FIFOSampleBuffer midBuffer;
/// Output sample buffer
FIFOSampleBuffer outputBuffer;
BOOL bUseAAFilter;
virtual void resetRegisters() = 0;
virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples) = 0;
virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples) = 0;
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples) = 0;
inline int transpose(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples);
void downsample(const SAMPLETYPE *src,
uint numSamples);
void upsample(const SAMPLETYPE *src,
uint numSamples);
/// Transposes sample rate by applying anti-alias filter to prevent folding.
/// Returns amount of samples returned in the "dest" buffer.
@ -108,25 +104,24 @@ protected:
void processSamples(const SAMPLETYPE *src,
uint numSamples);
public:
RateTransposer();
virtual ~RateTransposer();
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
/// depending on if we're to use integer or floating point arithmetics.
static void *operator new(size_t s);
// static void *operator new(size_t s);
/// Use this function instead of "new" operator to create a new instance of this class.
/// This function automatically chooses a correct implementation, depending on if
/// integer ot floating point arithmetics are to be used.
static RateTransposer *newInstance();
// static RateTransposer *newInstance();
/// Returns the output buffer object
FIFOSamplePipe *getOutput() { return &outputBuffer; };
/// Returns the store buffer object
FIFOSamplePipe *getStore() { return &storeBuffer; };
// FIFOSamplePipe *getStore() { return &storeBuffer; };
/// Return anti-alias filter object
AAFilter *getAAFilter();

View File

@ -97,7 +97,7 @@ SoundTouch::SoundTouch()
{
// Initialize rate transposer and tempo changer instances
pRateTransposer = RateTransposer::newInstance();
pRateTransposer = new RateTransposer();
pTDStretch = TDStretch::newInstance();
setOutPipe(pTDStretch);
@ -255,7 +255,7 @@ void SoundTouch::calcEffectiveRateAndTempo()
tempoOut = pTDStretch->getOutput();
tempoOut->moveSamples(*output);
// move samples in pitch transposer's store buffer to tempo changer's input
pTDStretch->moveSamples(*pRateTransposer->getStore());
// deprecated : pTDStretch->moveSamples(*pRateTransposer->getStore());
output = pTDStretch;
}