* Rationalise naming: block -> window or chunk
This commit is contained in:
@@ -72,7 +72,7 @@ public:
|
||||
virtual void setPhaseOption(Options options);
|
||||
|
||||
virtual void setExpectedInputDuration(size_t samples);
|
||||
virtual void setMaxProcessBlockSize(size_t samples);
|
||||
virtual void setMaxProcessSize(size_t samples);
|
||||
virtual size_t getSamplesRequired() const;
|
||||
|
||||
// if samples == 0, input may be null
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
namespace RubberBand
|
||||
{
|
||||
|
||||
AudioCurve::AudioCurve(size_t sampleRate, size_t blockSize) :
|
||||
AudioCurve::AudioCurve(size_t sampleRate, size_t windowSize) :
|
||||
m_sampleRate(sampleRate),
|
||||
m_blockSize(blockSize)
|
||||
m_windowSize(windowSize)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -23,17 +23,17 @@ namespace RubberBand
|
||||
class AudioCurve
|
||||
{
|
||||
public:
|
||||
AudioCurve(size_t sampleRate, size_t blockSize);
|
||||
AudioCurve(size_t sampleRate, size_t windowSize);
|
||||
virtual ~AudioCurve();
|
||||
|
||||
virtual void setBlockSize(size_t newSize) = 0;
|
||||
virtual void setWindowSize(size_t newSize) = 0;
|
||||
|
||||
virtual float process(float *mag, size_t increment) = 0;
|
||||
virtual void reset() = 0;
|
||||
|
||||
protected:
|
||||
size_t m_sampleRate;
|
||||
size_t m_blockSize;
|
||||
size_t m_windowSize;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
namespace RubberBand
|
||||
{
|
||||
|
||||
ConstantAudioCurve::ConstantAudioCurve(size_t sampleRate, size_t blockSize) :
|
||||
AudioCurve(sampleRate, blockSize)
|
||||
ConstantAudioCurve::ConstantAudioCurve(size_t sampleRate, size_t windowSize) :
|
||||
AudioCurve(sampleRate, windowSize)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -32,9 +32,9 @@ ConstantAudioCurve::reset()
|
||||
}
|
||||
|
||||
void
|
||||
ConstantAudioCurve::setBlockSize(size_t newSize)
|
||||
ConstantAudioCurve::setWindowSize(size_t newSize)
|
||||
{
|
||||
m_blockSize = newSize;
|
||||
m_windowSize = newSize;
|
||||
}
|
||||
|
||||
float
|
||||
|
||||
@@ -23,10 +23,10 @@ namespace RubberBand
|
||||
class ConstantAudioCurve : public AudioCurve
|
||||
{
|
||||
public:
|
||||
ConstantAudioCurve(size_t sampleRate, size_t blockSize);
|
||||
ConstantAudioCurve(size_t sampleRate, size_t windowSize);
|
||||
virtual ~ConstantAudioCurve();
|
||||
|
||||
virtual void setBlockSize(size_t newSize);
|
||||
virtual void setWindowSize(size_t newSize);
|
||||
|
||||
virtual float process(float *mag, size_t increment);
|
||||
virtual void reset();
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
namespace RubberBand
|
||||
{
|
||||
|
||||
HighFrequencyAudioCurve::HighFrequencyAudioCurve(size_t sampleRate, size_t blockSize) :
|
||||
AudioCurve(sampleRate, blockSize)
|
||||
HighFrequencyAudioCurve::HighFrequencyAudioCurve(size_t sampleRate, size_t windowSize) :
|
||||
AudioCurve(sampleRate, windowSize)
|
||||
{
|
||||
m_prevMag = new double[m_blockSize/2 + 1];
|
||||
m_prevMag = new double[m_windowSize/2 + 1];
|
||||
|
||||
for (size_t i = 0; i <= m_blockSize/2; ++i) {
|
||||
for (size_t i = 0; i <= m_windowSize/2; ++i) {
|
||||
m_prevMag[i] = 0.f;
|
||||
}
|
||||
}
|
||||
@@ -35,15 +35,15 @@ HighFrequencyAudioCurve::~HighFrequencyAudioCurve()
|
||||
void
|
||||
HighFrequencyAudioCurve::reset()
|
||||
{
|
||||
for (size_t i = 0; i <= m_blockSize/2; ++i) {
|
||||
for (size_t i = 0; i <= m_windowSize/2; ++i) {
|
||||
m_prevMag[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HighFrequencyAudioCurve::setBlockSize(size_t newSize)
|
||||
HighFrequencyAudioCurve::setWindowSize(size_t newSize)
|
||||
{
|
||||
m_blockSize = newSize;
|
||||
m_windowSize = newSize;
|
||||
}
|
||||
|
||||
float
|
||||
@@ -51,7 +51,7 @@ HighFrequencyAudioCurve::process(float *mag, size_t increment)
|
||||
{
|
||||
float result = 0.0;
|
||||
|
||||
for (size_t n = 0; n <= m_blockSize / 2; ++n) {
|
||||
for (size_t n = 0; n <= m_windowSize / 2; ++n) {
|
||||
result += mag[n];
|
||||
}
|
||||
|
||||
|
||||
@@ -24,11 +24,11 @@ namespace RubberBand
|
||||
class HighFrequencyAudioCurve : public AudioCurve
|
||||
{
|
||||
public:
|
||||
HighFrequencyAudioCurve(size_t sampleRate, size_t blockSize);
|
||||
HighFrequencyAudioCurve(size_t sampleRate, size_t windowSize);
|
||||
|
||||
virtual ~HighFrequencyAudioCurve();
|
||||
|
||||
virtual void setBlockSize(size_t newSize);
|
||||
virtual void setWindowSize(size_t newSize);
|
||||
|
||||
virtual float process(float *mag, size_t increment);
|
||||
virtual void reset();
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
namespace RubberBand
|
||||
{
|
||||
|
||||
PercussiveAudioCurve::PercussiveAudioCurve(size_t sampleRate, size_t blockSize) :
|
||||
AudioCurve(sampleRate, blockSize)
|
||||
PercussiveAudioCurve::PercussiveAudioCurve(size_t sampleRate, size_t windowSize) :
|
||||
AudioCurve(sampleRate, windowSize)
|
||||
{
|
||||
m_prevMag = new double[m_blockSize/2 + 1];
|
||||
m_prevMag = new double[m_windowSize/2 + 1];
|
||||
|
||||
for (size_t i = 0; i <= m_blockSize/2; ++i) {
|
||||
for (size_t i = 0; i <= m_windowSize/2; ++i) {
|
||||
m_prevMag[i] = 0.f;
|
||||
}
|
||||
}
|
||||
@@ -37,18 +37,18 @@ PercussiveAudioCurve::~PercussiveAudioCurve()
|
||||
void
|
||||
PercussiveAudioCurve::reset()
|
||||
{
|
||||
for (size_t i = 0; i <= m_blockSize/2; ++i) {
|
||||
for (size_t i = 0; i <= m_windowSize/2; ++i) {
|
||||
m_prevMag[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PercussiveAudioCurve::setBlockSize(size_t newSize)
|
||||
PercussiveAudioCurve::setWindowSize(size_t newSize)
|
||||
{
|
||||
delete[] m_prevMag;
|
||||
m_blockSize = newSize;
|
||||
m_windowSize = newSize;
|
||||
|
||||
m_prevMag = new double[m_blockSize/2 + 1];
|
||||
m_prevMag = new double[m_windowSize/2 + 1];
|
||||
|
||||
reset();
|
||||
}
|
||||
@@ -62,7 +62,7 @@ PercussiveAudioCurve::process(float *mag, size_t increment)
|
||||
size_t count = 0;
|
||||
size_t nonZeroCount = 0;
|
||||
|
||||
for (size_t n = 1; n <= m_blockSize / 2; ++n) {
|
||||
for (size_t n = 1; n <= m_windowSize / 2; ++n) {
|
||||
//!!! adjust threshold so that this multiplication is unnecessary
|
||||
float sqrmag = mag[n] * mag[n];
|
||||
bool above = ((sqrmag / m_prevMag[n]) >= threshold);
|
||||
@@ -71,7 +71,7 @@ PercussiveAudioCurve::process(float *mag, size_t increment)
|
||||
m_prevMag[n] = sqrmag;
|
||||
}
|
||||
|
||||
//!!! return float(count) / float(m_blockSize);
|
||||
//!!! return float(count) / float(m_windowSize);
|
||||
if (nonZeroCount == 0) return 0;
|
||||
else return float(count) / float(nonZeroCount);
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@ namespace RubberBand
|
||||
class PercussiveAudioCurve : public AudioCurve
|
||||
{
|
||||
public:
|
||||
PercussiveAudioCurve(size_t sampleRate, size_t blockSize);
|
||||
PercussiveAudioCurve(size_t sampleRate, size_t windowSize);
|
||||
|
||||
virtual ~PercussiveAudioCurve();
|
||||
|
||||
virtual void setBlockSize(size_t newSize);
|
||||
virtual void setWindowSize(size_t newSize);
|
||||
|
||||
virtual float process(float *mag, size_t increment);
|
||||
virtual void reset();
|
||||
|
||||
@@ -88,9 +88,9 @@ RubberBandStretcher::setExpectedInputDuration(size_t samples)
|
||||
}
|
||||
|
||||
void
|
||||
RubberBandStretcher::setMaxProcessBlockSize(size_t samples)
|
||||
RubberBandStretcher::setMaxProcessSize(size_t samples)
|
||||
{
|
||||
m_d->setMaxProcessBlockSize(samples);
|
||||
m_d->setMaxProcessSize(samples);
|
||||
}
|
||||
|
||||
size_t
|
||||
|
||||
@@ -51,10 +51,6 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
|
||||
|
||||
//!!! This description is out of date.
|
||||
|
||||
//!!! Rationalise naming -- generally wise to avoid the word
|
||||
//"frame" and instead use "block" / "sample" for processing frame /
|
||||
// audio frame.
|
||||
|
||||
// 1. Pre-process the df array, and for each (say) one second's
|
||||
// worth of values, calculate the number of peaks that would
|
||||
// qualify for phase locking given the default threshold. Then
|
||||
@@ -74,12 +70,12 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
|
||||
// ensure that their timing is strictly "correct".
|
||||
|
||||
// 4. Calculate how much time is left in the stretch total, after
|
||||
// each of the locked frames has been allocated its static
|
||||
// allowance. Also count the non-locked frames.
|
||||
// each of the locked chunks has been allocated its static
|
||||
// allowance. Also count the non-locked chunks.
|
||||
|
||||
// 5. For each region between two locked frames, calculate the
|
||||
// 5. For each region between two locked chunks, calculate the
|
||||
// number of samples to allocate that region given the time
|
||||
// available for stretch and the number of non-locked frames.
|
||||
// available for stretch and the number of non-locked chunks.
|
||||
// Then divvy them up... how exactly?
|
||||
|
||||
|
||||
@@ -109,11 +105,11 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
|
||||
|
||||
// size_t stretchable = outputDuration - lockCount * m_increment;
|
||||
|
||||
std::vector<size_t> fixedAudioFrames;
|
||||
std::vector<size_t> fixedAudioChunks;
|
||||
for (size_t i = 0; i < peaks.size(); ++i) {
|
||||
fixedAudioFrames.push_back
|
||||
fixedAudioChunks.push_back
|
||||
//!!! this should be rounding down, shouldn't it? not lrint?
|
||||
(lrint((double(peaks[i].frame) * outputDuration) / totalCount));
|
||||
(lrint((double(peaks[i].chunk) * outputDuration) / totalCount));
|
||||
}
|
||||
|
||||
// size_t lockIndex = 0;
|
||||
@@ -125,9 +121,9 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
|
||||
size_t totalInput = 0, totalOutput = 0;
|
||||
|
||||
// so for each inter-lock region, we want to take the number of
|
||||
// output frames to be allocated and the detection function values
|
||||
// output chunks to be allocated and the detection function values
|
||||
// within the range, and produce a series of increments that sum
|
||||
// to the number of output frames, such that each increment is
|
||||
// to the number of output chunks, such that each increment is
|
||||
// displaced from the input increment by an amount inversely
|
||||
// proportional to the magnitude of the detection function at that
|
||||
// input step. Ideally the detection function would have been
|
||||
@@ -136,41 +132,41 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
|
||||
//!!! Actually, we would possibly be better off using a fixed
|
||||
// smooth curve than the detection function itself.
|
||||
|
||||
size_t regionTotalFrames = 0;
|
||||
size_t regionTotalChunks = 0;
|
||||
|
||||
for (size_t i = 0; i <= peaks.size(); ++i) {
|
||||
|
||||
size_t regionStart, regionStartBlock, regionEnd, regionEndBlock;
|
||||
size_t regionStart, regionStartChunk, regionEnd, regionEndChunk;
|
||||
bool phaseLock = false;
|
||||
|
||||
if (i == 0) {
|
||||
regionStartBlock = 0;
|
||||
regionStartChunk = 0;
|
||||
regionStart = 0;
|
||||
} else {
|
||||
regionStartBlock = peaks[i-1].frame;
|
||||
regionStart = fixedAudioFrames[i-1];
|
||||
regionStartChunk = peaks[i-1].chunk;
|
||||
regionStart = fixedAudioChunks[i-1];
|
||||
phaseLock = peaks[i-1].hard;
|
||||
}
|
||||
|
||||
if (i == peaks.size()) {
|
||||
regionEndBlock = totalCount;
|
||||
regionEndChunk = totalCount;
|
||||
regionEnd = outputDuration;
|
||||
} else {
|
||||
regionEndBlock = peaks[i].frame;
|
||||
regionEnd = fixedAudioFrames[i];
|
||||
regionEndChunk = peaks[i].chunk;
|
||||
regionEnd = fixedAudioChunks[i];
|
||||
}
|
||||
|
||||
size_t regionDuration = regionEnd - regionStart;
|
||||
regionTotalFrames += regionDuration;
|
||||
regionTotalChunks += regionDuration;
|
||||
|
||||
std::vector<float> dfRegion;
|
||||
|
||||
for (size_t j = regionStartBlock; j != regionEndBlock; ++j) {
|
||||
for (size_t j = regionStartChunk; j != regionEndChunk; ++j) {
|
||||
dfRegion.push_back(stretchDf[j]);
|
||||
}
|
||||
|
||||
if (m_debugLevel > 1) {
|
||||
std::cerr << "distributeRegion from " << regionStartBlock << " to " << regionEndBlock << " (frames " << regionStart << " to " << regionEnd << ")" << std::endl;
|
||||
std::cerr << "distributeRegion from " << regionStartChunk << " to " << regionEndChunk << " (chunks " << regionStart << " to " << regionEnd << ")" << std::endl;
|
||||
}
|
||||
|
||||
dfRegion = smoothDF(dfRegion);
|
||||
@@ -201,8 +197,8 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
|
||||
}
|
||||
|
||||
if (m_debugLevel > 0) {
|
||||
std::cerr << "total input increment = " << totalInput << " (= " << totalInput / m_increment << " blocks), output = " << totalOutput << ", ratio = " << double(totalOutput)/double(totalInput) << ", ideal output " << ceil(totalInput * ratio) << std::endl;
|
||||
std::cerr << "(region total = " << regionTotalFrames << ")" << std::endl;
|
||||
std::cerr << "total input increment = " << totalInput << " (= " << totalInput / m_increment << " chunks), output = " << totalOutput << ", ratio = " << double(totalOutput)/double(totalInput) << ", ideal output " << ceil(totalInput * ratio) << std::endl;
|
||||
std::cerr << "(region total = " << regionTotalChunks << ")" << std::endl;
|
||||
}
|
||||
return increments;
|
||||
}
|
||||
@@ -215,10 +211,10 @@ StretchCalculator::calculateSingle(double ratio,
|
||||
bool isTransient = false;
|
||||
|
||||
//!!! We want to ensure, as close as possible, that the lock
|
||||
// points appear at _exactly_ the right frame numbers
|
||||
// points appear at _exactly_ the right audio frame numbers
|
||||
|
||||
//!!! depends on block size. larger block sizes need higher
|
||||
//thresholds. since block size depends on ratio, I suppose we
|
||||
//!!! depends on chunk size. larger chunk sizes need higher
|
||||
//thresholds. since chunk size depends on ratio, I suppose we
|
||||
//could in theory calculate the threshold from the ratio directly.
|
||||
//For now we just frig it to work OK for a couple of common cases
|
||||
float transientThreshold = 0.35;
|
||||
@@ -306,7 +302,7 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
|
||||
std::cerr << "hardPeakAmnesty = " << hardPeakAmnesty << std::endl;
|
||||
for (size_t i = 1; i + 1 < df.size(); ++i) {
|
||||
|
||||
//!!! this ratio configurable? dependent on block size and sr?
|
||||
//!!! this ratio configurable? dependent on chunk size and sr?
|
||||
|
||||
if (df[i] < 0.1) continue;
|
||||
if (df[i] <= df[i-1] * 1.2) continue;
|
||||
@@ -518,14 +514,14 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
|
||||
size_t softPeak = (haveSoftPeak ? *softPeakCandidates.begin() : 0);
|
||||
Peak peak;
|
||||
peak.hard = false;
|
||||
peak.frame = softPeak;
|
||||
peak.chunk = softPeak;
|
||||
if (haveHardPeak &&
|
||||
(!haveSoftPeak || hardPeak <= softPeak)) {
|
||||
if (m_debugLevel > 2) {
|
||||
std::cerr << "Hard peak: " << hardPeak << std::endl;
|
||||
}
|
||||
peak.hard = true;
|
||||
peak.frame = hardPeak;
|
||||
peak.chunk = hardPeak;
|
||||
hardPeakCandidates.erase(hardPeakCandidates.begin());
|
||||
} else {
|
||||
if (m_debugLevel > 2) {
|
||||
@@ -533,7 +529,7 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
|
||||
}
|
||||
}
|
||||
|
||||
if (haveSoftPeak && peak.frame == softPeak) {
|
||||
if (haveSoftPeak && peak.chunk == softPeak) {
|
||||
softPeakCandidates.erase(softPeakCandidates.begin());
|
||||
}
|
||||
|
||||
@@ -616,7 +612,7 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
|
||||
// bool negative = (toAllot < 0);
|
||||
|
||||
if (m_debugLevel > 1) {
|
||||
std::cerr << "region of " << df.size() << " blocks, output duration " << duration << ", toAllot " << toAllot << std::endl;
|
||||
std::cerr << "region of " << df.size() << " chunks, output duration " << duration << ", toAllot " << toAllot << std::endl;
|
||||
}
|
||||
|
||||
size_t totalIncrement = 0;
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
void setDebugLevel(int level) { m_debugLevel = level; }
|
||||
|
||||
struct Peak {
|
||||
size_t frame;
|
||||
size_t chunk;
|
||||
bool hard;
|
||||
};
|
||||
std::vector<Peak> getLastCalculatedPeaks() const { return m_lastPeaks; }
|
||||
|
||||
@@ -7,39 +7,39 @@
|
||||
namespace RubberBand
|
||||
{
|
||||
|
||||
RubberBandStretcher::Impl::ChannelData::ChannelData(size_t blockSize,
|
||||
RubberBandStretcher::Impl::ChannelData::ChannelData(size_t windowSize,
|
||||
size_t outbufSize)
|
||||
{
|
||||
std::set<size_t> s;
|
||||
construct(s, blockSize, outbufSize);
|
||||
construct(s, windowSize, outbufSize);
|
||||
}
|
||||
|
||||
RubberBandStretcher::Impl::ChannelData::ChannelData(const std::set<size_t> &blockSizes,
|
||||
size_t initialBlockSize,
|
||||
RubberBandStretcher::Impl::ChannelData::ChannelData(const std::set<size_t> &windowSizes,
|
||||
size_t initialWindowSize,
|
||||
size_t outbufSize)
|
||||
{
|
||||
construct(blockSizes, initialBlockSize, outbufSize);
|
||||
construct(windowSizes, initialWindowSize, outbufSize);
|
||||
}
|
||||
|
||||
void
|
||||
RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &blockSizes,
|
||||
size_t initialBlockSize,
|
||||
RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &windowSizes,
|
||||
size_t initialWindowSize,
|
||||
size_t outbufSize)
|
||||
{
|
||||
size_t maxSize = initialBlockSize;
|
||||
size_t maxSize = initialWindowSize;
|
||||
|
||||
if (!blockSizes.empty()) {
|
||||
if (!windowSizes.empty()) {
|
||||
// std::set is ordered by value
|
||||
std::set<size_t>::const_iterator i = blockSizes.end();
|
||||
std::set<size_t>::const_iterator i = windowSizes.end();
|
||||
maxSize = *--i;
|
||||
}
|
||||
if (blockSizes.find(initialBlockSize) == blockSizes.end()) {
|
||||
if (initialBlockSize > maxSize) maxSize = initialBlockSize;
|
||||
if (windowSizes.find(initialWindowSize) == windowSizes.end()) {
|
||||
if (initialWindowSize > maxSize) maxSize = initialWindowSize;
|
||||
}
|
||||
|
||||
size_t realSize = maxSize/2 + 1; // size of the real "half" of freq data
|
||||
|
||||
std::cerr << "ChannelData::construct([" << blockSizes.size() << "], " << maxSize << ", " << outbufSize << ")" << std::endl;
|
||||
std::cerr << "ChannelData::construct([" << windowSizes.size() << "], " << maxSize << ", " << outbufSize << ")" << std::endl;
|
||||
|
||||
if (outbufSize < maxSize) outbufSize = maxSize;
|
||||
|
||||
@@ -58,16 +58,16 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &blockS
|
||||
fltbuf = new float[maxSize];
|
||||
dblbuf = new double[maxSize];
|
||||
|
||||
for (std::set<size_t>::const_iterator i = blockSizes.begin();
|
||||
i != blockSizes.end(); ++i) {
|
||||
for (std::set<size_t>::const_iterator i = windowSizes.begin();
|
||||
i != windowSizes.end(); ++i) {
|
||||
ffts[*i] = new FFT(*i);
|
||||
ffts[*i]->initDouble();
|
||||
}
|
||||
if (blockSizes.find(initialBlockSize) == blockSizes.end()) {
|
||||
ffts[initialBlockSize] = new FFT(initialBlockSize);
|
||||
ffts[initialBlockSize]->initDouble();
|
||||
if (windowSizes.find(initialWindowSize) == windowSizes.end()) {
|
||||
ffts[initialWindowSize] = new FFT(initialWindowSize);
|
||||
ffts[initialWindowSize]->initDouble();
|
||||
}
|
||||
fft = ffts[initialBlockSize];
|
||||
fft = ffts[initialWindowSize];
|
||||
|
||||
resampler = 0;
|
||||
resamplebuf = 0;
|
||||
@@ -92,14 +92,14 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &blockS
|
||||
}
|
||||
|
||||
void
|
||||
RubberBandStretcher::Impl::ChannelData::setBlockSize(size_t blockSize)
|
||||
RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
|
||||
{
|
||||
size_t oldSize = inbuf->getSize();
|
||||
size_t realSize = blockSize/2 + 1;
|
||||
size_t realSize = windowSize/2 + 1;
|
||||
|
||||
std::cerr << "ChannelData::setBlockSize(" << blockSize << ") [from " << oldSize << "]" << std::endl;
|
||||
std::cerr << "ChannelData::setWindowSize(" << windowSize << ") [from " << oldSize << "]" << std::endl;
|
||||
|
||||
if (oldSize >= blockSize) {
|
||||
if (oldSize >= windowSize) {
|
||||
|
||||
// no need to reallocate buffers, just reselect fft
|
||||
|
||||
@@ -107,14 +107,14 @@ RubberBandStretcher::Impl::ChannelData::setBlockSize(size_t blockSize)
|
||||
//process thread, can we? we need to zero the mag/phase
|
||||
//buffers without interference
|
||||
|
||||
if (ffts.find(blockSize) == ffts.end()) {
|
||||
if (ffts.find(windowSize) == ffts.end()) {
|
||||
//!!! this also requires a lock, but it shouldn't occur in
|
||||
//RT mode with proper initialisation
|
||||
ffts[blockSize] = new FFT(blockSize);
|
||||
ffts[blockSize]->initDouble();
|
||||
ffts[windowSize] = new FFT(windowSize);
|
||||
ffts[windowSize]->initDouble();
|
||||
}
|
||||
|
||||
fft = ffts[blockSize];
|
||||
fft = ffts[windowSize];
|
||||
|
||||
for (size_t i = 0; i < realSize; ++i) {
|
||||
mag[i] = 0.0;
|
||||
@@ -134,7 +134,7 @@ RubberBandStretcher::Impl::ChannelData::setBlockSize(size_t blockSize)
|
||||
//is unavailable (since this should never normally be the case in
|
||||
//general use in RT mode)
|
||||
|
||||
RingBuffer<float> *newbuf = inbuf->resized(blockSize);
|
||||
RingBuffer<float> *newbuf = inbuf->resized(windowSize);
|
||||
delete inbuf;
|
||||
inbuf = newbuf;
|
||||
|
||||
@@ -155,17 +155,17 @@ RubberBandStretcher::Impl::ChannelData::setBlockSize(size_t blockSize)
|
||||
delete[] fltbuf;
|
||||
delete[] dblbuf;
|
||||
|
||||
fltbuf = new float[blockSize];
|
||||
dblbuf = new double[blockSize];
|
||||
fltbuf = new float[windowSize];
|
||||
dblbuf = new double[windowSize];
|
||||
|
||||
// But we do want to preserve data in these
|
||||
|
||||
float *newAcc = new float[blockSize];
|
||||
float *newAcc = new float[windowSize];
|
||||
for (size_t i = 0; i < oldSize; ++i) newAcc[i] = accumulator[i];
|
||||
delete[] accumulator;
|
||||
accumulator = newAcc;
|
||||
|
||||
newAcc = new float[blockSize];
|
||||
newAcc = new float[windowSize];
|
||||
for (size_t i = 0; i < oldSize; ++i) newAcc[i] = windowAccumulator[i];
|
||||
delete[] windowAccumulator;
|
||||
windowAccumulator = newAcc;
|
||||
@@ -180,22 +180,22 @@ RubberBandStretcher::Impl::ChannelData::setBlockSize(size_t blockSize)
|
||||
freqPeak[i] = 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < blockSize; ++i) {
|
||||
for (size_t i = 0; i < windowSize; ++i) {
|
||||
dblbuf[i] = 0.0;
|
||||
fltbuf[i] = 0.0;
|
||||
}
|
||||
|
||||
for (size_t i = oldSize; i < blockSize; ++i) {
|
||||
for (size_t i = oldSize; i < windowSize; ++i) {
|
||||
accumulator[i] = 0.f;
|
||||
windowAccumulator[i] = 0.f;
|
||||
}
|
||||
|
||||
if (ffts.find(blockSize) == ffts.end()) {
|
||||
ffts[blockSize] = new FFT(blockSize);
|
||||
ffts[blockSize]->initDouble();
|
||||
if (ffts.find(windowSize) == ffts.end()) {
|
||||
ffts[windowSize] = new FFT(windowSize);
|
||||
ffts[windowSize]->initDouble();
|
||||
}
|
||||
|
||||
fft = ffts[blockSize];
|
||||
fft = ffts[windowSize];
|
||||
}
|
||||
|
||||
void
|
||||
@@ -253,7 +253,7 @@ RubberBandStretcher::Impl::ChannelData::reset()
|
||||
|
||||
accumulatorFill = 0;
|
||||
prevIncrement = 0;
|
||||
blockCount = 0;
|
||||
chunkCount = 0;
|
||||
inCount = 0;
|
||||
inputSize = -1;
|
||||
outCount = 0;
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
/**
|
||||
* Construct a ChannelData structure.
|
||||
*
|
||||
* The block size passed in here is the size for the FFT
|
||||
* The window size passed in here is the size for the FFT
|
||||
* calculation, and most of the buffer sizes also depend on
|
||||
* it. In practice it is always a power of two and except for
|
||||
* very extreme stretches is always either 1024, 2048 or 4096.
|
||||
@@ -39,22 +39,22 @@ public:
|
||||
* the pitch scale factor and any maximum processing block
|
||||
* size specified by the user of the code.
|
||||
*/
|
||||
ChannelData(size_t blockSize, size_t outbufSize);
|
||||
ChannelData(size_t windowSize, size_t outbufSize);
|
||||
|
||||
/**
|
||||
* Construct a ChannelData structure that can process at
|
||||
* different FFT sizes without requiring reallocation when the
|
||||
* size changes. The size can subsequently be changed with a
|
||||
* call to setBlockSize. Reallocation will only be necessary
|
||||
* if setBlockSize is called with a value not equal to one of
|
||||
* call to setWindowSize. Reallocation will only be necessary
|
||||
* if setWindowSize is called with a value not equal to one of
|
||||
* those passed in to the constructor.
|
||||
*
|
||||
* The outbufSize should be the maximum possible outbufSize to
|
||||
* avoid reallocation, which will happen if setOutbufSize is
|
||||
* called subsequently.
|
||||
*/
|
||||
ChannelData(const std::set<size_t> &blockSizes,
|
||||
size_t initialBlockSize, size_t outbufSize);
|
||||
ChannelData(const std::set<size_t> &windowSizes,
|
||||
size_t initialWindowSize, size_t outbufSize);
|
||||
~ChannelData();
|
||||
|
||||
/**
|
||||
@@ -64,11 +64,11 @@ public:
|
||||
|
||||
/**
|
||||
* Set the FFT and buffer sizes from the given processing
|
||||
* block size. If this ChannelData was constructed with a set
|
||||
* of block sizes and the given block size here was among
|
||||
* window size. If this ChannelData was constructed with a set
|
||||
* of window sizes and the given window size here was among
|
||||
* them, no reallocation will be required.
|
||||
*/
|
||||
void setBlockSize(size_t blockSize);
|
||||
void setWindowSize(size_t windowSize);
|
||||
|
||||
/**
|
||||
* Set the outbufSize for the channel data. Reallocation will
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
|
||||
size_t prevIncrement; // only used in RT mode
|
||||
|
||||
size_t blockCount;
|
||||
size_t chunkCount;
|
||||
size_t inCount;
|
||||
long inputSize; // set only after known (when data ended); -1 previously
|
||||
size_t outCount;
|
||||
@@ -112,8 +112,8 @@ public:
|
||||
size_t resamplebufSize;
|
||||
|
||||
private:
|
||||
void construct(const std::set<size_t> &blockSizes,
|
||||
size_t initialBlockSize, size_t outbufSize);
|
||||
void construct(const std::set<size_t> &windowSizes,
|
||||
size_t initialWindowSize, size_t outbufSize);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ using std::min;
|
||||
namespace RubberBand {
|
||||
|
||||
static const size_t defaultIncrement = 256;
|
||||
static const size_t defaultBlockSize = 2048;
|
||||
static const size_t defaultWindowSize = 2048;
|
||||
|
||||
RubberBandStretcher::Impl::Impl(RubberBandStretcher *stretcher,
|
||||
size_t sampleRate,
|
||||
@@ -48,10 +48,10 @@ RubberBandStretcher::Impl::Impl(RubberBandStretcher *stretcher,
|
||||
m_channels(channels),
|
||||
m_timeRatio(initialTimeRatio),
|
||||
m_pitchScale(initialPitchScale),
|
||||
m_blockSize(defaultBlockSize),
|
||||
m_outbufSize(defaultBlockSize * 2),
|
||||
m_windowSize(defaultWindowSize),
|
||||
m_increment(defaultIncrement),
|
||||
m_maxProcessBlockSize(defaultBlockSize),
|
||||
m_outbufSize(defaultWindowSize * 2),
|
||||
m_maxProcessSize(defaultWindowSize),
|
||||
m_expectedInputDuration(0),
|
||||
m_threaded(false),
|
||||
m_realtime(false),
|
||||
@@ -69,7 +69,7 @@ RubberBandStretcher::Impl::Impl(RubberBandStretcher *stretcher,
|
||||
m_freq0(600),
|
||||
m_freq1(1200),
|
||||
m_freq2(12000),
|
||||
m_baseBlockSize(defaultBlockSize)
|
||||
m_baseWindowSize(defaultWindowSize)
|
||||
{
|
||||
cerr << "RubberBandStretcher::Impl::Impl: options = " << options << endl;
|
||||
|
||||
@@ -77,15 +77,15 @@ RubberBandStretcher::Impl::Impl(RubberBandStretcher *stretcher,
|
||||
if ((options & OptionWindowShort) && (options & OptionWindowLong)) {
|
||||
cerr << "RubberBandStretcher::Impl::Impl: Cannot specify OptionWindowLong and OptionWindowShort together; falling back to OptionWindowStandard" << endl;
|
||||
} else if (options & OptionWindowShort) {
|
||||
m_baseBlockSize = defaultBlockSize / 2;
|
||||
cerr << "setting baseBlockSize to " << m_baseBlockSize << endl;
|
||||
m_baseWindowSize = defaultWindowSize / 2;
|
||||
cerr << "setting baseWindowSize to " << m_baseWindowSize << endl;
|
||||
} else if (options & OptionWindowLong) {
|
||||
m_baseBlockSize = defaultBlockSize * 2;
|
||||
cerr << "setting baseBlockSize to " << m_baseBlockSize << endl;
|
||||
m_baseWindowSize = defaultWindowSize * 2;
|
||||
cerr << "setting baseWindowSize to " << m_baseWindowSize << endl;
|
||||
}
|
||||
m_blockSize = m_baseBlockSize;
|
||||
m_outbufSize = m_baseBlockSize * 2;
|
||||
m_maxProcessBlockSize = m_baseBlockSize;
|
||||
m_windowSize = m_baseWindowSize;
|
||||
m_outbufSize = m_baseWindowSize * 2;
|
||||
m_maxProcessSize = m_baseWindowSize;
|
||||
}
|
||||
|
||||
if (m_options & OptionProcessRealTime) {
|
||||
@@ -154,7 +154,7 @@ RubberBandStretcher::Impl::reset()
|
||||
|
||||
for (size_t c = 0; c < m_channels; ++c) {
|
||||
delete m_channelData[c];
|
||||
m_channelData[c] = new ChannelData(m_blockSize, m_outbufSize);
|
||||
m_channelData[c] = new ChannelData(m_windowSize, m_outbufSize);
|
||||
}
|
||||
m_mode = JustCreated;
|
||||
if (m_lockAudioCurve) m_lockAudioCurve->reset();
|
||||
@@ -219,10 +219,10 @@ RubberBandStretcher::Impl::setExpectedInputDuration(size_t samples)
|
||||
}
|
||||
|
||||
void
|
||||
RubberBandStretcher::Impl::setMaxProcessBlockSize(size_t samples)
|
||||
RubberBandStretcher::Impl::setMaxProcessSize(size_t samples)
|
||||
{
|
||||
if (samples <= m_maxProcessBlockSize) return;
|
||||
m_maxProcessBlockSize = samples;
|
||||
if (samples <= m_maxProcessSize) return;
|
||||
m_maxProcessSize = samples;
|
||||
|
||||
reconfigure();
|
||||
}
|
||||
@@ -279,7 +279,7 @@ void
|
||||
RubberBandStretcher::Impl::calculateSizes()
|
||||
{
|
||||
size_t inputIncrement = defaultIncrement;
|
||||
size_t blockSize = m_baseBlockSize;
|
||||
size_t windowSize = m_baseWindowSize;
|
||||
size_t outputIncrement;
|
||||
|
||||
double r = getEffectiveRatio();
|
||||
@@ -295,7 +295,7 @@ RubberBandStretcher::Impl::calculateSizes()
|
||||
if (outputIncrement < 1) {
|
||||
outputIncrement = 1;
|
||||
inputIncrement = roundUp(lrint(ceil(outputIncrement / r)));
|
||||
blockSize = inputIncrement * 4;
|
||||
windowSize = inputIncrement * 4;
|
||||
}
|
||||
} else {
|
||||
outputIncrement = int(ceil(inputIncrement * r));
|
||||
@@ -303,8 +303,8 @@ RubberBandStretcher::Impl::calculateSizes()
|
||||
inputIncrement /= 2;
|
||||
outputIncrement = lrint(ceil(inputIncrement * r));
|
||||
}
|
||||
blockSize = std::max(blockSize, roundUp(outputIncrement * 6));
|
||||
if (r > 5) while (blockSize < 8192) blockSize *= 2;
|
||||
windowSize = std::max(windowSize, roundUp(outputIncrement * 6));
|
||||
if (r > 5) while (windowSize < 8192) windowSize *= 2;
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -312,23 +312,23 @@ RubberBandStretcher::Impl::calculateSizes()
|
||||
// use a variable increment
|
||||
|
||||
if (r < 1) {
|
||||
inputIncrement = blockSize / 4;
|
||||
inputIncrement = windowSize / 4;
|
||||
while (inputIncrement >= 512) inputIncrement /= 2;
|
||||
outputIncrement = int(floor(inputIncrement * r));
|
||||
if (outputIncrement < 1) {
|
||||
outputIncrement = 1;
|
||||
inputIncrement = roundUp(lrint(ceil(outputIncrement / r)));
|
||||
blockSize = inputIncrement * 4;
|
||||
windowSize = inputIncrement * 4;
|
||||
}
|
||||
} else {
|
||||
outputIncrement = blockSize / 6;
|
||||
outputIncrement = windowSize / 6;
|
||||
inputIncrement = int(outputIncrement / r);
|
||||
while (outputIncrement > 1024 && inputIncrement > 1) {
|
||||
outputIncrement /= 2;
|
||||
inputIncrement = int(outputIncrement / r);
|
||||
}
|
||||
blockSize = std::max(blockSize, roundUp(outputIncrement * 6));
|
||||
if (r > 5) while (blockSize < 8192) blockSize *= 2;
|
||||
windowSize = std::max(windowSize, roundUp(outputIncrement * 6));
|
||||
if (r > 5) while (windowSize < 8192) windowSize *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,10 +339,10 @@ RubberBandStretcher::Impl::calculateSizes()
|
||||
}
|
||||
}
|
||||
|
||||
// blockSize can be almost anything, but it can't be greater than
|
||||
// 4 * defaultBlockSize unless ratio is less than 1/1024.
|
||||
// windowSize can be almost anything, but it can't be greater than
|
||||
// 4 * defaultWindowSize unless ratio is less than 1/1024.
|
||||
|
||||
m_blockSize = blockSize;
|
||||
m_windowSize = windowSize;
|
||||
m_increment = inputIncrement;
|
||||
|
||||
// When squashing, the greatest theoretically possible output
|
||||
@@ -350,29 +350,29 @@ RubberBandStretcher::Impl::calculateSizes()
|
||||
// the sky's the limit in principle, but we expect
|
||||
// StretchCalculator to restrict itself to using no more than
|
||||
// twice the basic output increment (i.e. input increment times
|
||||
// ratio) for any block.
|
||||
// ratio) for any chunk.
|
||||
|
||||
if (m_debugLevel > 0) {
|
||||
cerr << "configure: effective ratio = " << getEffectiveRatio() << endl;
|
||||
cerr << "configure: block size = " << m_blockSize << ", increment = " << m_increment << " (approx output increment = " << int(lrint(m_increment * getEffectiveRatio())) << ")" << endl;
|
||||
cerr << "configure: window size = " << m_windowSize << ", increment = " << m_increment << " (approx output increment = " << int(lrint(m_increment * getEffectiveRatio())) << ")" << endl;
|
||||
}
|
||||
|
||||
static size_t maxBlockSize = 0;
|
||||
static size_t maxWindowSize = 0;
|
||||
|
||||
if (m_blockSize > maxBlockSize) {
|
||||
if (m_windowSize > maxWindowSize) {
|
||||
//!!!
|
||||
cerr << "configure: NOTE: max block size so far increased from "
|
||||
<< maxBlockSize << " to " << m_blockSize << endl;
|
||||
maxBlockSize = m_blockSize;
|
||||
cerr << "configure: NOTE: max window size so far increased from "
|
||||
<< maxWindowSize << " to " << m_windowSize << endl;
|
||||
maxWindowSize = m_windowSize;
|
||||
}
|
||||
|
||||
if (m_blockSize > m_maxProcessBlockSize) {
|
||||
m_maxProcessBlockSize = m_blockSize;
|
||||
if (m_windowSize > m_maxProcessSize) {
|
||||
m_maxProcessSize = m_windowSize;
|
||||
}
|
||||
|
||||
m_outbufSize = max
|
||||
(size_t(ceil(m_maxProcessBlockSize / m_pitchScale)),
|
||||
m_blockSize);
|
||||
(size_t(ceil(m_maxProcessSize / m_pitchScale)),
|
||||
m_windowSize);
|
||||
|
||||
if (m_realtime) {
|
||||
// This headroom is so as to try to avoid reallocation when
|
||||
@@ -391,7 +391,7 @@ RubberBandStretcher::Impl::calculateSizes()
|
||||
//!!! for very long stretches (e.g. x5), this is necessary; for
|
||||
//even longer ones (e.g. x10), even more of an outbuf is
|
||||
//necessary. clearly something wrong in our calculations... or do
|
||||
//we just need to ensure client calls setMaxProcessBlockSize?
|
||||
//we just need to ensure client calls setMaxProcessSize?
|
||||
if (!m_realtime && !m_threaded) {
|
||||
m_outbufSize = m_outbufSize * 2;
|
||||
}
|
||||
@@ -400,16 +400,16 @@ RubberBandStretcher::Impl::calculateSizes()
|
||||
void
|
||||
RubberBandStretcher::Impl::configure()
|
||||
{
|
||||
size_t prevBlockSize = m_blockSize;
|
||||
size_t prevWindowSize = m_windowSize;
|
||||
size_t prevOutbufSize = m_outbufSize;
|
||||
if (m_windows.empty()) {
|
||||
prevBlockSize = 0;
|
||||
prevWindowSize = 0;
|
||||
prevOutbufSize = 0;
|
||||
}
|
||||
|
||||
calculateSizes();
|
||||
|
||||
bool blockSizeChanged = (prevBlockSize != m_blockSize);
|
||||
bool windowSizeChanged = (prevWindowSize != m_windowSize);
|
||||
bool outbufSizeChanged = (prevOutbufSize != m_outbufSize);
|
||||
|
||||
// This function may be called at any time in non-RT mode, after a
|
||||
@@ -420,30 +420,30 @@ RubberBandStretcher::Impl::configure()
|
||||
// mode. After that reconfigure() does the work in a hopefully
|
||||
// RT-safe way.
|
||||
|
||||
set<size_t> blockSizes;
|
||||
set<size_t> windowSizes;
|
||||
if (m_realtime) {
|
||||
blockSizes.insert(m_baseBlockSize);
|
||||
blockSizes.insert(m_baseBlockSize * 2);
|
||||
blockSizes.insert(m_baseBlockSize * 4);
|
||||
windowSizes.insert(m_baseWindowSize);
|
||||
windowSizes.insert(m_baseWindowSize * 2);
|
||||
windowSizes.insert(m_baseWindowSize * 4);
|
||||
}
|
||||
blockSizes.insert(m_blockSize);
|
||||
windowSizes.insert(m_windowSize);
|
||||
|
||||
if (blockSizeChanged) {
|
||||
if (windowSizeChanged) {
|
||||
|
||||
for (set<size_t>::const_iterator i = blockSizes.begin();
|
||||
i != blockSizes.end(); ++i) {
|
||||
for (set<size_t>::const_iterator i = windowSizes.begin();
|
||||
i != windowSizes.end(); ++i) {
|
||||
if (m_windows.find(*i) == m_windows.end()) {
|
||||
m_windows[*i] = new Window<float>(HanningWindow, *i);
|
||||
}
|
||||
}
|
||||
m_window = m_windows[m_blockSize];
|
||||
m_window = m_windows[m_windowSize];
|
||||
|
||||
if (m_debugLevel > 0) {
|
||||
cerr << "Window area: " << m_window->getArea() << "; synthesis window area: " << m_window->getArea() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (blockSizeChanged || outbufSizeChanged) {
|
||||
if (windowSizeChanged || outbufSizeChanged) {
|
||||
|
||||
for (size_t c = 0; c < m_channelData.size(); ++c) {
|
||||
delete m_channelData[c];
|
||||
@@ -452,13 +452,13 @@ RubberBandStretcher::Impl::configure()
|
||||
|
||||
for (size_t c = 0; c < m_channels; ++c) {
|
||||
m_channelData.push_back
|
||||
(new ChannelData(blockSizes, m_blockSize, m_outbufSize));
|
||||
(new ChannelData(windowSizes, m_windowSize, m_outbufSize));
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_realtime && blockSizeChanged) {
|
||||
if (!m_realtime && windowSizeChanged) {
|
||||
delete m_studyFFT;
|
||||
m_studyFFT = new FFT(m_blockSize);
|
||||
m_studyFFT = new FFT(m_windowSize);
|
||||
m_studyFFT->initFloat();
|
||||
}
|
||||
|
||||
@@ -480,7 +480,7 @@ RubberBandStretcher::Impl::configure()
|
||||
|
||||
delete m_lockAudioCurve;
|
||||
m_lockAudioCurve = new PercussiveAudioCurve(m_stretcher->m_sampleRate,
|
||||
m_blockSize);
|
||||
m_windowSize);
|
||||
|
||||
// stretchAudioCurve unused in RT mode; lockAudioCurve and
|
||||
// stretchCalculator however are used in all modes
|
||||
@@ -491,10 +491,10 @@ RubberBandStretcher::Impl::configure()
|
||||
//!!! probably adaptively-whitened spectral difference curve
|
||||
//would be better
|
||||
m_stretchAudioCurve = new HighFrequencyAudioCurve
|
||||
(m_stretcher->m_sampleRate, m_blockSize);
|
||||
(m_stretcher->m_sampleRate, m_windowSize);
|
||||
} else {
|
||||
m_stretchAudioCurve = new ConstantAudioCurve
|
||||
(m_stretcher->m_sampleRate, m_blockSize);
|
||||
(m_stretcher->m_sampleRate, m_windowSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,11 +506,11 @@ RubberBandStretcher::Impl::configure()
|
||||
m_stretchCalculator->setDebugLevel(m_debugLevel);
|
||||
m_inputDuration = 0;
|
||||
|
||||
// Prepare the inbufs with half a block of emptiness. The centre
|
||||
// point of the first processing block for the onset detector
|
||||
// Prepare the inbufs with half a chunk of emptiness. The centre
|
||||
// point of the first processing chunk for the onset detector
|
||||
// should be the first sample of the audio, and we continue until
|
||||
// we can no longer centre a block within the input audio. The
|
||||
// number of onset detector blocks will be the number of audio
|
||||
// we can no longer centre a chunk within the input audio. The
|
||||
// number of onset detector chunks will be the number of audio
|
||||
// samples input, divided by the input increment, plus one.
|
||||
|
||||
// In real-time mode, we don't do this prefill -- it's better to
|
||||
@@ -520,7 +520,7 @@ RubberBandStretcher::Impl::configure()
|
||||
if (!m_realtime) {
|
||||
for (size_t c = 0; c < m_channels; ++c) {
|
||||
m_channelData[c]->reset();
|
||||
m_channelData[c]->inbuf->zero(m_blockSize/2);
|
||||
m_channelData[c]->inbuf->zero(m_windowSize/2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -543,7 +543,7 @@ RubberBandStretcher::Impl::reconfigure()
|
||||
configure();
|
||||
}
|
||||
|
||||
size_t prevBlockSize = m_blockSize;
|
||||
size_t prevWindowSize = m_windowSize;
|
||||
size_t prevOutbufSize = m_outbufSize;
|
||||
|
||||
calculateSizes();
|
||||
@@ -553,18 +553,18 @@ RubberBandStretcher::Impl::reconfigure()
|
||||
// where not all of the things we need were correctly created when
|
||||
// we first configured (for whatever reason). This is intended to
|
||||
// be "effectively" realtime safe. The same goes for
|
||||
// ChannelData::setOutbufSize and setBlockSize.
|
||||
// ChannelData::setOutbufSize and setWindowSize.
|
||||
|
||||
if (m_blockSize != prevBlockSize) {
|
||||
if (m_windowSize != prevWindowSize) {
|
||||
|
||||
if (m_windows.find(m_blockSize) == m_windows.end()) {
|
||||
std::cerr << "WARNING: reconfigure(): window allocation (size " << m_blockSize << ") required in RT mode" << std::endl;
|
||||
m_windows[m_blockSize] = new Window<float>(HanningWindow, m_blockSize);
|
||||
if (m_windows.find(m_windowSize) == m_windows.end()) {
|
||||
std::cerr << "WARNING: reconfigure(): window allocation (size " << m_windowSize << ") required in RT mode" << std::endl;
|
||||
m_windows[m_windowSize] = new Window<float>(HanningWindow, m_windowSize);
|
||||
}
|
||||
m_window = m_windows[m_blockSize];
|
||||
m_window = m_windows[m_windowSize];
|
||||
|
||||
for (size_t c = 0; c < m_channels; ++c) {
|
||||
m_channelData[c]->setBlockSize(m_blockSize);
|
||||
m_channelData[c]->setWindowSize(m_windowSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -582,7 +582,7 @@ RubberBandStretcher::Impl::reconfigure()
|
||||
std::cerr << "WARNING: reconfigure(): resampler construction required in RT mode" << std::endl;
|
||||
|
||||
m_channelData[c]->resampler =
|
||||
new Resampler(Resampler::FastestTolerable, 1, m_blockSize);
|
||||
new Resampler(Resampler::FastestTolerable, 1, m_windowSize);
|
||||
|
||||
m_channelData[c]->resamplebufSize =
|
||||
lrintf(ceil((m_increment * m_timeRatio * 2) / m_pitchScale));
|
||||
@@ -591,8 +591,8 @@ RubberBandStretcher::Impl::reconfigure()
|
||||
}
|
||||
}
|
||||
|
||||
if (m_blockSize != prevBlockSize) {
|
||||
m_lockAudioCurve->setBlockSize(m_blockSize);
|
||||
if (m_windowSize != prevWindowSize) {
|
||||
m_lockAudioCurve->setWindowSize(m_windowSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -600,7 +600,7 @@ size_t
|
||||
RubberBandStretcher::Impl::getLatency() const
|
||||
{
|
||||
if (!m_realtime) return 0;
|
||||
return int((m_blockSize/2) / m_pitchScale + 1);
|
||||
return int((m_windowSize/2) / m_pitchScale + 1);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -684,22 +684,19 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
|
||||
consumed += writable;
|
||||
}
|
||||
|
||||
while ((inbuf.getReadSpace() >= m_blockSize) ||
|
||||
(final && (inbuf.getReadSpace() >= m_blockSize/2))) {
|
||||
while ((inbuf.getReadSpace() >= m_windowSize) ||
|
||||
(final && (inbuf.getReadSpace() >= m_windowSize/2))) {
|
||||
|
||||
//!!! inconsistency throughout -- we are using "blocksize",
|
||||
// but "chunk" instead of "block"
|
||||
|
||||
// We know we have at least m_blockSize samples available
|
||||
// in m_inbuf. We need to peek m_blockSize of them for
|
||||
// We know we have at least m_windowSize samples available
|
||||
// in m_inbuf. We need to peek m_windowSize of them for
|
||||
// processing, and then skip m_increment to advance the
|
||||
// read pointer.
|
||||
|
||||
// cd.accumulator is not otherwise used during studying,
|
||||
// so we can use it as a temporary buffer here
|
||||
|
||||
size_t got = inbuf.peek(cd.accumulator, m_blockSize);
|
||||
assert(final || got == m_blockSize);
|
||||
size_t got = inbuf.peek(cd.accumulator, m_windowSize);
|
||||
assert(final || got == m_windowSize);
|
||||
|
||||
m_window->cut(cd.accumulator);
|
||||
|
||||
@@ -718,8 +715,8 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
|
||||
|
||||
// cout << df << endl;
|
||||
|
||||
// We have augmented the input by m_blockSize/2 so
|
||||
// that the first block is centred on the first audio
|
||||
// We have augmented the input by m_windowSize/2 so
|
||||
// that the first chunk is centred on the first audio
|
||||
// sample. We want to ensure that m_inputDuration
|
||||
// contains the exact input duration without including
|
||||
// this extra bit. We just add up all the increments
|
||||
@@ -736,8 +733,8 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
|
||||
m_inputDuration += rs;
|
||||
// cerr << "incr input duration by read space: " << rs << " -> " << m_inputDuration << endl;
|
||||
|
||||
if (m_inputDuration > m_blockSize/2) { // deducting the extra
|
||||
m_inputDuration -= m_blockSize/2;
|
||||
if (m_inputDuration > m_windowSize/2) { // deducting the extra
|
||||
m_inputDuration -= m_windowSize/2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -780,7 +777,7 @@ RubberBandStretcher::Impl::getExactTimePoints() const
|
||||
std::vector<StretchCalculator::Peak> peaks =
|
||||
m_stretchCalculator->getLastCalculatedPeaks();
|
||||
for (size_t i = 0; i < peaks.size(); ++i) {
|
||||
points.push_back(peaks[i].frame);
|
||||
points.push_back(peaks[i].chunk);
|
||||
}
|
||||
}
|
||||
return points;
|
||||
@@ -828,16 +825,16 @@ RubberBandStretcher::Impl::getSamplesRequired() const
|
||||
|
||||
// See notes in testInbufReadSpace below
|
||||
|
||||
if (rs < m_blockSize && !cd.draining) {
|
||||
if (rs < m_windowSize && !cd.draining) {
|
||||
|
||||
if (cd.inputSize == -1) {
|
||||
reqdHere = m_blockSize - rs;
|
||||
reqdHere = m_windowSize - rs;
|
||||
if (reqdHere > reqd) reqd = reqdHere;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rs == 0) {
|
||||
reqdHere = m_blockSize;
|
||||
reqdHere = m_windowSize;
|
||||
if (reqdHere > reqd) reqd = reqdHere;
|
||||
continue;
|
||||
}
|
||||
@@ -851,7 +848,7 @@ void
|
||||
RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bool final)
|
||||
{
|
||||
if (m_mode == Finished) {
|
||||
cerr << "RubberBandStretcher::Impl::process: Cannot process again after final block" << endl;
|
||||
cerr << "RubberBandStretcher::Impl::process: Cannot process again after final chunk" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -866,7 +863,7 @@ RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bo
|
||||
|
||||
for (size_t c = 0; c < m_channels; ++c) {
|
||||
m_channelData[c]->reset();
|
||||
m_channelData[c]->inbuf->zero(m_blockSize/2);
|
||||
m_channelData[c]->inbuf->zero(m_windowSize/2);
|
||||
}
|
||||
|
||||
if (m_threaded) {
|
||||
@@ -945,7 +942,7 @@ RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bo
|
||||
/*
|
||||
} else {
|
||||
if (!allConsumed) {
|
||||
cerr << "RubberBandStretcher::Impl::process: ERROR: Too much data provided to process() call -- either call setMaxProcessBlockSize() beforehand, or provide only getSamplesRequired() frames at a time" << endl;
|
||||
cerr << "RubberBandStretcher::Impl::process: ERROR: Too much data provided to process() call -- either call setMaxProcessSize() beforehand, or provide only getSamplesRequired() frames at a time" << endl;
|
||||
for (size_t c = 0; c < m_channels; ++c) {
|
||||
cerr << "channel " << c << ": " << samples << " provided, " << consumed[c] << " consumed" << endl;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
void setPhaseOption(Options);
|
||||
|
||||
void setExpectedInputDuration(size_t samples);
|
||||
void setMaxProcessBlockSize(size_t samples);
|
||||
void setMaxProcessSize(size_t samples);
|
||||
|
||||
size_t getSamplesRequired() const;
|
||||
|
||||
@@ -111,11 +111,11 @@ protected:
|
||||
double m_timeRatio;
|
||||
double m_pitchScale;
|
||||
|
||||
size_t m_blockSize;
|
||||
size_t m_outbufSize;
|
||||
size_t m_windowSize;
|
||||
size_t m_increment;
|
||||
size_t m_outbufSize;
|
||||
|
||||
size_t m_maxProcessBlockSize;
|
||||
size_t m_maxProcessSize;
|
||||
size_t m_expectedInputDuration;
|
||||
|
||||
bool m_threaded;
|
||||
@@ -173,7 +173,7 @@ protected:
|
||||
float m_freq1;
|
||||
float m_freq2;
|
||||
|
||||
size_t m_baseBlockSize;
|
||||
size_t m_baseWindowSize;
|
||||
|
||||
void writeOutput(RingBuffer<float> &to, float *from,
|
||||
size_t qty, size_t &outCount, size_t theoreticalOut);
|
||||
|
||||
@@ -83,8 +83,8 @@ RubberBandStretcher::Impl::processChunks(size_t c)
|
||||
if (!testInbufReadSpace(c)) break;
|
||||
|
||||
if (!cd.draining) {
|
||||
size_t got = cd.inbuf->peek(cd.fltbuf, m_blockSize);
|
||||
assert(got == m_blockSize || cd.inputSize >= 0);
|
||||
size_t got = cd.inbuf->peek(cd.fltbuf, m_windowSize);
|
||||
assert(got == m_windowSize || cd.inputSize >= 0);
|
||||
cd.inbuf->skip(m_increment);
|
||||
analyseChunk(c);
|
||||
}
|
||||
@@ -94,9 +94,9 @@ RubberBandStretcher::Impl::processChunks(size_t c)
|
||||
getIncrements(c, phaseIncrement, shiftIncrement, lock);
|
||||
|
||||
last = processChunkForChannel(c, phaseIncrement, shiftIncrement, lock);
|
||||
cd.blockCount++;
|
||||
cd.chunkCount++;
|
||||
if (m_debugLevel > 2) {
|
||||
cerr << "channel " << c << ": last = " << last << ", blockCount = " << cd.blockCount << endl;
|
||||
cerr << "channel " << c << ": last = " << last << ", chunkCount = " << cd.chunkCount << endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,8 +114,8 @@ RubberBandStretcher::Impl::processOneChunk()
|
||||
if (!testInbufReadSpace(c)) return false;
|
||||
ChannelData &cd = *m_channelData[c];
|
||||
if (!cd.draining) {
|
||||
size_t got = cd.inbuf->peek(cd.fltbuf, m_blockSize);
|
||||
assert(got == m_blockSize || cd.inputSize >= 0);
|
||||
size_t got = cd.inbuf->peek(cd.fltbuf, m_windowSize);
|
||||
assert(got == m_windowSize || cd.inputSize >= 0);
|
||||
cd.inbuf->skip(m_increment);
|
||||
analyseChunk(c);
|
||||
}
|
||||
@@ -130,7 +130,7 @@ RubberBandStretcher::Impl::processOneChunk()
|
||||
bool last = false;
|
||||
for (size_t c = 0; c < m_channels; ++c) {
|
||||
last = processChunkForChannel(c, phaseIncrement, shiftIncrement, lock);
|
||||
m_channelData[c]->blockCount++;
|
||||
m_channelData[c]->chunkCount++;
|
||||
}
|
||||
|
||||
return last;
|
||||
@@ -144,20 +144,20 @@ RubberBandStretcher::Impl::testInbufReadSpace(size_t c)
|
||||
|
||||
size_t rs = inbuf.getReadSpace();
|
||||
|
||||
if (rs < m_blockSize && !cd.draining) {
|
||||
if (rs < m_windowSize && !cd.draining) {
|
||||
|
||||
if (cd.inputSize == -1) {
|
||||
|
||||
// Not all the input data has been written to the inbuf
|
||||
// (that's why the input size is not yet set). We can't
|
||||
// process, because we don't have a full block of data, so
|
||||
// our process block would contain some empty padding in
|
||||
// process, because we don't have a full chunk of data, so
|
||||
// our process chunk would contain some empty padding in
|
||||
// its input -- and that would give incorrect output, as
|
||||
// we know there is more input to come.
|
||||
|
||||
if (!m_threaded) {
|
||||
// cerr << "WARNING: RubberBandStretcher: read space < block size ("
|
||||
// << inbuf.getReadSpace() << " < " << m_blockSize
|
||||
// cerr << "WARNING: RubberBandStretcher: read space < chunk size ("
|
||||
// << inbuf.getReadSpace() << " < " << m_windowSize
|
||||
// << ") when not all input written, on processChunks for channel " << c << endl;
|
||||
}
|
||||
return false;
|
||||
@@ -170,7 +170,7 @@ RubberBandStretcher::Impl::testInbufReadSpace(size_t c)
|
||||
}
|
||||
return false;
|
||||
|
||||
} else if (rs < m_blockSize/2) {
|
||||
} else if (rs < m_windowSize/2) {
|
||||
|
||||
if (m_debugLevel > 1) {
|
||||
cerr << "read space = " << rs << ", setting draining true" << endl;
|
||||
@@ -208,12 +208,12 @@ RubberBandStretcher::Impl::processChunkForChannel(size_t c,
|
||||
// to write from the existing accumulator into the output.
|
||||
|
||||
// We know we have enough samples available in m_inbuf --
|
||||
// this is usually m_blockSize, but we know that if fewer
|
||||
// this is usually m_windowSize, but we know that if fewer
|
||||
// are available, it's OK to use zeroes for the rest
|
||||
// (which the ring buffer will provide) because we've
|
||||
// reached the true end of the data.
|
||||
|
||||
// We need to peek m_blockSize samples for processing, and
|
||||
// We need to peek m_windowSize samples for processing, and
|
||||
// then skip m_increment to advance the read pointer.
|
||||
|
||||
modifyChunk(c, phaseIncrement, lock);
|
||||
@@ -285,7 +285,7 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
|
||||
// basis that both channels are in sync. This is in contrast to
|
||||
// getIncrements, which requires that all the increments have been
|
||||
// calculated in advance but can then return increments
|
||||
// corresponding to different blocks in different channels.
|
||||
// corresponding to different chunks in different channels.
|
||||
|
||||
// Requires frequency domain representations of channel data in
|
||||
// the mag and phase buffers in the channel.
|
||||
@@ -300,9 +300,9 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
|
||||
|
||||
ChannelData &cd = *m_channelData[0];
|
||||
|
||||
size_t bc = cd.blockCount;
|
||||
size_t bc = cd.chunkCount;
|
||||
for (size_t c = 1; c < m_channels; ++c) {
|
||||
if (m_channelData[c]->blockCount != bc) {
|
||||
if (m_channelData[c]->chunkCount != bc) {
|
||||
cerr << "ERROR: RubberBandStretcher::Impl::calculateIncrements: Channels are not in sync" << endl;
|
||||
return;
|
||||
}
|
||||
@@ -318,12 +318,12 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
|
||||
// phases to cancel each other, and broadband effects will still
|
||||
// be apparent.
|
||||
|
||||
for (size_t i = 0; i <= m_blockSize/2; ++i) {
|
||||
for (size_t i = 0; i <= m_windowSize/2; ++i) {
|
||||
cd.fltbuf[i] = 0.0;
|
||||
}
|
||||
|
||||
for (size_t c = 0; c < m_channels; ++c) {
|
||||
for (size_t i = 0; i <= m_blockSize/2; ++i) {
|
||||
for (size_t i = 0; i <= m_windowSize/2; ++i) {
|
||||
cd.fltbuf[i] += m_channelData[c]->mag[i];
|
||||
}
|
||||
}
|
||||
@@ -351,7 +351,7 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
|
||||
|
||||
// This implies we should use this increment for the shift
|
||||
// increment, and make the following phase increment the same as
|
||||
// it. This means in RT mode we'll be one block later with our
|
||||
// it. This means in RT mode we'll be one chunk later with our
|
||||
// phase lock than we would be in non-RT mode. The sensitivity of
|
||||
// the broadband onset detector may mean that this isn't a problem
|
||||
// -- test it and see.
|
||||
@@ -399,9 +399,9 @@ RubberBandStretcher::Impl::getIncrements(size_t channel,
|
||||
ChannelData &cd = *m_channelData[channel];
|
||||
bool gotData = true;
|
||||
|
||||
if (cd.blockCount >= m_outputIncrements.size()) {
|
||||
if (cd.chunkCount >= m_outputIncrements.size()) {
|
||||
//!!! this is an error if in non-realtime mode
|
||||
// cerr << "*** ERROR: block count " << cd.blockCount << " >= "
|
||||
// cerr << "*** ERROR: chunk count " << cd.chunkCount << " >= "
|
||||
// << m_outputIncrements.size() << endl;
|
||||
if (m_outputIncrements.size() == 0) {
|
||||
phaseIncrementRtn = m_increment;
|
||||
@@ -409,16 +409,16 @@ RubberBandStretcher::Impl::getIncrements(size_t channel,
|
||||
lock = false;
|
||||
return false;
|
||||
} else {
|
||||
cd.blockCount = m_outputIncrements.size()-1;
|
||||
cd.chunkCount = m_outputIncrements.size()-1;
|
||||
gotData = false;
|
||||
}
|
||||
}
|
||||
|
||||
int phaseIncrement = m_outputIncrements[cd.blockCount];
|
||||
int phaseIncrement = m_outputIncrements[cd.chunkCount];
|
||||
|
||||
int shiftIncrement = phaseIncrement;
|
||||
if (cd.blockCount + 1 < m_outputIncrements.size()) {
|
||||
shiftIncrement = m_outputIncrements[cd.blockCount + 1];
|
||||
if (cd.chunkCount + 1 < m_outputIncrements.size()) {
|
||||
shiftIncrement = m_outputIncrements[cd.chunkCount + 1];
|
||||
}
|
||||
|
||||
if (phaseIncrement < 0) {
|
||||
@@ -430,14 +430,14 @@ RubberBandStretcher::Impl::getIncrements(size_t channel,
|
||||
shiftIncrement = -shiftIncrement;
|
||||
}
|
||||
|
||||
if (shiftIncrement >= int(m_blockSize)) {
|
||||
cerr << "*** ERROR: RubberBandStretcher::Impl::processChunks: shiftIncrement " << shiftIncrement << " >= blockSize " << m_blockSize << " at " << cd.blockCount << " (of " << m_outputIncrements.size() << ")" << endl;
|
||||
shiftIncrement = m_blockSize;
|
||||
if (shiftIncrement >= int(m_windowSize)) {
|
||||
cerr << "*** ERROR: RubberBandStretcher::Impl::processChunks: shiftIncrement " << shiftIncrement << " >= windowSize " << m_windowSize << " at " << cd.chunkCount << " (of " << m_outputIncrements.size() << ")" << endl;
|
||||
shiftIncrement = m_windowSize;
|
||||
}
|
||||
|
||||
phaseIncrementRtn = phaseIncrement;
|
||||
shiftIncrementRtn = shiftIncrement;
|
||||
if (cd.blockCount == 0) lock = true; // don't mess with the first block
|
||||
if (cd.chunkCount == 0) lock = true; // don't mess with the first chunk
|
||||
return gotData;
|
||||
}
|
||||
|
||||
@@ -448,13 +448,13 @@ RubberBandStretcher::Impl::analyseChunk(size_t channel)
|
||||
|
||||
ChannelData &cd = *m_channelData[channel];
|
||||
|
||||
// cd.fltbuf is known to contain m_blockSize samples
|
||||
// cd.fltbuf is known to contain m_windowSize samples
|
||||
|
||||
m_window->cut(cd.fltbuf);
|
||||
|
||||
for (i = 0; i < m_blockSize/2; ++i) {
|
||||
cd.dblbuf[i] = cd.fltbuf[i + m_blockSize/2];
|
||||
cd.dblbuf[i + m_blockSize/2] = cd.fltbuf[i];
|
||||
for (i = 0; i < m_windowSize/2; ++i) {
|
||||
cd.dblbuf[i] = cd.fltbuf[i + m_windowSize/2];
|
||||
cd.dblbuf[i + m_windowSize/2] = cd.fltbuf[i];
|
||||
}
|
||||
|
||||
cd.fft->forwardPolar(cd.dblbuf, cd.mag, cd.phase);
|
||||
@@ -473,7 +473,7 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement,
|
||||
cerr << "lock: leaving phases unmodified" << endl;
|
||||
}
|
||||
|
||||
size_t count = m_blockSize/2;
|
||||
size_t count = m_windowSize/2;
|
||||
size_t pfp = 0;
|
||||
double rate = m_stretcher->m_sampleRate;
|
||||
|
||||
@@ -498,9 +498,9 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement,
|
||||
freq0 = std::max(freq0, rf0);
|
||||
}
|
||||
|
||||
size_t limit0 = lrint((freq0 * m_blockSize) / rate);
|
||||
size_t limit1 = lrint((m_freq1 * m_blockSize) / rate);
|
||||
size_t limit2 = lrint((m_freq2 * m_blockSize) / rate);
|
||||
size_t limit0 = lrint((freq0 * m_windowSize) / rate);
|
||||
size_t limit1 = lrint((m_freq1 * m_windowSize) / rate);
|
||||
size_t limit2 = lrint((m_freq2 * m_windowSize) / rate);
|
||||
|
||||
size_t range = 0;
|
||||
|
||||
@@ -590,8 +590,8 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement,
|
||||
if (!(m_options & OptionTransientsSmooth) &&
|
||||
!(m_options & OptionTransientsCrisp)) {
|
||||
// must be OptionTransientsMixed
|
||||
size_t low = lrint((150 * m_blockSize) / rate);
|
||||
size_t high = lrint((1000 * m_blockSize) / rate);
|
||||
size_t low = lrint((150 * m_windowSize) / rate);
|
||||
size_t high = lrint((1000 * m_windowSize) / rate);
|
||||
if (lockThis) {
|
||||
if (i > low && i < high) lockThis = false;
|
||||
}
|
||||
@@ -601,7 +601,7 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement,
|
||||
|
||||
if (i == 0 || p != pp) {
|
||||
|
||||
double omega = (2 * M_PI * m_increment * p) / m_blockSize;
|
||||
double omega = (2 * M_PI * m_increment * p) / m_windowSize;
|
||||
double expectedPhase = cd.prevPhase[p] + omega;
|
||||
double phaseError = princarg(cd.phase[p] - expectedPhase);
|
||||
double phaseIncrement = (omega + phaseError) / m_increment;
|
||||
@@ -641,29 +641,29 @@ RubberBandStretcher::Impl::synthesiseChunk(size_t channel)
|
||||
|
||||
cd.fft->inversePolar(cd.mag, cd.phase, cd.dblbuf);
|
||||
|
||||
for (size_t i = 0; i < m_blockSize/2; ++i) {
|
||||
cd.fltbuf[i] = cd.dblbuf[i + m_blockSize/2];
|
||||
cd.fltbuf[i + m_blockSize/2] = cd.dblbuf[i];
|
||||
for (size_t i = 0; i < m_windowSize/2; ++i) {
|
||||
cd.fltbuf[i] = cd.dblbuf[i + m_windowSize/2];
|
||||
cd.fltbuf[i + m_windowSize/2] = cd.dblbuf[i];
|
||||
}
|
||||
|
||||
// our ffts produced unscaled results
|
||||
for (size_t i = 0; i < m_blockSize; ++i) {
|
||||
cd.fltbuf[i] = cd.fltbuf[i] / m_blockSize;
|
||||
for (size_t i = 0; i < m_windowSize; ++i) {
|
||||
cd.fltbuf[i] = cd.fltbuf[i] / m_windowSize;
|
||||
}
|
||||
|
||||
m_window->cut(cd.fltbuf);
|
||||
|
||||
for (size_t i = 0; i < m_blockSize; ++i) {
|
||||
for (size_t i = 0; i < m_windowSize; ++i) {
|
||||
cd.accumulator[i] += cd.fltbuf[i];
|
||||
}
|
||||
|
||||
cd.accumulatorFill = m_blockSize;
|
||||
cd.accumulatorFill = m_windowSize;
|
||||
|
||||
//!!! not much cop, this bit
|
||||
|
||||
float area = m_window->getArea();
|
||||
|
||||
for (size_t i = 0; i < m_blockSize; ++i) {
|
||||
for (size_t i = 0; i < m_windowSize; ++i) {
|
||||
float val = m_window->getValue(i);
|
||||
cd.windowAccumulator[i] += val * area;
|
||||
}
|
||||
@@ -718,11 +718,6 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
|
||||
cd.resamplebuf = new float[cd.resamplebufSize];
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPP
|
||||
if (m_threaded) {
|
||||
m_resamplerMutex.lock();
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t outframes = cd.resampler->resample(&cd.accumulator,
|
||||
&cd.resamplebuf,
|
||||
@@ -730,11 +725,6 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
|
||||
1.0 / m_pitchScale,
|
||||
last);
|
||||
|
||||
#ifdef HAVE_IPP
|
||||
if (m_threaded) {
|
||||
m_resamplerMutex.unlock();
|
||||
}
|
||||
#endif
|
||||
|
||||
writeOutput(*cd.outbuf, cd.resamplebuf,
|
||||
outframes, cd.outCount, theoreticalOut);
|
||||
@@ -744,19 +734,19 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
|
||||
shiftIncrement, cd.outCount, theoreticalOut);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < m_blockSize - shiftIncrement; ++i) {
|
||||
for (size_t i = 0; i < m_windowSize - shiftIncrement; ++i) {
|
||||
cd.accumulator[i] = cd.accumulator[i + shiftIncrement];
|
||||
}
|
||||
|
||||
for (size_t i = m_blockSize - shiftIncrement; i < m_blockSize; ++i) {
|
||||
for (size_t i = m_windowSize - shiftIncrement; i < m_windowSize; ++i) {
|
||||
cd.accumulator[i] = 0.0f;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < m_blockSize - shiftIncrement; ++i) {
|
||||
for (size_t i = 0; i < m_windowSize - shiftIncrement; ++i) {
|
||||
cd.windowAccumulator[i] = cd.windowAccumulator[i + shiftIncrement];
|
||||
}
|
||||
|
||||
for (size_t i = m_blockSize - shiftIncrement; i < m_blockSize; ++i) {
|
||||
for (size_t i = m_windowSize - shiftIncrement; i < m_windowSize; ++i) {
|
||||
cd.windowAccumulator[i] = 0.0f;
|
||||
}
|
||||
|
||||
@@ -777,13 +767,13 @@ void
|
||||
RubberBandStretcher::Impl::writeOutput(RingBuffer<float> &to, float *from, size_t qty, size_t &outCount, size_t theoreticalOut)
|
||||
{
|
||||
// In non-RT mode, we don't want to write the first startSkip
|
||||
// samples, because the first block is centred on the start of the
|
||||
// samples, because the first chunk is centred on the start of the
|
||||
// output. In RT mode we didn't apply any pre-padding in
|
||||
// configure(), so we don't want to remove any here.
|
||||
|
||||
size_t startSkip = 0;
|
||||
if (!m_realtime) {
|
||||
startSkip = lrintf((m_blockSize/2) / m_pitchScale);
|
||||
startSkip = lrintf((m_windowSize/2) / m_pitchScale);
|
||||
}
|
||||
|
||||
if (outCount > startSkip) {
|
||||
|
||||
Reference in New Issue
Block a user