2008-02-10 17:24:28 +01:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
///
|
|
|
|
/// Sample rate transposer. Changes sample rate by using linear interpolation
|
|
|
|
/// together with anti-alias filtering (first order interpolation with anti-
|
|
|
|
/// alias filtering should be quite adequate for this application)
|
|
|
|
///
|
|
|
|
/// Author : Copyright (c) Olli Parviainen
|
|
|
|
/// Author e-mail : oparviai 'at' iki.fi
|
|
|
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
|
|
|
///
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
2008-02-10 17:26:55 +01:00
|
|
|
// Last changed : $Date$
|
2008-02-10 17:24:28 +01:00
|
|
|
// File revision : $Revision: 4 $
|
|
|
|
//
|
2008-02-10 17:26:55 +01:00
|
|
|
// $Id$
|
2008-02-10 17:24:28 +01:00
|
|
|
//
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// License :
|
|
|
|
//
|
|
|
|
// SoundTouch audio processing library
|
|
|
|
// Copyright (c) Olli Parviainen
|
|
|
|
//
|
|
|
|
// This library is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
|
|
// License as published by the Free Software Foundation; either
|
|
|
|
// version 2.1 of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
|
|
// License along with this library; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
//
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#include <memory.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "RateTransposer.h"
|
|
|
|
#include "AAFilter.h"
|
|
|
|
|
|
|
|
using namespace soundtouch;
|
|
|
|
|
|
|
|
|
2014-01-05 22:40:22 +01:00
|
|
|
|
2008-02-10 17:24:28 +01:00
|
|
|
/// A linear samplerate transposer class that uses integer arithmetics.
|
|
|
|
/// for the transposing.
|
2014-01-05 22:40:22 +01:00
|
|
|
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
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
|
|
|
protected:
|
|
|
|
int iSlopeCount;
|
|
|
|
int iRate;
|
2013-06-12 17:24:44 +02:00
|
|
|
SAMPLETYPE *sPrevSample;
|
2008-02-10 17:24:28 +01:00
|
|
|
|
|
|
|
virtual void resetRegisters();
|
|
|
|
|
2013-06-12 17:24:44 +02:00
|
|
|
virtual int transposeStereo(SAMPLETYPE *dest,
|
2008-02-10 17:24:28 +01:00
|
|
|
const SAMPLETYPE *src,
|
|
|
|
uint numSamples);
|
2013-06-12 17:24:44 +02:00
|
|
|
virtual int transposeMono(SAMPLETYPE *dest,
|
2008-02-10 17:24:28 +01:00
|
|
|
const SAMPLETYPE *src,
|
|
|
|
uint numSamples);
|
2013-06-12 17:24:44 +02:00
|
|
|
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples);
|
2008-02-10 17:24:28 +01:00
|
|
|
public:
|
2014-01-05 22:40:22 +01:00
|
|
|
LinearTransposerInteger();
|
|
|
|
virtual ~LinearTransposerInteger();
|
2008-02-10 17:24:28 +01:00
|
|
|
|
|
|
|
/// 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.
|
2014-01-05 22:40:22 +01:00
|
|
|
class LinearTransposerFloat : public LinearTransposerBase
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
|
|
|
protected:
|
|
|
|
float fSlopeCount;
|
2013-06-12 17:24:44 +02:00
|
|
|
SAMPLETYPE *sPrevSample;
|
2008-02-10 17:24:28 +01:00
|
|
|
|
|
|
|
virtual void resetRegisters();
|
|
|
|
|
2013-06-12 17:24:44 +02:00
|
|
|
virtual int transposeStereo(SAMPLETYPE *dest,
|
2008-02-10 17:24:28 +01:00
|
|
|
const SAMPLETYPE *src,
|
|
|
|
uint numSamples);
|
2013-06-12 17:24:44 +02:00
|
|
|
virtual int transposeMono(SAMPLETYPE *dest,
|
2008-02-10 17:24:28 +01:00
|
|
|
const SAMPLETYPE *src,
|
|
|
|
uint numSamples);
|
2013-06-12 17:24:44 +02:00
|
|
|
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples);
|
2008-02-10 17:24:28 +01:00
|
|
|
|
|
|
|
public:
|
2014-01-05 22:40:22 +01:00
|
|
|
LinearTransposerFloat();
|
|
|
|
virtual ~LinearTransposerFloat();
|
2008-02-10 17:24:28 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-01-05 22:40:22 +01:00
|
|
|
TransposerBase::TransposerBase()
|
|
|
|
{
|
|
|
|
numChannels = 0;
|
|
|
|
rate = 1.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TransposerBase::~TransposerBase()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TransposerBase::setChannels(int channels)
|
|
|
|
{
|
|
|
|
numChannels = channels;
|
|
|
|
resetRegisters();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TransposerBase::setRate(float newRate)
|
|
|
|
{
|
|
|
|
rate = newRate;
|
|
|
|
}
|
2008-02-10 17:24:28 +01:00
|
|
|
|
|
|
|
|
|
|
|
// 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.
|
2014-01-05 22:40:22 +01:00
|
|
|
/*
|
2008-02-10 17:24:28 +01:00
|
|
|
void * RateTransposer::operator new(size_t s)
|
|
|
|
{
|
2011-09-02 20:56:11 +02:00
|
|
|
ST_THROW_RT_ERROR("Error in RateTransoser::new: don't use \"new TDStretch\" directly, use \"newInstance\" to create a new instance instead!");
|
|
|
|
return newInstance();
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
2014-01-05 22:40:22 +01:00
|
|
|
*/
|
2008-02-10 17:24:28 +01:00
|
|
|
|
|
|
|
|
2014-01-05 22:40:22 +01:00
|
|
|
TransposerBase *TransposerBase::newInstance()
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
2011-02-13 20:13:57 +01:00
|
|
|
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
2014-01-05 22:40:22 +01:00
|
|
|
return ::new LinearTransposerInteger;
|
2008-02-10 17:24:28 +01:00
|
|
|
#else
|
2014-01-05 22:40:22 +01:00
|
|
|
return ::new LinearTransposerFloat;
|
2008-02-10 17:24:28 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Constructor
|
|
|
|
RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
|
|
|
|
{
|
|
|
|
bUseAAFilter = TRUE;
|
|
|
|
|
|
|
|
// Instantiates the anti-alias filter with default tap length
|
|
|
|
// of 32
|
|
|
|
pAAFilter = new AAFilter(32);
|
2014-01-05 22:40:22 +01:00
|
|
|
pTransposer = TransposerBase::newInstance();
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RateTransposer::~RateTransposer()
|
|
|
|
{
|
|
|
|
delete pAAFilter;
|
2014-01-05 22:40:22 +01:00
|
|
|
delete pTransposer;
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
|
2009-01-11 12:34:24 +01:00
|
|
|
void RateTransposer::enableAAFilter(BOOL newMode)
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
|
|
|
bUseAAFilter = newMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns nonzero if anti-alias filter is enabled.
|
|
|
|
BOOL RateTransposer::isAAFilterEnabled() const
|
|
|
|
{
|
|
|
|
return bUseAAFilter;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-21 17:00:14 +01:00
|
|
|
AAFilter *RateTransposer::getAAFilter()
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
|
|
|
return pAAFilter;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
|
|
|
|
// iRate, larger faster iRates.
|
|
|
|
void RateTransposer::setRate(float newRate)
|
|
|
|
{
|
|
|
|
double fCutoff;
|
|
|
|
|
2014-01-05 22:40:22 +01:00
|
|
|
pTransposer->setRate(newRate);
|
2008-02-10 17:24:28 +01:00
|
|
|
|
|
|
|
// design a new anti-alias filter
|
|
|
|
if (newRate > 1.0f)
|
|
|
|
{
|
|
|
|
fCutoff = 0.5f / newRate;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fCutoff = 0.5f * newRate;
|
|
|
|
}
|
|
|
|
pAAFilter->setCutoffFreq(fCutoff);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Outputs as many samples of the 'outputBuffer' as possible, and if there's
|
|
|
|
// any room left, outputs also as many of the incoming samples as possible.
|
|
|
|
// The goal is to drive the outputBuffer empty.
|
|
|
|
//
|
|
|
|
// It's allowed for 'output' and 'input' parameters to point to the same
|
|
|
|
// memory position.
|
|
|
|
/*
|
2014-01-05 22:40:22 +01:00
|
|
|
void RateTransposer::flushinputBuffer()
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
2014-01-05 22:40:22 +01:00
|
|
|
if (inputBuffer.isEmpty()) return;
|
2008-02-10 17:24:28 +01:00
|
|
|
|
2014-01-05 22:40:22 +01:00
|
|
|
outputBuffer.moveSamples(inputBuffer);
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
// Adds 'nSamples' pcs of samples from the 'samples' memory position into
|
|
|
|
// the input of the object.
|
|
|
|
void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples)
|
|
|
|
{
|
|
|
|
processSamples(samples, nSamples);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
// the 'set_returnBuffer_size' function.
|
|
|
|
void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
|
|
|
|
{
|
|
|
|
uint count;
|
|
|
|
|
|
|
|
if (nSamples == 0) return;
|
2014-01-05 22:40:22 +01:00
|
|
|
|
|
|
|
// Store samples to input buffer
|
|
|
|
inputBuffer.putSamples(src, nSamples);
|
2008-02-10 17:24:28 +01:00
|
|
|
|
|
|
|
// If anti-alias filter is turned off, simply transpose without applying
|
|
|
|
// the filter
|
|
|
|
if (bUseAAFilter == FALSE)
|
|
|
|
{
|
2014-01-05 22:40:22 +01:00
|
|
|
count = pTransposer->transpose(outputBuffer, inputBuffer);
|
2008-02-10 17:24:28 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-01-05 22:40:22 +01:00
|
|
|
assert(pAAFilter);
|
|
|
|
|
2008-02-10 17:24:28 +01:00
|
|
|
// Transpose with anti-alias filter
|
2014-01-05 22:40:22 +01:00
|
|
|
if (pTransposer->rate < 1.0f)
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
2014-01-05 22:40:22 +01:00
|
|
|
// 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);
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-01-05 22:40:22 +01:00
|
|
|
// 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);
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Transposes the sample rate of the given samples using linear interpolation.
|
|
|
|
// Returns the number of samples returned in the "dest" buffer
|
2014-01-05 22:40:22 +01:00
|
|
|
int LinearTransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src)
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
2014-01-05 22:40:22 +01:00
|
|
|
int numSrcSamples = src.numSamples();
|
|
|
|
int sizeDemand = (int)((float)numSrcSamples / rate) + 8;
|
|
|
|
int numOutput;
|
|
|
|
SAMPLETYPE *psrc = src.ptrBegin();
|
|
|
|
SAMPLETYPE *pdest = dest.ptrEnd(sizeDemand);
|
|
|
|
|
2013-06-12 17:24:44 +02:00
|
|
|
#ifndef USE_MULTICH_ALWAYS
|
|
|
|
if (numChannels == 1)
|
|
|
|
{
|
2014-01-05 22:40:22 +01:00
|
|
|
numOutput = transposeMono(pdest, psrc, numSrcSamples);
|
2013-06-12 17:24:44 +02:00
|
|
|
}
|
|
|
|
else if (numChannels == 2)
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
2014-01-05 22:40:22 +01:00
|
|
|
numOutput = transposeStereo(pdest, psrc, numSrcSamples);
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
else
|
2013-06-12 17:24:44 +02:00
|
|
|
#endif // USE_MULTICH_ALWAYS
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
2013-06-12 17:24:44 +02:00
|
|
|
assert(numChannels > 0);
|
2014-01-05 22:40:22 +01:00
|
|
|
numOutput = transposeMulti(pdest, psrc, numSrcSamples);
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
2014-01-05 22:40:22 +01:00
|
|
|
dest.putSamples(numOutput);
|
|
|
|
src.receiveSamples(numOutput);
|
|
|
|
return numOutput;
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Sets the number of channels, 1 = mono, 2 = stereo
|
|
|
|
void RateTransposer::setChannels(int nChannels)
|
|
|
|
{
|
|
|
|
assert(nChannels > 0);
|
|
|
|
|
2014-01-05 22:40:22 +01:00
|
|
|
if (pTransposer->numChannels == nChannels) return;
|
|
|
|
pTransposer->setChannels(nChannels);
|
2008-02-10 17:24:28 +01:00
|
|
|
|
2014-01-05 22:40:22 +01:00
|
|
|
inputBuffer.setChannels(nChannels);
|
|
|
|
midBuffer.setChannels(nChannels);
|
|
|
|
outputBuffer.setChannels(nChannels);
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Clears all the samples in the object
|
|
|
|
void RateTransposer::clear()
|
|
|
|
{
|
|
|
|
outputBuffer.clear();
|
2014-01-05 22:40:22 +01:00
|
|
|
midBuffer.clear();
|
|
|
|
inputBuffer.clear();
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Returns nonzero if there aren't any samples available for outputting.
|
|
|
|
int RateTransposer::isEmpty() const
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
|
|
|
|
res = FIFOProcessor::isEmpty();
|
|
|
|
if (res == 0) return 0;
|
2014-01-05 22:40:22 +01:00
|
|
|
return inputBuffer.isEmpty();
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
2014-01-05 22:40:22 +01:00
|
|
|
// LinearTransposerInteger - integer arithmetic implementation
|
2008-02-10 17:24:28 +01:00
|
|
|
//
|
|
|
|
|
|
|
|
/// fixed-point interpolation routine precision
|
|
|
|
#define SCALE 65536
|
|
|
|
|
|
|
|
// Constructor
|
2014-01-05 22:40:22 +01:00
|
|
|
LinearTransposerInteger::LinearTransposerInteger() : LinearTransposerBase()
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
|
|
|
// Notice: use local function calling syntax for sake of clarity,
|
|
|
|
// to indicate the fact that C++ constructor can't call virtual functions.
|
2013-06-12 17:24:44 +02:00
|
|
|
sPrevSample=0;
|
2014-01-05 22:40:22 +01:00
|
|
|
resetRegisters();
|
|
|
|
setRate(1.0f);
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-05 22:40:22 +01:00
|
|
|
LinearTransposerInteger::~LinearTransposerInteger()
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
2013-06-12 17:24:44 +02:00
|
|
|
if (sPrevSample) delete[] sPrevSample;
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-05 22:40:22 +01:00
|
|
|
void LinearTransposerInteger::resetRegisters()
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
|
|
|
iSlopeCount = 0;
|
2013-06-14 19:34:33 +02:00
|
|
|
delete[] sPrevSample;
|
2013-06-12 17:24:44 +02:00
|
|
|
sPrevSample = new SAMPLETYPE[numChannels];
|
2013-06-14 19:34:33 +02:00
|
|
|
memset(sPrevSample, 0, numChannels * sizeof(SAMPLETYPE));
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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
|
2014-01-05 22:40:22 +01:00
|
|
|
int LinearTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
2013-06-12 17:24:44 +02:00
|
|
|
int i, remain;
|
2008-02-10 17:24:28 +01:00
|
|
|
LONG_SAMPLETYPE temp, vol1;
|
|
|
|
|
2009-10-31 15:37:24 +01:00
|
|
|
if (nSamples == 0) return 0; // no samples, no work
|
|
|
|
|
2013-06-12 17:24:44 +02:00
|
|
|
remain = nSamples - 1;
|
2008-02-10 17:24:28 +01:00
|
|
|
i = 0;
|
|
|
|
|
|
|
|
// Process the last sample saved from the previous call first...
|
|
|
|
while (iSlopeCount <= SCALE)
|
|
|
|
{
|
|
|
|
vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
|
2013-06-12 17:24:44 +02:00
|
|
|
temp = vol1 * sPrevSample[0] + iSlopeCount * src[0];
|
2008-02-10 17:24:28 +01:00
|
|
|
dest[i] = (SAMPLETYPE)(temp / SCALE);
|
|
|
|
i++;
|
|
|
|
iSlopeCount += iRate;
|
|
|
|
}
|
|
|
|
// now always (iSlopeCount > SCALE)
|
|
|
|
iSlopeCount -= SCALE;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
while (iSlopeCount > SCALE)
|
|
|
|
{
|
|
|
|
iSlopeCount -= SCALE;
|
2013-06-12 17:24:44 +02:00
|
|
|
src ++;
|
|
|
|
remain --;
|
|
|
|
if (remain == 0) goto end;
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
|
2013-06-12 17:24:44 +02:00
|
|
|
temp = src[0] * vol1 + iSlopeCount * src[1];
|
2008-02-10 17:24:28 +01:00
|
|
|
dest[i] = (SAMPLETYPE)(temp / SCALE);
|
|
|
|
|
|
|
|
i++;
|
|
|
|
iSlopeCount += iRate;
|
|
|
|
}
|
|
|
|
end:
|
|
|
|
// Store the last sample for the next round
|
2013-06-12 17:24:44 +02:00
|
|
|
sPrevSample[0] = src[0];
|
2008-02-10 17:24:28 +01:00
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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
|
2014-01-05 22:40:22 +01:00
|
|
|
int LinearTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
2013-06-12 17:24:44 +02:00
|
|
|
int i, remain;
|
2008-02-10 17:24:28 +01:00
|
|
|
LONG_SAMPLETYPE temp, vol1;
|
|
|
|
|
|
|
|
if (nSamples == 0) return 0; // no samples, no work
|
|
|
|
|
2013-06-12 17:24:44 +02:00
|
|
|
remain = nSamples - 1;
|
2008-02-10 17:24:28 +01:00
|
|
|
i = 0;
|
|
|
|
|
|
|
|
// Process the last sample saved from the sPrevSampleLious call first...
|
|
|
|
while (iSlopeCount <= SCALE)
|
|
|
|
{
|
|
|
|
vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
|
2013-06-12 17:24:44 +02:00
|
|
|
temp = vol1 * sPrevSample[0] + iSlopeCount * src[0];
|
2008-02-10 17:24:28 +01:00
|
|
|
dest[2 * i] = (SAMPLETYPE)(temp / SCALE);
|
2013-06-12 17:24:44 +02:00
|
|
|
temp = vol1 * sPrevSample[1] + iSlopeCount * src[1];
|
2008-02-10 17:24:28 +01:00
|
|
|
dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE);
|
|
|
|
i++;
|
|
|
|
iSlopeCount += iRate;
|
|
|
|
}
|
|
|
|
// now always (iSlopeCount > SCALE)
|
|
|
|
iSlopeCount -= SCALE;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
while (iSlopeCount > SCALE)
|
|
|
|
{
|
|
|
|
iSlopeCount -= SCALE;
|
2013-06-12 17:24:44 +02:00
|
|
|
remain --;
|
|
|
|
src += 2;
|
|
|
|
if (remain == 0) goto end;
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
|
2013-06-12 17:24:44 +02:00
|
|
|
temp = src[0] * vol1 + iSlopeCount * src[2];
|
2008-02-10 17:24:28 +01:00
|
|
|
dest[2 * i] = (SAMPLETYPE)(temp / SCALE);
|
2013-06-12 17:24:44 +02:00
|
|
|
temp = src[1] * vol1 + iSlopeCount * src[3];
|
2008-02-10 17:24:28 +01:00
|
|
|
dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE);
|
|
|
|
|
|
|
|
i++;
|
|
|
|
iSlopeCount += iRate;
|
|
|
|
}
|
|
|
|
end:
|
|
|
|
// Store the last sample for the next round
|
2013-06-12 17:24:44 +02:00
|
|
|
sPrevSample[0] = src[0];
|
|
|
|
sPrevSample[1] = src[1];
|
2008-02-10 17:24:28 +01:00
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-05 22:40:22 +01:00
|
|
|
int LinearTransposerInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
|
2013-06-12 17:24:44 +02:00
|
|
|
{
|
|
|
|
int i, remaining;
|
|
|
|
LONG_SAMPLETYPE temp, vol1;
|
|
|
|
|
|
|
|
if (nSamples == 0) return 0; // no samples, no work
|
|
|
|
|
|
|
|
remaining = nSamples - 1;
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
// Process the last sample saved from the sPrevSampleLious call first...
|
|
|
|
while (iSlopeCount <= SCALE)
|
|
|
|
{
|
|
|
|
for (int c = 0; c < numChannels; c ++)
|
|
|
|
{
|
|
|
|
vol1 = (SCALE - iSlopeCount);
|
|
|
|
temp = vol1 * sPrevSample[c] + iSlopeCount * src[c];
|
|
|
|
*dest = (SAMPLETYPE)(temp / SCALE);
|
|
|
|
dest ++;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
|
|
|
|
iSlopeCount += iRate;
|
|
|
|
}
|
|
|
|
// now always (iSlopeCount > SCALE)
|
|
|
|
iSlopeCount -= SCALE;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
while (iSlopeCount > SCALE)
|
|
|
|
{
|
|
|
|
iSlopeCount -= SCALE;
|
|
|
|
src += numChannels;
|
|
|
|
remaining --;
|
|
|
|
if (remaining == 0) goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int c = 0; c < numChannels; c ++)
|
|
|
|
{
|
|
|
|
vol1 = (SCALE - iSlopeCount);
|
|
|
|
temp = src[c] * vol1 + iSlopeCount * src[c + numChannels];
|
|
|
|
*dest = (SAMPLETYPE)(temp / SCALE);
|
|
|
|
dest++;
|
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
|
|
|
iSlopeCount += iRate;
|
|
|
|
}
|
|
|
|
end:
|
|
|
|
// Store the last sample for the next round
|
|
|
|
memcpy(sPrevSample, src, numChannels * sizeof(SAMPLETYPE));
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2008-02-10 17:24:28 +01:00
|
|
|
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
|
|
|
|
// iRate, larger faster iRates.
|
2014-01-05 22:40:22 +01:00
|
|
|
void LinearTransposerInteger::setRate(float newRate)
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
|
|
|
iRate = (int)(newRate * SCALE + 0.5f);
|
2014-01-05 22:40:22 +01:00
|
|
|
TransposerBase::setRate(newRate);
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
2014-01-05 22:40:22 +01:00
|
|
|
// LinearTransposerFloat - floating point arithmetic implementation
|
2008-02-10 17:24:28 +01:00
|
|
|
//
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// Constructor
|
2014-01-05 22:40:22 +01:00
|
|
|
LinearTransposerFloat::LinearTransposerFloat() : LinearTransposerBase()
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
|
|
|
// Notice: use local function calling syntax for sake of clarity,
|
|
|
|
// to indicate the fact that C++ constructor can't call virtual functions.
|
2013-06-14 19:34:33 +02:00
|
|
|
sPrevSample = NULL;
|
2014-01-05 22:40:22 +01:00
|
|
|
resetRegisters();
|
|
|
|
setRate(1.0f);
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-05 22:40:22 +01:00
|
|
|
LinearTransposerFloat::~LinearTransposerFloat()
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
2013-06-14 19:34:33 +02:00
|
|
|
delete[] sPrevSample;
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-05 22:40:22 +01:00
|
|
|
void LinearTransposerFloat::resetRegisters()
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
|
|
|
fSlopeCount = 0;
|
2013-06-14 19:34:33 +02:00
|
|
|
delete[] sPrevSample;
|
2013-06-12 17:24:44 +02:00
|
|
|
sPrevSample = new SAMPLETYPE[numChannels];
|
2013-06-14 19:34:33 +02:00
|
|
|
memset(sPrevSample, 0, numChannels * sizeof(SAMPLETYPE));
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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
|
2014-01-05 22:40:22 +01:00
|
|
|
int LinearTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
2013-06-12 17:24:44 +02:00
|
|
|
int i, remain;
|
2008-02-10 17:24:28 +01:00
|
|
|
|
2014-01-05 22:40:22 +01:00
|
|
|
remain = nSamples - 1;
|
|
|
|
i = 0;
|
2008-02-10 17:24:28 +01:00
|
|
|
|
|
|
|
// Process the last sample saved from the previous call first...
|
|
|
|
while (fSlopeCount <= 1.0f)
|
|
|
|
{
|
2013-06-12 17:24:44 +02:00
|
|
|
dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSample[0] + fSlopeCount * src[0]);
|
2008-02-10 17:24:28 +01:00
|
|
|
i++;
|
2014-01-05 22:40:22 +01:00
|
|
|
fSlopeCount += rate;
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
fSlopeCount -= 1.0f;
|
|
|
|
|
2009-02-21 17:00:14 +01:00
|
|
|
if (nSamples > 1)
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
2009-02-21 17:00:14 +01:00
|
|
|
while (1)
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
2009-02-21 17:00:14 +01:00
|
|
|
while (fSlopeCount > 1.0f)
|
|
|
|
{
|
|
|
|
fSlopeCount -= 1.0f;
|
2013-06-12 17:24:44 +02:00
|
|
|
src ++;
|
|
|
|
remain --;
|
|
|
|
if (remain == 0) goto end;
|
2009-02-21 17:00:14 +01:00
|
|
|
}
|
2013-06-12 17:24:44 +02:00
|
|
|
dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[0] + fSlopeCount * src[1]);
|
2009-02-21 17:00:14 +01:00
|
|
|
i++;
|
2014-01-05 22:40:22 +01:00
|
|
|
fSlopeCount += rate;
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
end:
|
|
|
|
// Store the last sample for the next round
|
2013-06-12 17:24:44 +02:00
|
|
|
sPrevSample[0] = src[0];
|
2008-02-10 17:24:28 +01:00
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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
|
2014-01-05 22:40:22 +01:00
|
|
|
int LinearTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
2013-06-12 17:24:44 +02:00
|
|
|
int i, remain;
|
2008-02-10 17:24:28 +01:00
|
|
|
|
|
|
|
if (nSamples == 0) return 0; // no samples, no work
|
|
|
|
|
2013-06-12 17:24:44 +02:00
|
|
|
remain = nSamples - 1;
|
2008-02-10 17:24:28 +01:00
|
|
|
i = 0;
|
|
|
|
|
|
|
|
// Process the last sample saved from the sPrevSampleLious call first...
|
|
|
|
while (fSlopeCount <= 1.0f)
|
|
|
|
{
|
2013-06-12 17:24:44 +02:00
|
|
|
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]);
|
2008-02-10 17:24:28 +01:00
|
|
|
i++;
|
2014-01-05 22:40:22 +01:00
|
|
|
fSlopeCount += rate;
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
// now always (iSlopeCount > 1.0f)
|
|
|
|
fSlopeCount -= 1.0f;
|
|
|
|
|
2009-02-21 17:00:14 +01:00
|
|
|
if (nSamples > 1)
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
2009-02-21 17:00:14 +01:00
|
|
|
while (1)
|
2008-02-10 17:24:28 +01:00
|
|
|
{
|
2009-02-21 17:00:14 +01:00
|
|
|
while (fSlopeCount > 1.0f)
|
|
|
|
{
|
|
|
|
fSlopeCount -= 1.0f;
|
2013-06-12 17:24:44 +02:00
|
|
|
remain --;
|
|
|
|
src += 2;
|
|
|
|
if (remain == 0) goto end;
|
2009-02-21 17:00:14 +01:00
|
|
|
}
|
|
|
|
|
2013-06-12 17:24:44 +02:00
|
|
|
dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[0]
|
|
|
|
+ fSlopeCount * src[2]);
|
|
|
|
dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[1]
|
|
|
|
+ fSlopeCount * src[3]);
|
2009-02-21 17:00:14 +01:00
|
|
|
|
|
|
|
i++;
|
2014-01-05 22:40:22 +01:00
|
|
|
fSlopeCount += rate;
|
2008-02-10 17:24:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
end:
|
|
|
|
// Store the last sample for the next round
|
2013-06-12 17:24:44 +02:00
|
|
|
sPrevSample[0] = src[0];
|
|
|
|
sPrevSample[1] = src[1];
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2014-01-05 22:40:22 +01:00
|
|
|
int LinearTransposerFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
|
2013-06-12 17:24:44 +02:00
|
|
|
{
|
|
|
|
int i, remaining;
|
|
|
|
|
|
|
|
if (nSamples == 0) return 0; // no samples, no work
|
|
|
|
|
|
|
|
remaining = nSamples - 1;
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
// Process the last sample saved from the sPrevSampleLious call first...
|
|
|
|
while (fSlopeCount <= 1.0f)
|
|
|
|
{
|
|
|
|
for (int c = 0; c < numChannels; c ++)
|
|
|
|
{
|
|
|
|
*dest = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSample[c] + fSlopeCount * src[c]);
|
|
|
|
dest ++;
|
|
|
|
}
|
|
|
|
i++;
|
2014-01-05 22:40:22 +01:00
|
|
|
fSlopeCount += rate;
|
2013-06-12 17:24:44 +02:00
|
|
|
}
|
|
|
|
// now always (iSlopeCount > 1.0f)
|
|
|
|
fSlopeCount -= 1.0f;
|
|
|
|
|
|
|
|
while (remaining > 0)
|
|
|
|
{
|
|
|
|
while (fSlopeCount > 1.0f)
|
|
|
|
{
|
|
|
|
fSlopeCount -= 1.0f;
|
|
|
|
src += numChannels;
|
|
|
|
remaining --;
|
|
|
|
if (remaining == 0) goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int c = 0; c < numChannels; c ++)
|
|
|
|
{
|
|
|
|
*dest = (SAMPLETYPE)((1.0f - fSlopeCount) * src[c]
|
|
|
|
+ fSlopeCount * src[c + numChannels]);
|
|
|
|
dest++;
|
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
2014-01-05 22:40:22 +01:00
|
|
|
fSlopeCount += rate;
|
2013-06-12 17:24:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
|
|
|
// Store the last sample for the next round
|
|
|
|
memcpy(sPrevSample, src, numChannels * sizeof(SAMPLETYPE));
|
2008-02-10 17:24:28 +01:00
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|