* Separate out analysis and synthesis window sizes from FFT size.

This is an internal change only, so far -- results should be
  unchanged from 1.5.0.
This commit is contained in:
Chris Cannam
2010-05-16 10:44:38 +01:00
parent 8b3a5e4979
commit 3ed58ba356
16 changed files with 285 additions and 281 deletions

View File

@@ -27,7 +27,7 @@
* *
* The Rubber Band API is contained in the single class * The Rubber Band API is contained in the single class
* RubberBand::RubberBandStretcher. * RubberBand::RubberBandStretcher.
* *
* Threading notes for real-time applications: * Threading notes for real-time applications:
* *
* Multiple instances of RubberBandStretcher may be created and used * Multiple instances of RubberBandStretcher may be created and used

View File

@@ -22,41 +22,39 @@ namespace RubberBand
{ {
RubberBandStretcher::Impl::ChannelData::ChannelData(size_t windowSize, RubberBandStretcher::Impl::ChannelData::ChannelData(size_t windowSize,
int overSample, size_t fftSize,
size_t outbufSize) : size_t outbufSize)
oversample(overSample)
{ {
std::set<size_t> s; std::set<size_t> s;
construct(s, windowSize, outbufSize); construct(s, windowSize, fftSize, outbufSize);
} }
RubberBandStretcher::Impl::ChannelData::ChannelData(const std::set<size_t> &windowSizes, RubberBandStretcher::Impl::ChannelData::ChannelData(const std::set<size_t> &sizes,
int overSample,
size_t initialWindowSize, size_t initialWindowSize,
size_t outbufSize) : size_t initialFftSize,
oversample(overSample) size_t outbufSize)
{ {
construct(windowSizes, initialWindowSize, outbufSize); construct(sizes, initialWindowSize, initialFftSize, outbufSize);
} }
void void
RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &windowSizes, RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &sizes,
size_t initialWindowSize, size_t initialWindowSize,
size_t initialFftSize,
size_t outbufSize) size_t outbufSize)
{ {
size_t maxSize = initialWindowSize; size_t maxSize = initialWindowSize;
if (initialFftSize > maxSize) maxSize = initialFftSize;
if (!windowSizes.empty()) { // std::set is ordered by value
// std::set is ordered by value std::set<size_t>::const_iterator i = sizes.end();
std::set<size_t>::const_iterator i = windowSizes.end(); if (i != sizes.begin()) {
maxSize = *--i; --i;
} if (*i > maxSize) maxSize = *i;
if (windowSizes.find(initialWindowSize) == windowSizes.end()) {
if (initialWindowSize > maxSize) maxSize = initialWindowSize;
} }
// max size of the real "half" of freq data // max possible size of the real "half" of freq data
size_t realSize = (maxSize * oversample)/2 + 1; size_t realSize = maxSize / 2 + 1;
// std::cerr << "ChannelData::construct([" << windowSizes.size() << "], " << maxSize << ", " << outbufSize << ")" << std::endl; // std::cerr << "ChannelData::construct([" << windowSizes.size() << "], " << maxSize << ", " << outbufSize << ")" << std::endl;
@@ -79,16 +77,12 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
accumulator = allocate<float>(maxSize); accumulator = allocate<float>(maxSize);
windowAccumulator = allocate<float>(maxSize); windowAccumulator = allocate<float>(maxSize);
for (std::set<size_t>::const_iterator i = windowSizes.begin(); for (std::set<size_t>::const_iterator i = sizes.begin();
i != windowSizes.end(); ++i) { i != sizes.end(); ++i) {
ffts[*i] = new FFT(*i * oversample); ffts[*i] = new FFT(*i);
ffts[*i]->initDouble(); ffts[*i]->initDouble();
} }
if (windowSizes.find(initialWindowSize) == windowSizes.end()) { fft = ffts[initialFftSize];
ffts[initialWindowSize] = new FFT(initialWindowSize * oversample);
ffts[initialWindowSize]->initDouble();
}
fft = ffts[initialWindowSize];
dblbuf = fft->getDoubleTimeBuffer(); dblbuf = fft->getDoubleTimeBuffer();
@@ -102,7 +96,7 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
freqPeak[i] = 0; freqPeak[i] = 0;
} }
for (size_t i = 0; i < initialWindowSize * oversample; ++i) { for (size_t i = 0; i < initialFftSize; ++i) {
dblbuf[i] = 0.0; dblbuf[i] = 0.0;
} }
@@ -115,15 +109,16 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
windowAccumulator[0] = 1.f; windowAccumulator[0] = 1.f;
} }
void void
RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize) RubberBandStretcher::Impl::ChannelData::setSizes(size_t windowSize,
size_t fftSize)
{ {
size_t oldSize = inbuf->getSize(); size_t maxSize = std::max(windowSize, fftSize);
size_t realSize = (windowSize * oversample) / 2 + 1; size_t realSize = maxSize / 2 + 1;
size_t oldMax = inbuf->getSize();
// std::cerr << "ChannelData::setWindowSize(" << windowSize << ") [from " << oldSize << "]" << std::endl; if (oldMax >= maxSize) {
if (oldSize >= windowSize) { //!!! shurely >= realSize?
// no need to reallocate buffers, just reselect fft // no need to reallocate buffers, just reselect fft
@@ -131,18 +126,18 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
//process thread, can we? we need to zero the mag/phase //process thread, can we? we need to zero the mag/phase
//buffers without interference //buffers without interference
if (ffts.find(windowSize) == ffts.end()) { if (ffts.find(fftSize) == ffts.end()) {
//!!! this also requires a lock, but it shouldn't occur in //!!! this also requires a lock, but it shouldn't occur in
//RT mode with proper initialisation //RT mode with proper initialisation
ffts[windowSize] = new FFT(windowSize * oversample); ffts[fftSize] = new FFT(fftSize);
ffts[windowSize]->initDouble(); ffts[fftSize]->initDouble();
} }
fft = ffts[windowSize]; fft = ffts[fftSize];
dblbuf = fft->getDoubleTimeBuffer(); dblbuf = fft->getDoubleTimeBuffer();
for (size_t i = 0; i < windowSize * oversample; ++i) { for (size_t i = 0; i < maxSize; ++i) {
dblbuf[i] = 0.0; dblbuf[i] = 0.0;
} }
@@ -165,37 +160,37 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
//is unavailable (since this should never normally be the case in //is unavailable (since this should never normally be the case in
//general use in RT mode) //general use in RT mode)
RingBuffer<float> *newbuf = inbuf->resized(windowSize); RingBuffer<float> *newbuf = inbuf->resized(maxSize);
delete inbuf; delete inbuf;
inbuf = newbuf; inbuf = newbuf;
// We don't want to preserve data in these arrays // We don't want to preserve data in these arrays
mag = reallocate<double>(mag, oldSize, realSize); mag = reallocate<double>(mag, oldMax, realSize);
phase = reallocate<double>(phase, oldSize, realSize); phase = reallocate<double>(phase, oldMax, realSize);
prevPhase = reallocate<double>(prevPhase, oldSize, realSize); prevPhase = reallocate<double>(prevPhase, oldMax, realSize);
prevError = reallocate<double>(prevError, oldSize, realSize); prevError = reallocate<double>(prevError, oldMax, realSize);
unwrappedPhase = reallocate<double>(unwrappedPhase, oldSize, realSize); unwrappedPhase = reallocate<double>(unwrappedPhase, oldMax, realSize);
envelope = reallocate<double>(envelope, oldSize, realSize); envelope = reallocate<double>(envelope, oldMax, realSize);
delete[] freqPeak; delete[] freqPeak;
freqPeak = new size_t[realSize]; freqPeak = new size_t[realSize];
deallocate(fltbuf); deallocate(fltbuf);
fltbuf = allocate<float>(windowSize); fltbuf = allocate<float>(maxSize);
// But we do want to preserve data in these // But we do want to preserve data in these
float *newAcc = allocate<float>(windowSize); float *newAcc = allocate<float>(maxSize);
v_copy(newAcc, accumulator, oldSize); v_copy(newAcc, accumulator, oldMax);
deallocate(accumulator); deallocate(accumulator);
accumulator = newAcc; accumulator = newAcc;
newAcc = allocate<float>(windowSize); newAcc = allocate<float>(maxSize);
v_copy(newAcc, windowAccumulator, oldSize); v_copy(newAcc, windowAccumulator, oldMax);
deallocate(windowAccumulator); deallocate(windowAccumulator);
windowAccumulator = newAcc; windowAccumulator = newAcc;
@@ -206,20 +201,20 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
freqPeak[i] = 0; freqPeak[i] = 0;
} }
for (size_t i = 0; i < windowSize; ++i) { for (size_t i = 0; i < maxSize; ++i) {
fltbuf[i] = 0.f; fltbuf[i] = 0.f;
} }
if (ffts.find(windowSize) == ffts.end()) { if (ffts.find(fftSize) == ffts.end()) {
ffts[windowSize] = new FFT(windowSize * oversample); ffts[fftSize] = new FFT(fftSize);
ffts[windowSize]->initDouble(); ffts[fftSize]->initDouble();
} }
fft = ffts[windowSize]; fft = ffts[fftSize];
dblbuf = fft->getDoubleTimeBuffer(); dblbuf = fft->getDoubleTimeBuffer();
for (size_t i = 0; i < windowSize * oversample; ++i) { for (size_t i = 0; i < fftSize; ++i) {
dblbuf[i] = 0.0; dblbuf[i] = 0.0;
} }
} }

View File

@@ -32,31 +32,36 @@ public:
/** /**
* Construct a ChannelData structure. * Construct a ChannelData structure.
* *
* The window size passed in here is the size for the FFT * The sizes passed in here are for the time-domain analysis
* calculation, and most of the buffer sizes also depend on * window and FFT calculation, and most of the buffer sizes also
* it. In practice it is always a power of two and except for * depend on them. In practice they are always powers of two, the
* very extreme stretches is always either 1024, 2048 or 4096. * window and FFT sizes are either equal or generally in a 2:1
* relationship either way, and except for very extreme stretches
* the FFT size is either 1024, 2048 or 4096.
* *
* The outbuf size depends on other factors as well, including * The outbuf size depends on other factors as well, including
* the pitch scale factor and any maximum processing block * the pitch scale factor and any maximum processing block
* size specified by the user of the code. * size specified by the user of the code.
*/ */
ChannelData(size_t windowSize, int overSample, size_t outbufSize); ChannelData(size_t windowSize,
size_t fftSize,
size_t outbufSize);
/** /**
* Construct a ChannelData structure that can process at * Construct a ChannelData structure that can process at different
* different FFT sizes without requiring reallocation when the * FFT sizes without requiring reallocation when the size changes.
* size changes. The size can subsequently be changed with a * The sizes can subsequently be changed with a call to setSizes.
* call to setWindowSize. Reallocation will only be necessary * Reallocation will only be necessary if setSizes is called with
* if setWindowSize is called with a value not equal to one of * values not equal to any of those passed in to the constructor.
* those passed in to the constructor.
* *
* The outbufSize should be the maximum possible outbufSize to * The outbufSize should be the maximum possible outbufSize to
* avoid reallocation, which will happen if setOutbufSize is * avoid reallocation, which will happen if setOutbufSize is
* called subsequently. * called subsequently.
*/ */
ChannelData(const std::set<size_t> &windowSizes, ChannelData(const std::set<size_t> &sizes,
int overSample, size_t initialWindowSize, size_t outbufSize); size_t initialWindowSize,
size_t initialFftSize,
size_t outbufSize);
~ChannelData(); ~ChannelData();
/** /**
@@ -65,12 +70,12 @@ public:
void reset(); void reset();
/** /**
* Set the FFT and buffer sizes from the given processing * Set the FFT, analysis window, and buffer sizes. If this
* window size. If this ChannelData was constructed with a set * ChannelData was constructed with a set of sizes and the given
* of window sizes and the given window size here was among * window and FFT sizes here were among them, no reallocation will
* them, no reallocation will be required. * be required.
*/ */
void setWindowSize(size_t windowSize); void setSizes(size_t windowSize, size_t fftSizes);
/** /**
* Set the outbufSize for the channel data. Reallocation will * Set the outbufSize for the channel data. Reallocation will
@@ -94,7 +99,6 @@ public:
double *prevError; double *prevError;
double *unwrappedPhase; double *unwrappedPhase;
size_t *freqPeak; size_t *freqPeak;
float *accumulator; float *accumulator;
@@ -123,11 +127,10 @@ public:
float *resamplebuf; float *resamplebuf;
size_t resamplebufSize; size_t resamplebufSize;
int oversample;
private: private:
void construct(const std::set<size_t> &windowSizes, void construct(const std::set<size_t> &sizes,
size_t initialWindowSize, size_t outbufSize); size_t initialWindowSize, size_t initialFftSize,
size_t outbufSize);
}; };
} }

View File

@@ -52,7 +52,7 @@ const size_t
RubberBandStretcher::Impl::m_defaultIncrement = 256; RubberBandStretcher::Impl::m_defaultIncrement = 256;
const size_t const size_t
RubberBandStretcher::Impl::m_defaultWindowSize = 2048; RubberBandStretcher::Impl::m_defaultFftSize = 2048;
int int
RubberBandStretcher::Impl::m_defaultDebugLevel = 0; RubberBandStretcher::Impl::m_defaultDebugLevel = 0;
@@ -68,17 +68,20 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
m_channels(channels), m_channels(channels),
m_timeRatio(initialTimeRatio), m_timeRatio(initialTimeRatio),
m_pitchScale(initialPitchScale), m_pitchScale(initialPitchScale),
m_windowSize(m_defaultWindowSize), m_fftSize(m_defaultFftSize),
m_aWindowSize(m_defaultFftSize),
m_sWindowSize(m_defaultFftSize),
m_increment(m_defaultIncrement), m_increment(m_defaultIncrement),
m_outbufSize(m_defaultWindowSize * 2), m_outbufSize(m_defaultFftSize * 2),
m_maxProcessSize(m_defaultWindowSize), m_maxProcessSize(m_defaultFftSize),
m_expectedInputDuration(0), m_expectedInputDuration(0),
m_threaded(false), m_threaded(false),
m_realtime(false), m_realtime(false),
m_options(options), m_options(options),
m_debugLevel(m_defaultDebugLevel), m_debugLevel(m_defaultDebugLevel),
m_mode(JustCreated), m_mode(JustCreated),
m_window(0), m_awindow(0),
m_swindow(0),
m_studyFFT(0), m_studyFFT(0),
m_spaceAvailable("space"), m_spaceAvailable("space"),
m_inputDuration(0), m_inputDuration(0),
@@ -94,7 +97,7 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
m_freq0(600), m_freq0(600),
m_freq1(1200), m_freq1(1200),
m_freq2(12000), m_freq2(12000),
m_baseWindowSize(m_defaultWindowSize) m_baseFftSize(m_defaultFftSize)
{ {
if (!_initialised) { if (!_initialised) {
system_specific_initialise(); system_specific_initialise();
@@ -109,25 +112,27 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
// we don't let it drop below the 48k default // we don't let it drop below the 48k default
m_rateMultiple = float(m_sampleRate) / 48000.f; m_rateMultiple = float(m_sampleRate) / 48000.f;
// if (m_rateMultiple < 1.f) m_rateMultiple = 1.f; // if (m_rateMultiple < 1.f) m_rateMultiple = 1.f;
m_baseWindowSize = roundUp(int(m_defaultWindowSize * m_rateMultiple)); m_baseFftSize = roundUp(int(m_defaultFftSize * m_rateMultiple));
if ((options & OptionWindowShort) || (options & OptionWindowLong)) { if ((options & OptionWindowShort) || (options & OptionWindowLong)) {
if ((options & OptionWindowShort) && (options & OptionWindowLong)) { if ((options & OptionWindowShort) && (options & OptionWindowLong)) {
cerr << "RubberBandStretcher::Impl::Impl: Cannot specify OptionWindowLong and OptionWindowShort together; falling back to OptionWindowStandard" << endl; cerr << "RubberBandStretcher::Impl::Impl: Cannot specify OptionWindowLong and OptionWindowShort together; falling back to OptionWindowStandard" << endl;
} else if (options & OptionWindowShort) { } else if (options & OptionWindowShort) {
m_baseWindowSize = m_baseWindowSize / 2; m_baseFftSize = m_baseFftSize / 2;
if (m_debugLevel > 0) { if (m_debugLevel > 0) {
cerr << "setting baseWindowSize to " << m_baseWindowSize << endl; cerr << "setting baseFftSize to " << m_baseFftSize << endl;
} }
} else if (options & OptionWindowLong) { } else if (options & OptionWindowLong) {
m_baseWindowSize = m_baseWindowSize * 2; m_baseFftSize = m_baseFftSize * 2;
if (m_debugLevel > 0) { if (m_debugLevel > 0) {
cerr << "setting baseWindowSize to " << m_baseWindowSize << endl; cerr << "setting baseFftSize to " << m_baseFftSize << endl;
} }
} }
m_windowSize = m_baseWindowSize; m_fftSize = m_baseFftSize;
m_outbufSize = m_baseWindowSize * 2; m_aWindowSize = m_baseFftSize;
m_maxProcessSize = m_baseWindowSize; m_sWindowSize = m_baseFftSize;
m_outbufSize = m_sWindowSize * 2;
m_maxProcessSize = m_aWindowSize;
} }
if (m_options & OptionProcessRealTime) { if (m_options & OptionProcessRealTime) {
@@ -378,7 +383,7 @@ void
RubberBandStretcher::Impl::calculateSizes() RubberBandStretcher::Impl::calculateSizes()
{ {
size_t inputIncrement = m_defaultIncrement; size_t inputIncrement = m_defaultIncrement;
size_t windowSize = m_baseWindowSize; size_t windowSize = m_baseFftSize;
size_t outputIncrement; size_t outputIncrement;
if (m_pitchScale <= 0.0) { if (m_pitchScale <= 0.0) {
@@ -413,7 +418,7 @@ RubberBandStretcher::Impl::calculateSizes()
if (outputIncrement < m_defaultIncrement / 4) { if (outputIncrement < m_defaultIncrement / 4) {
if (outputIncrement < 1) outputIncrement = 1; if (outputIncrement < 1) outputIncrement = 1;
while (outputIncrement < m_defaultIncrement / 4 && while (outputIncrement < m_defaultIncrement / 4 &&
windowSize < m_baseWindowSize * 4) { windowSize < m_baseFftSize * 4) {
outputIncrement *= 2; outputIncrement *= 2;
inputIncrement = lrint(ceil(outputIncrement / r)); inputIncrement = lrint(ceil(outputIncrement / r));
windowSize = roundUp(lrint(ceil(inputIncrement * windowIncrRatio))); windowSize = roundUp(lrint(ceil(inputIncrement * windowIncrRatio)));
@@ -483,9 +488,11 @@ RubberBandStretcher::Impl::calculateSizes()
} }
// windowSize can be almost anything, but it can't be greater than // windowSize can be almost anything, but it can't be greater than
// 4 * m_baseWindowSize unless ratio is less than 1/1024. // 4 * m_baseFftSize unless ratio is less than 1/1024.
m_windowSize = windowSize; m_fftSize = windowSize;
m_aWindowSize = windowSize;
m_sWindowSize = windowSize;
m_increment = inputIncrement; m_increment = inputIncrement;
// When squashing, the greatest theoretically possible output // When squashing, the greatest theoretically possible output
@@ -497,18 +504,18 @@ RubberBandStretcher::Impl::calculateSizes()
if (m_debugLevel > 0) { if (m_debugLevel > 0) {
cerr << "configure: effective ratio = " << getEffectiveRatio() << endl; cerr << "configure: effective ratio = " << getEffectiveRatio() << endl;
cerr << "configure: window size = " << m_windowSize << ", increment = " << m_increment << " (approx output increment = " << int(lrint(m_increment * getEffectiveRatio())) << ")" << endl; cerr << "configure: analysis window size = " << m_aWindowSize << ", synthesis window size = " << m_sWindowSize << ", fft size = " << m_fftSize << ", increment = " << m_increment << " (approx output increment = " << int(lrint(m_increment * getEffectiveRatio())) << ")" << endl;
} }
if (m_windowSize > m_maxProcessSize) { if (std::max(m_aWindowSize, m_sWindowSize) > m_maxProcessSize) {
m_maxProcessSize = m_windowSize; m_maxProcessSize = std::max(m_aWindowSize, m_sWindowSize);
} }
m_outbufSize = m_outbufSize =
size_t size_t
(ceil(max (ceil(max
(m_maxProcessSize / m_pitchScale, (m_maxProcessSize / m_pitchScale,
m_windowSize * 2 * (m_timeRatio > 1.f ? m_timeRatio : 1.f)))); m_sWindowSize * 2 * (m_timeRatio > 1.f ? m_timeRatio : 1.f))));
if (m_realtime) { if (m_realtime) {
// This headroom is so as to try to avoid reallocation when // This headroom is so as to try to avoid reallocation when
@@ -535,16 +542,22 @@ RubberBandStretcher::Impl::configure()
// std::cerr << "configure[" << this << "]: realtime = " << m_realtime << ", pitch scale = " // std::cerr << "configure[" << this << "]: realtime = " << m_realtime << ", pitch scale = "
// << m_pitchScale << ", channels = " << m_channels << std::endl; // << m_pitchScale << ", channels = " << m_channels << std::endl;
size_t prevWindowSize = m_windowSize; size_t prevFftSize = m_fftSize;
size_t prevAWindowSize = m_aWindowSize;
size_t prevSWindowSize = m_sWindowSize;
size_t prevOutbufSize = m_outbufSize; size_t prevOutbufSize = m_outbufSize;
if (m_windows.empty()) { if (m_windows.empty()) {
prevWindowSize = 0; prevFftSize = 0;
prevAWindowSize = 0;
prevSWindowSize = 0;
prevOutbufSize = 0; prevOutbufSize = 0;
} }
calculateSizes(); calculateSizes();
bool windowSizeChanged = (prevWindowSize != m_windowSize); bool fftSizeChanged = (prevFftSize != m_fftSize);
bool windowSizeChanged = ((prevAWindowSize != m_aWindowSize) ||
(prevSWindowSize != m_sWindowSize));
bool outbufSizeChanged = (prevOutbufSize != m_outbufSize); bool outbufSizeChanged = (prevOutbufSize != m_outbufSize);
// This function may be called at any time in non-RT mode, after a // This function may be called at any time in non-RT mode, after a
@@ -557,12 +570,14 @@ RubberBandStretcher::Impl::configure()
set<size_t> windowSizes; set<size_t> windowSizes;
if (m_realtime) { if (m_realtime) {
windowSizes.insert(m_baseWindowSize); windowSizes.insert(m_baseFftSize);
windowSizes.insert(m_baseWindowSize / 2); windowSizes.insert(m_baseFftSize / 2);
windowSizes.insert(m_baseWindowSize * 2); windowSizes.insert(m_baseFftSize * 2);
// windowSizes.insert(m_baseWindowSize * 4); // windowSizes.insert(m_baseFftSize * 4);
} }
windowSizes.insert(m_windowSize); windowSizes.insert(m_fftSize);
windowSizes.insert(m_aWindowSize);
windowSizes.insert(m_sWindowSize);
if (windowSizeChanged) { if (windowSizeChanged) {
@@ -572,10 +587,11 @@ RubberBandStretcher::Impl::configure()
m_windows[*i] = new Window<float>(HanningWindow, *i); m_windows[*i] = new Window<float>(HanningWindow, *i);
} }
} }
m_window = m_windows[m_windowSize]; m_awindow = m_windows[m_aWindowSize];
m_swindow = m_windows[m_sWindowSize];
if (m_debugLevel > 0) { if (m_debugLevel > 0) {
cerr << "Window area: " << m_window->getArea() << "; synthesis window area: " << m_window->getArea() << endl; cerr << "Window area: " << m_awindow->getArea() << "; synthesis window area: " << m_swindow->getArea() << endl;
} }
} }
@@ -588,13 +604,16 @@ RubberBandStretcher::Impl::configure()
for (size_t c = 0; c < m_channels; ++c) { for (size_t c = 0; c < m_channels; ++c) {
m_channelData.push_back m_channelData.push_back
(new ChannelData(windowSizes, 1, m_windowSize, m_outbufSize)); (new ChannelData(windowSizes,
std::max(m_aWindowSize, m_sWindowSize),
m_fftSize,
m_outbufSize));
} }
} }
if (!m_realtime && windowSizeChanged) { if (!m_realtime && fftSizeChanged) {
delete m_studyFFT; delete m_studyFFT;
m_studyFFT = new FFT(m_windowSize, m_debugLevel); m_studyFFT = new FFT(m_fftSize, m_debugLevel);
m_studyFFT->initFloat(); m_studyFFT->initFloat();
} }
@@ -626,21 +645,21 @@ RubberBandStretcher::Impl::configure()
delete m_phaseResetAudioCurve; delete m_phaseResetAudioCurve;
m_phaseResetAudioCurve = new CompoundAudioCurve m_phaseResetAudioCurve = new CompoundAudioCurve
(CompoundAudioCurve::Parameters(m_sampleRate, m_windowSize)); (CompoundAudioCurve::Parameters(m_sampleRate, m_fftSize));
m_phaseResetAudioCurve->setType(m_detectorType); m_phaseResetAudioCurve->setType(m_detectorType);
delete m_silentAudioCurve; delete m_silentAudioCurve;
m_silentAudioCurve = new SilentAudioCurve m_silentAudioCurve = new SilentAudioCurve
(SilentAudioCurve::Parameters(m_sampleRate, m_windowSize)); (SilentAudioCurve::Parameters(m_sampleRate, m_fftSize));
if (!m_realtime) { if (!m_realtime) {
delete m_stretchAudioCurve; delete m_stretchAudioCurve;
if (!(m_options & OptionStretchPrecise)) { if (!(m_options & OptionStretchPrecise)) {
m_stretchAudioCurve = new SpectralDifferenceAudioCurve m_stretchAudioCurve = new SpectralDifferenceAudioCurve
(SpectralDifferenceAudioCurve::Parameters(m_sampleRate, m_windowSize)); (SpectralDifferenceAudioCurve::Parameters(m_sampleRate, m_fftSize));
} else { } else {
m_stretchAudioCurve = new ConstantAudioCurve m_stretchAudioCurve = new ConstantAudioCurve
(ConstantAudioCurve::Parameters(m_sampleRate, m_windowSize)); (ConstantAudioCurve::Parameters(m_sampleRate, m_fftSize));
} }
} }
@@ -666,7 +685,7 @@ RubberBandStretcher::Impl::configure()
if (!m_realtime) { if (!m_realtime) {
for (size_t c = 0; c < m_channels; ++c) { for (size_t c = 0; c < m_channels; ++c) {
m_channelData[c]->reset(); m_channelData[c]->reset();
m_channelData[c]->inbuf->zero(m_windowSize/2); m_channelData[c]->inbuf->zero(m_aWindowSize/2);
} }
} }
} }
@@ -688,7 +707,9 @@ RubberBandStretcher::Impl::reconfigure()
configure(); configure();
} }
size_t prevWindowSize = m_windowSize; size_t prevFftSize = m_fftSize;
size_t prevAWindowSize = m_aWindowSize;
size_t prevSWindowSize = m_sWindowSize;
size_t prevOutbufSize = m_outbufSize; size_t prevOutbufSize = m_outbufSize;
calculateSizes(); calculateSizes();
@@ -698,18 +719,29 @@ RubberBandStretcher::Impl::reconfigure()
// where not all of the things we need were correctly created when // where not all of the things we need were correctly created when
// we first configured (for whatever reason). This is intended to // we first configured (for whatever reason). This is intended to
// be "effectively" realtime safe. The same goes for // be "effectively" realtime safe. The same goes for
// ChannelData::setOutbufSize and setWindowSize. // ChannelData::setOutbufSize and setSizes.
if (m_windowSize != prevWindowSize) { if (m_aWindowSize != prevAWindowSize ||
m_sWindowSize != prevSWindowSize) {
if (m_windows.find(m_windowSize) == m_windows.end()) { if (m_windows.find(m_aWindowSize) == m_windows.end()) {
std::cerr << "WARNING: reconfigure(): window allocation (size " << m_windowSize << ") required in RT mode" << std::endl; std::cerr << "WARNING: reconfigure(): window allocation (size " << m_aWindowSize << ") required in RT mode" << std::endl;
m_windows[m_windowSize] = new Window<float>(HanningWindow, m_windowSize); m_windows[m_aWindowSize] = new Window<float>
(HanningWindow, m_aWindowSize);
} }
m_window = m_windows[m_windowSize];
if (m_windows.find(m_sWindowSize) == m_windows.end()) {
std::cerr << "WARNING: reconfigure(): window allocation (size " << m_sWindowSize << ") required in RT mode" << std::endl;
m_windows[m_sWindowSize] = new Window<float>
(HanningWindow, m_sWindowSize);
}
m_awindow = m_windows[m_aWindowSize];
m_swindow = m_windows[m_sWindowSize];
for (size_t c = 0; c < m_channels; ++c) { for (size_t c = 0; c < m_channels; ++c) {
m_channelData[c]->setWindowSize(m_windowSize); m_channelData[c]->setSizes(std::max(m_aWindowSize, m_sWindowSize),
m_fftSize);
} }
} }
@@ -727,7 +759,7 @@ RubberBandStretcher::Impl::reconfigure()
std::cerr << "WARNING: reconfigure(): resampler construction required in RT mode" << std::endl; std::cerr << "WARNING: reconfigure(): resampler construction required in RT mode" << std::endl;
m_channelData[c]->resampler = m_channelData[c]->resampler =
new Resampler(Resampler::FastestTolerable, 1, m_windowSize, new Resampler(Resampler::FastestTolerable, 1, m_sWindowSize,
m_debugLevel); m_debugLevel);
m_channelData[c]->setResampleBufSize m_channelData[c]->setResampleBufSize
@@ -735,8 +767,8 @@ RubberBandStretcher::Impl::reconfigure()
} }
} }
if (m_windowSize != prevWindowSize) { if (m_fftSize != prevFftSize) {
m_phaseResetAudioCurve->setWindowSize(m_windowSize); m_phaseResetAudioCurve->setFftSize(m_fftSize);
} }
} }
@@ -744,7 +776,7 @@ size_t
RubberBandStretcher::Impl::getLatency() const RubberBandStretcher::Impl::getLatency() const
{ {
if (!m_realtime) return 0; if (!m_realtime) return 0;
return int((m_windowSize/2) / m_pitchScale + 1); return int((m_aWindowSize/2) / m_pitchScale + 1);
} }
void void
@@ -887,21 +919,24 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
consumed += writable; consumed += writable;
} }
while ((inbuf.getReadSpace() >= int(m_windowSize)) || while ((inbuf.getReadSpace() >= int(m_aWindowSize)) ||
(final && (inbuf.getReadSpace() >= int(m_windowSize/2)))) { (final && (inbuf.getReadSpace() >= int(m_aWindowSize/2)))) {
// We know we have at least m_windowSize samples available // We know we have at least m_aWindowSize samples
// in m_inbuf. We need to peek m_windowSize of them for // available in m_inbuf. We need to peek m_aWindowSize of
// processing, and then skip m_increment to advance the // them for processing, and then skip m_increment to
// read pointer. // advance the read pointer.
// cd.accumulator is not otherwise used during studying, // cd.accumulator is not otherwise used during studying,
// so we can use it as a temporary buffer here // so we can use it as a temporary buffer here
size_t got = inbuf.peek(cd.accumulator, m_windowSize); size_t got = inbuf.peek(cd.accumulator, m_aWindowSize);
assert(final || got == m_windowSize); assert(final || got == m_aWindowSize);
m_window->cut(cd.accumulator); m_awindow->cut(cd.accumulator);
//!!! insert appropriate cunning here if m_aWindowSize !=
//!!! m_fftSize
// We don't need the fftshift for studying, as we're only // We don't need the fftshift for studying, as we're only
// interested in magnitude // interested in magnitude
@@ -925,12 +960,12 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
// cout << df << endl; // cout << df << endl;
// We have augmented the input by m_windowSize/2 so // We have augmented the input by m_aWindowSize/2 so that
// that the first chunk is centred on the first audio // the first chunk is centred on the first audio sample.
// sample. We want to ensure that m_inputDuration // We want to ensure that m_inputDuration contains the
// contains the exact input duration without including // exact input duration without including this extra bit.
// this extra bit. We just add up all the increments // We just add up all the increments here, and deduct the
// here, and deduct the extra afterwards. // extra afterwards.
m_inputDuration += m_increment; m_inputDuration += m_increment;
// cerr << "incr input duration by increment: " << m_increment << " -> " << m_inputDuration << endl; // cerr << "incr input duration by increment: " << m_increment << " -> " << m_inputDuration << endl;
@@ -943,8 +978,8 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
m_inputDuration += rs; m_inputDuration += rs;
// cerr << "incr input duration by read space: " << rs << " -> " << m_inputDuration << endl; // cerr << "incr input duration by read space: " << rs << " -> " << m_inputDuration << endl;
if (m_inputDuration > m_windowSize/2) { // deducting the extra if (m_inputDuration > m_aWindowSize/2) { // deducting the extra
m_inputDuration -= m_windowSize/2; m_inputDuration -= m_aWindowSize/2;
} }
} }
@@ -1029,7 +1064,7 @@ RubberBandStretcher::Impl::calculateStretch()
if (i >= m_silence.size()) break; if (i >= m_silence.size()) break;
if (m_silence[i]) ++history; if (m_silence[i]) ++history;
else history = 0; else history = 0;
if (history >= int(m_windowSize / m_increment) && increments[i] >= 0) { if (history >= int(m_aWindowSize / m_increment) && increments[i] >= 0) {
increments[i] = -increments[i]; increments[i] = -increments[i];
if (m_debugLevel > 1) { if (m_debugLevel > 1) {
std::cerr << "phase reset on silence (silent history == " std::cerr << "phase reset on silence (silent history == "
@@ -1073,16 +1108,16 @@ RubberBandStretcher::Impl::getSamplesRequired() const
// See notes in testInbufReadSpace // See notes in testInbufReadSpace
if (rs < m_windowSize && !cd.draining) { if (rs < m_aWindowSize && !cd.draining) {
if (cd.inputSize == -1) { if (cd.inputSize == -1) {
reqdHere = m_windowSize - rs; reqdHere = m_aWindowSize - rs;
if (reqdHere > reqd) reqd = reqdHere; if (reqdHere > reqd) reqd = reqdHere;
continue; continue;
} }
if (rs == 0) { if (rs == 0) {
reqdHere = m_windowSize; reqdHere = m_aWindowSize;
if (reqdHere > reqd) reqd = reqdHere; if (reqdHere > reqd) reqd = reqdHere;
continue; continue;
} }
@@ -1110,7 +1145,7 @@ RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bo
for (size_t c = 0; c < m_channels; ++c) { for (size_t c = 0; c < m_channels; ++c) {
m_channelData[c]->reset(); m_channelData[c]->reset();
m_channelData[c]->inbuf->zero(m_windowSize/2); m_channelData[c]->inbuf->zero(m_aWindowSize/2);
} }
if (m_threaded) { if (m_threaded) {

View File

@@ -123,7 +123,11 @@ protected:
double m_timeRatio; double m_timeRatio;
double m_pitchScale; double m_pitchScale;
size_t m_windowSize; // n.b. either m_fftSize is an integer multiple of m_windowSize,
// or vice versa
size_t m_fftSize;
size_t m_aWindowSize; //!!! or use m_awindow->getSize() throughout?
size_t m_sWindowSize; //!!! or use m_swindow->getSize() throughout?
size_t m_increment; size_t m_increment;
size_t m_outbufSize; size_t m_outbufSize;
@@ -145,7 +149,8 @@ protected:
ProcessMode m_mode; ProcessMode m_mode;
std::map<size_t, Window<float> *> m_windows; std::map<size_t, Window<float> *> m_windows;
Window<float> *m_window; Window<float> *m_awindow;
Window<float> *m_swindow;
FFT *m_studyFFT; FFT *m_studyFFT;
Condition m_spaceAvailable; Condition m_spaceAvailable;
@@ -194,7 +199,7 @@ protected:
float m_freq1; float m_freq1;
float m_freq2; float m_freq2;
size_t m_baseWindowSize; size_t m_baseFftSize;
float m_rateMultiple; float m_rateMultiple;
void writeOutput(RingBuffer<float> &to, float *from, void writeOutput(RingBuffer<float> &to, float *from,
@@ -202,7 +207,7 @@ protected:
static int m_defaultDebugLevel; static int m_defaultDebugLevel;
static const size_t m_defaultIncrement; static const size_t m_defaultIncrement;
static const size_t m_defaultWindowSize; static const size_t m_defaultFftSize;
}; };
} }

View File

@@ -215,8 +215,8 @@ RubberBandStretcher::Impl::processChunks(size_t c, bool &any, bool &last)
any = true; any = true;
if (!cd.draining) { if (!cd.draining) {
size_t got = cd.inbuf->peek(cd.fltbuf, m_windowSize); size_t got = cd.inbuf->peek(cd.fltbuf, m_aWindowSize);
assert(got == m_windowSize || cd.inputSize >= 0); assert(got == m_aWindowSize || cd.inputSize >= 0);
cd.inbuf->skip(m_increment); cd.inbuf->skip(m_increment);
} }
@@ -224,20 +224,20 @@ RubberBandStretcher::Impl::processChunks(size_t c, bool &any, bool &last)
size_t phaseIncrement, shiftIncrement; size_t phaseIncrement, shiftIncrement;
getIncrements(c, phaseIncrement, shiftIncrement, phaseReset); getIncrements(c, phaseIncrement, shiftIncrement, phaseReset);
if (shiftIncrement <= m_windowSize) { if (shiftIncrement <= m_aWindowSize) {
analyseChunk(c); analyseChunk(c);
last = processChunkForChannel last = processChunkForChannel
(c, phaseIncrement, shiftIncrement, phaseReset); (c, phaseIncrement, shiftIncrement, phaseReset);
} else { } else {
size_t bit = m_windowSize/4; size_t bit = m_aWindowSize/4;
if (m_debugLevel > 1) { if (m_debugLevel > 1) {
cerr << "channel " << c << " breaking down overlong increment " << shiftIncrement << " into " << bit << "-size bits" << endl; cerr << "channel " << c << " breaking down overlong increment " << shiftIncrement << " into " << bit << "-size bits" << endl;
} }
analyseChunk(c); analyseChunk(c);
float *tmp = (float *)alloca(m_windowSize * sizeof(float)); float *tmp = (float *)alloca(m_aWindowSize * sizeof(float));
v_copy(tmp, cd.fltbuf, m_windowSize); v_copy(tmp, cd.fltbuf, m_aWindowSize);
for (size_t i = 0; i < shiftIncrement; i += bit) { for (size_t i = 0; i < shiftIncrement; i += bit) {
v_copy(cd.fltbuf, tmp, m_windowSize); v_copy(cd.fltbuf, tmp, m_aWindowSize);
size_t thisIncrement = bit; size_t thisIncrement = bit;
if (i + thisIncrement > shiftIncrement) { if (i + thisIncrement > shiftIncrement) {
thisIncrement = shiftIncrement - i; thisIncrement = shiftIncrement - i;
@@ -270,8 +270,8 @@ RubberBandStretcher::Impl::processOneChunk()
if (!testInbufReadSpace(c)) return false; if (!testInbufReadSpace(c)) return false;
ChannelData &cd = *m_channelData[c]; ChannelData &cd = *m_channelData[c];
if (!cd.draining) { if (!cd.draining) {
size_t got = cd.inbuf->peek(cd.fltbuf, m_windowSize); size_t got = cd.inbuf->peek(cd.fltbuf, m_aWindowSize);
assert(got == m_windowSize || cd.inputSize >= 0); assert(got == m_aWindowSize || cd.inputSize >= 0);
cd.inbuf->skip(m_increment); cd.inbuf->skip(m_increment);
analyseChunk(c); analyseChunk(c);
} }
@@ -302,7 +302,7 @@ RubberBandStretcher::Impl::testInbufReadSpace(size_t c)
size_t rs = inbuf.getReadSpace(); size_t rs = inbuf.getReadSpace();
if (rs < m_windowSize && !cd.draining) { if (rs < m_aWindowSize && !cd.draining) {
if (cd.inputSize == -1) { if (cd.inputSize == -1) {
@@ -328,7 +328,7 @@ RubberBandStretcher::Impl::testInbufReadSpace(size_t c)
} }
return false; return false;
} else if (rs < m_windowSize/2) { } else if (rs < m_aWindowSize/2) {
if (m_debugLevel > 1) { if (m_debugLevel > 1) {
cerr << "read space = " << rs << ", setting draining true" << endl; cerr << "read space = " << rs << ", setting draining true" << endl;
@@ -356,7 +356,7 @@ RubberBandStretcher::Impl::processChunkForChannel(size_t c,
if (phaseReset && (m_debugLevel > 1)) { if (phaseReset && (m_debugLevel > 1)) {
cerr << "processChunkForChannel: phase reset found, incrs " cerr << "processChunkForChannel: phase reset found, incrs "
<< phaseIncrement << ":" << shiftIncrement << endl; << phaseIncrement << ":" << shiftIncrement << endl;
} }
ChannelData &cd = *m_channelData[c]; ChannelData &cd = *m_channelData[c];
@@ -368,12 +368,12 @@ RubberBandStretcher::Impl::processChunkForChannel(size_t c,
// to write from the existing accumulator into the output. // to write from the existing accumulator into the output.
// We know we have enough samples available in m_inbuf -- // We know we have enough samples available in m_inbuf --
// this is usually m_windowSize, but we know that if fewer // this is usually m_aWindowSize, but we know that if fewer
// are available, it's OK to use zeroes for the rest // are available, it's OK to use zeroes for the rest
// (which the ring buffer will provide) because we've // (which the ring buffer will provide) because we've
// reached the true end of the data. // reached the true end of the data.
// We need to peek m_windowSize samples for processing, and // We need to peek m_aWindowSize samples for processing, and
// then skip m_increment to advance the read pointer. // then skip m_increment to advance the read pointer.
modifyChunk(c, phaseIncrement, phaseReset); modifyChunk(c, phaseIncrement, phaseReset);
@@ -474,7 +474,7 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
} }
} }
const int hs = m_windowSize/2 + 1; const int hs = m_fftSize/2 + 1;
// Normally we would mix down the time-domain signal and apply a // Normally we would mix down the time-domain signal and apply a
// single FFT, or else mix down the Cartesian form of the // single FFT, or else mix down the Cartesian form of the
@@ -544,7 +544,7 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
if (silent) ++m_silentHistory; if (silent) ++m_silentHistory;
else m_silentHistory = 0; else m_silentHistory = 0;
if (m_silentHistory >= int(m_windowSize / m_increment) && !phaseReset) { if (m_silentHistory >= int(m_aWindowSize / m_increment) && !phaseReset) {
phaseReset = true; phaseReset = true;
if (m_debugLevel > 1) { if (m_debugLevel > 1) {
cerr << "calculateIncrements: phase reset on silence (silent history == " cerr << "calculateIncrements: phase reset on silence (silent history == "
@@ -641,37 +641,24 @@ RubberBandStretcher::Impl::analyseChunk(size_t channel)
double *const R__ dblbuf = cd.dblbuf; double *const R__ dblbuf = cd.dblbuf;
float *const R__ fltbuf = cd.fltbuf; float *const R__ fltbuf = cd.fltbuf;
int sz = m_windowSize; int sz = m_fftSize;
int hs = m_windowSize/2; int hs = sz / 2;
// cd.fltbuf is known to contain m_windowSize samples // cd.fltbuf is known to contain m_aWindowSize samples
m_window->cut(fltbuf); m_awindow->cut(fltbuf);
if (cd.oversample > 1) { if (m_aWindowSize == m_fftSize) {
int bufsiz = sz * cd.oversample;
int offset = (bufsiz - sz) / 2;
// eek
for (i = 0; i < offset; ++i) {
dblbuf[i] = 0.0;
}
for (i = 0; i < offset; ++i) {
dblbuf[bufsiz - i - 1] = 0.0;
}
for (i = 0; i < sz; ++i) {
dblbuf[offset + i] = fltbuf[i];
}
for (i = 0; i < bufsiz / 2; ++i) {
double tmp = dblbuf[i];
dblbuf[i] = dblbuf[i + bufsiz/2];
dblbuf[i + bufsiz/2] = tmp;
}
} else {
v_convert(dblbuf, fltbuf + hs, hs); v_convert(dblbuf, fltbuf + hs, hs);
v_convert(dblbuf + hs, fltbuf, hs); v_convert(dblbuf + hs, fltbuf, hs);
} else {
v_zero(dblbuf, sz);
int j = sz - m_aWindowSize/2;
while (j < 0) j += sz;
for (int i = 0; i < m_aWindowSize; ++i) {
dblbuf[j] += fltbuf[i];
if (++j == sz) j = 0;
}
} }
cd.fft->forwardPolar(dblbuf, cd.mag, cd.phase); cd.fft->forwardPolar(dblbuf, cd.mag, cd.phase);
@@ -691,15 +678,14 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel,
} }
const double rate = m_sampleRate; const double rate = m_sampleRate;
const int sz = m_windowSize; const int count = m_fftSize / 2;
const int count = (sz * cd.oversample) / 2;
bool unchanged = cd.unchanged && (outputIncrement == m_increment); bool unchanged = cd.unchanged && (outputIncrement == m_increment);
bool fullReset = phaseReset; bool fullReset = phaseReset;
bool laminar = !(m_options & OptionPhaseIndependent); bool laminar = !(m_options & OptionPhaseIndependent);
bool bandlimited = (m_options & OptionTransientsMixed); bool bandlimited = (m_options & OptionTransientsMixed);
int bandlow = lrint((150 * sz * cd.oversample) / rate); int bandlow = lrint((150 * m_fftSize) / rate);
int bandhigh = lrint((1000 * sz * cd.oversample) / rate); int bandhigh = lrint((1000 * m_fftSize) / rate);
float freq0 = m_freq0; float freq0 = m_freq0;
float freq1 = m_freq1; float freq1 = m_freq1;
@@ -717,9 +703,9 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel,
} }
} }
int limit0 = lrint((freq0 * sz * cd.oversample) / rate); int limit0 = lrint((freq0 * m_fftSize) / rate);
int limit1 = lrint((freq1 * sz * cd.oversample) / rate); int limit1 = lrint((freq1 * m_fftSize) / rate);
int limit2 = lrint((freq2 * sz * cd.oversample) / rate); int limit2 = lrint((freq2 * m_fftSize) / rate);
if (limit1 < limit0) limit1 = limit0; if (limit1 < limit0) limit1 = limit0;
if (limit2 < limit1) limit2 = limit1; if (limit2 < limit1) limit2 = limit1;
@@ -758,7 +744,7 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel,
if (!resetThis) { if (!resetThis) {
double omega = (2 * M_PI * m_increment * i) / (sz * cd.oversample); double omega = (2 * M_PI * m_increment * i) / (m_fftSize);
double pp = cd.prevPhase[i]; double pp = cd.prevPhase[i];
double ep = pp + omega; double ep = pp + omega;
@@ -833,8 +819,8 @@ RubberBandStretcher::Impl::formantShiftChunk(size_t channel)
double *const R__ envelope = cd.envelope; double *const R__ envelope = cd.envelope;
double *const R__ dblbuf = cd.dblbuf; double *const R__ dblbuf = cd.dblbuf;
const int sz = m_windowSize; const int sz = m_fftSize;
const int hs = m_windowSize/2; const int hs = sz / 2;
const double factor = 1.0 / sz; const double factor = 1.0 / sz;
cd.fft->inverseCepstral(mag, dblbuf); cd.fft->inverseCepstral(mag, dblbuf);
@@ -861,7 +847,7 @@ RubberBandStretcher::Impl::formantShiftChunk(size_t channel)
// scaling up, we want a new envelope that is lower by the pitch factor // scaling up, we want a new envelope that is lower by the pitch factor
for (int target = 0; target <= hs; ++target) { for (int target = 0; target <= hs; ++target) {
int source = lrint(target * m_pitchScale); int source = lrint(target * m_pitchScale);
if (source > int(m_windowSize)) { if (source > sz) {
envelope[target] = 0.0; envelope[target] = 0.0;
} else { } else {
envelope[target] = envelope[source]; envelope[target] = envelope[source];
@@ -899,47 +885,40 @@ RubberBandStretcher::Impl::synthesiseChunk(size_t channel)
float *const R__ accumulator = cd.accumulator; float *const R__ accumulator = cd.accumulator;
float *const R__ windowAccumulator = cd.windowAccumulator; float *const R__ windowAccumulator = cd.windowAccumulator;
int sz = m_windowSize; int sz = m_fftSize;
int hs = m_windowSize/2; int hs = sz / 2;
int i; int i;
if (!cd.unchanged) { if (!cd.unchanged) {
cd.fft->inversePolar(cd.mag, cd.phase, cd.dblbuf); cd.fft->inversePolar(cd.mag, cd.phase, cd.dblbuf);
if (cd.oversample > 1) { // our ffts produced unscaled results
float factor = 1.0 / m_fftSize;
v_scale(dblbuf, factor, sz);
int bufsiz = sz * cd.oversample; if (m_sWindowSize == m_fftSize) {
int hbs = hs * cd.oversample;
int offset = (bufsiz - sz) / 2;
for (i = 0; i < hbs; ++i) {
double tmp = dblbuf[i];
dblbuf[i] = dblbuf[i + hbs];
dblbuf[i + hbs] = tmp;
}
for (i = 0; i < sz; ++i) {
fltbuf[i] = float(dblbuf[i + offset]);
}
} else {
v_convert(fltbuf, dblbuf + hs, hs); v_convert(fltbuf, dblbuf + hs, hs);
v_convert(fltbuf + hs, dblbuf, hs); v_convert(fltbuf + hs, dblbuf, hs);
} else {
v_zero(fltbuf, m_sWindowSize);
int j = sz - m_sWindowSize/2;
while (j < 0) j += sz;
for (int i = 0; i < m_sWindowSize; ++i) {
fltbuf[i] += dblbuf[j];
if (++j == sz) j = 0;
}
} }
// our ffts produced unscaled results
float factor = 1.f / float(sz * cd.oversample);
v_scale(fltbuf, factor, sz);
} }
m_window->cut(fltbuf); m_swindow->cut(fltbuf);
v_add(accumulator, fltbuf, sz); v_add(accumulator, fltbuf, m_sWindowSize);
cd.accumulatorFill = m_windowSize; cd.accumulatorFill = m_sWindowSize;
float fixed = m_window->getArea() * 1.5f; float fixed = m_swindow->getArea() * 1.5f;
m_window->add(windowAccumulator, fixed); m_swindow->add(windowAccumulator, fixed);
} }
void void
@@ -952,7 +931,7 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
float *const R__ accumulator = cd.accumulator; float *const R__ accumulator = cd.accumulator;
float *const R__ windowAccumulator = cd.windowAccumulator; float *const R__ windowAccumulator = cd.windowAccumulator;
const int sz = m_windowSize; const int sz = m_sWindowSize;
const int si = shiftIncrement; const int si = shiftIncrement;
int i; int i;
@@ -1035,7 +1014,7 @@ RubberBandStretcher::Impl::writeOutput(RingBuffer<float> &to, float *from, size_
size_t startSkip = 0; size_t startSkip = 0;
if (!m_realtime) { if (!m_realtime) {
startSkip = lrintf((m_windowSize/2) / m_pitchScale); startSkip = lrintf((m_sWindowSize/2) / m_pitchScale);
} }
if (outCount > startSkip) { if (outCount > startSkip) {

View File

@@ -23,7 +23,7 @@ static const int MaxPerceivedFreq = 16000;
AudioCurveCalculator::AudioCurveCalculator(Parameters parameters) : AudioCurveCalculator::AudioCurveCalculator(Parameters parameters) :
m_sampleRate(parameters.sampleRate), m_sampleRate(parameters.sampleRate),
m_windowSize(parameters.windowSize) m_fftSize(parameters.fftSize)
{ {
recalculateLastPerceivedBin(); recalculateLastPerceivedBin();
} }
@@ -40,9 +40,9 @@ AudioCurveCalculator::setSampleRate(int newRate)
} }
void void
AudioCurveCalculator::setWindowSize(int newSize) AudioCurveCalculator::setFftSize(int newSize)
{ {
m_windowSize = newSize; m_fftSize = newSize;
recalculateLastPerceivedBin(); recalculateLastPerceivedBin();
} }
@@ -53,9 +53,9 @@ AudioCurveCalculator::recalculateLastPerceivedBin()
m_lastPerceivedBin = 0; m_lastPerceivedBin = 0;
return; return;
} }
m_lastPerceivedBin = ((MaxPerceivedFreq * m_windowSize) / m_sampleRate); m_lastPerceivedBin = ((MaxPerceivedFreq * m_fftSize) / m_sampleRate);
if (m_lastPerceivedBin > m_windowSize/2) { if (m_lastPerceivedBin > m_fftSize/2) {
m_lastPerceivedBin = m_windowSize/2; m_lastPerceivedBin = m_fftSize/2;
} }
} }

View File

@@ -27,29 +27,29 @@ class AudioCurveCalculator
{ {
public: public:
struct Parameters { struct Parameters {
Parameters(int _sampleRate, int _windowSize) : Parameters(int _sampleRate, int _fftSize) :
sampleRate(_sampleRate), sampleRate(_sampleRate),
windowSize(_windowSize) fftSize(_fftSize)
{ } { }
int sampleRate; int sampleRate;
int windowSize; int fftSize;
}; };
AudioCurveCalculator(Parameters parameters); AudioCurveCalculator(Parameters parameters);
virtual ~AudioCurveCalculator(); virtual ~AudioCurveCalculator();
int getSampleRate() const { return m_sampleRate; } int getSampleRate() const { return m_sampleRate; }
int getWindowSize() const { return m_windowSize; } int getFftSize() const { return m_fftSize; }
virtual void setSampleRate(int newRate); virtual void setSampleRate(int newRate);
virtual void setWindowSize(int newSize); virtual void setFftSize(int newSize);
Parameters getParameters() const { Parameters getParameters() const {
return Parameters(m_sampleRate, m_windowSize); return Parameters(m_sampleRate, m_fftSize);
} }
void setParameters(Parameters p) { void setParameters(Parameters p) {
setSampleRate(p.sampleRate); setSampleRate(p.sampleRate);
setWindowSize(p.windowSize); setFftSize(p.fftSize);
} }
// You may not mix calls to the various process functions on a // You may not mix calls to the various process functions on a
@@ -65,7 +65,7 @@ public:
protected: protected:
int m_sampleRate; int m_sampleRate;
int m_windowSize; int m_fftSize;
int m_lastPerceivedBin; int m_lastPerceivedBin;
void recalculateLastPerceivedBin(); void recalculateLastPerceivedBin();
}; };

View File

@@ -58,11 +58,11 @@ CompoundAudioCurve::reset()
} }
void void
CompoundAudioCurve::setWindowSize(int newSize) CompoundAudioCurve::setFftSize(int newSize)
{ {
m_percussive.setWindowSize(newSize); m_percussive.setFftSize(newSize);
m_hf.setWindowSize(newSize); m_hf.setFftSize(newSize);
m_windowSize = newSize; m_fftSize = newSize;
m_lastHf = 0.0; m_lastHf = 0.0;
m_lastResult = 0.0; m_lastResult = 0.0;
} }

View File

@@ -37,7 +37,7 @@ public:
}; };
virtual void setType(Type); virtual void setType(Type);
virtual void setWindowSize(int newSize); virtual void setFftSize(int newSize);
virtual float processFloat(const float *R__ mag, int increment); virtual float processFloat(const float *R__ mag, int increment);
virtual double processDouble(const double *R__ mag, int increment); virtual double processDouble(const double *R__ mag, int increment);

View File

@@ -26,7 +26,7 @@ namespace RubberBand
PercussiveAudioCurve::PercussiveAudioCurve(Parameters parameters) : PercussiveAudioCurve::PercussiveAudioCurve(Parameters parameters) :
AudioCurveCalculator(parameters) AudioCurveCalculator(parameters)
{ {
m_prevMag = allocate_and_zero<double>(m_windowSize/2 + 1); m_prevMag = allocate_and_zero<double>(m_fftSize/2 + 1);
} }
PercussiveAudioCurve::~PercussiveAudioCurve() PercussiveAudioCurve::~PercussiveAudioCurve()
@@ -37,14 +37,14 @@ PercussiveAudioCurve::~PercussiveAudioCurve()
void void
PercussiveAudioCurve::reset() PercussiveAudioCurve::reset()
{ {
v_zero(m_prevMag, m_windowSize/2 + 1); v_zero(m_prevMag, m_fftSize/2 + 1);
} }
void void
PercussiveAudioCurve::setWindowSize(int newSize) PercussiveAudioCurve::setFftSize(int newSize)
{ {
m_prevMag = reallocate(m_prevMag, m_windowSize, newSize); m_prevMag = reallocate(m_prevMag, m_fftSize, newSize);
AudioCurveCalculator::setWindowSize(newSize); AudioCurveCalculator::setFftSize(newSize);
reset(); reset();
} }

View File

@@ -27,7 +27,7 @@ public:
virtual ~PercussiveAudioCurve(); virtual ~PercussiveAudioCurve();
virtual void setWindowSize(int newSize); virtual void setFftSize(int newSize);
virtual float processFloat(const float *R__ mag, int increment); virtual float processFloat(const float *R__ mag, int increment);
virtual double processDouble(const double *R__ mag, int increment); virtual double processDouble(const double *R__ mag, int increment);

View File

@@ -42,11 +42,11 @@ SpectralDifferenceAudioCurve::reset()
} }
void void
SpectralDifferenceAudioCurve::setWindowSize(int newSize) SpectralDifferenceAudioCurve::setFftSize(int newSize)
{ {
deallocate(m_tmpbuf); deallocate(m_tmpbuf);
deallocate(m_mag); deallocate(m_mag);
AudioCurveCalculator::setWindowSize(newSize); AudioCurveCalculator::setFftSize(newSize);
m_mag = allocate<double>(m_lastPerceivedBin + 1); m_mag = allocate<double>(m_lastPerceivedBin + 1);
m_tmpbuf = allocate<double>(m_lastPerceivedBin + 1); m_tmpbuf = allocate<double>(m_lastPerceivedBin + 1);
reset(); reset();

View File

@@ -28,7 +28,7 @@ public:
virtual ~SpectralDifferenceAudioCurve(); virtual ~SpectralDifferenceAudioCurve();
virtual void setWindowSize(int newSize); virtual void setFftSize(int newSize);
virtual float processFloat(const float *R__ mag, int increment); virtual float processFloat(const float *R__ mag, int increment);
virtual double processDouble(const double *R__ mag, int increment); virtual double processDouble(const double *R__ mag, int increment);

View File

@@ -44,15 +44,11 @@ T *allocate(size_t count)
if (posix_memalign(&ptr, 16, count * sizeof(T))) { if (posix_memalign(&ptr, 16, count * sizeof(T))) {
ptr = malloc(count * sizeof(T)); ptr = malloc(count * sizeof(T));
} }
#else
#ifdef __MSVC__
ptr = _aligned_malloc(count * sizeof(T), 16);
#else #else
// Note that malloc always aligns to 16 byte boundaries on OS/X, // Note that malloc always aligns to 16 byte boundaries on OS/X,
// so we don't need posix_memalign there (which is fortunate, // so we don't need posix_memalign there (which is fortunate,
// since it doesn't exist) // since it doesn't exist)
ptr = malloc(count * sizeof(T)); ptr = malloc(count * sizeof(T));
#endif
#endif #endif
if (!ptr) throw(std::bad_alloc()); if (!ptr) throw(std::bad_alloc());
return (T *)ptr; return (T *)ptr;
@@ -70,11 +66,7 @@ T *allocate_and_zero(size_t count)
template <typename T> template <typename T>
void deallocate(T *ptr) void deallocate(T *ptr)
{ {
#ifdef __MSVC__
if (ptr) _aligned_free((void *)ptr);
#else
if (ptr) free((void *)ptr); if (ptr) free((void *)ptr);
#endif
} }

View File

@@ -47,11 +47,6 @@ void gettimeofday(struct timeval *p, void *tz);
#endif #endif
#ifdef __MSVC__
void usleep(unsigned long);
#endif
enum ProcessStatus { ProcessRunning, ProcessNotRunning, UnknownProcessStatus }; enum ProcessStatus { ProcessRunning, ProcessNotRunning, UnknownProcessStatus };
extern ProcessStatus GetProcessStatus(int pid); extern ProcessStatus GetProcessStatus(int pid);