* 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
* RubberBand::RubberBandStretcher.
*
*
* Threading notes for real-time applications:
*
* Multiple instances of RubberBandStretcher may be created and used

View File

@@ -22,41 +22,39 @@ namespace RubberBand
{
RubberBandStretcher::Impl::ChannelData::ChannelData(size_t windowSize,
int overSample,
size_t outbufSize) :
oversample(overSample)
size_t fftSize,
size_t outbufSize)
{
std::set<size_t> s;
construct(s, windowSize, outbufSize);
construct(s, windowSize, fftSize, outbufSize);
}
RubberBandStretcher::Impl::ChannelData::ChannelData(const std::set<size_t> &windowSizes,
int overSample,
RubberBandStretcher::Impl::ChannelData::ChannelData(const std::set<size_t> &sizes,
size_t initialWindowSize,
size_t outbufSize) :
oversample(overSample)
size_t initialFftSize,
size_t outbufSize)
{
construct(windowSizes, initialWindowSize, outbufSize);
construct(sizes, initialWindowSize, initialFftSize, outbufSize);
}
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 initialFftSize,
size_t outbufSize)
{
size_t maxSize = initialWindowSize;
if (initialFftSize > maxSize) maxSize = initialFftSize;
if (!windowSizes.empty()) {
// std::set is ordered by value
std::set<size_t>::const_iterator i = windowSizes.end();
maxSize = *--i;
}
if (windowSizes.find(initialWindowSize) == windowSizes.end()) {
if (initialWindowSize > maxSize) maxSize = initialWindowSize;
// std::set is ordered by value
std::set<size_t>::const_iterator i = sizes.end();
if (i != sizes.begin()) {
--i;
if (*i > maxSize) maxSize = *i;
}
// max size of the real "half" of freq data
size_t realSize = (maxSize * oversample)/2 + 1;
// max possible size of the real "half" of freq data
size_t realSize = maxSize / 2 + 1;
// 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);
windowAccumulator = allocate<float>(maxSize);
for (std::set<size_t>::const_iterator i = windowSizes.begin();
i != windowSizes.end(); ++i) {
ffts[*i] = new FFT(*i * oversample);
for (std::set<size_t>::const_iterator i = sizes.begin();
i != sizes.end(); ++i) {
ffts[*i] = new FFT(*i);
ffts[*i]->initDouble();
}
if (windowSizes.find(initialWindowSize) == windowSizes.end()) {
ffts[initialWindowSize] = new FFT(initialWindowSize * oversample);
ffts[initialWindowSize]->initDouble();
}
fft = ffts[initialWindowSize];
fft = ffts[initialFftSize];
dblbuf = fft->getDoubleTimeBuffer();
@@ -102,7 +96,7 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
freqPeak[i] = 0;
}
for (size_t i = 0; i < initialWindowSize * oversample; ++i) {
for (size_t i = 0; i < initialFftSize; ++i) {
dblbuf[i] = 0.0;
}
@@ -115,15 +109,16 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
windowAccumulator[0] = 1.f;
}
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 realSize = (windowSize * oversample) / 2 + 1;
size_t maxSize = std::max(windowSize, fftSize);
size_t realSize = maxSize / 2 + 1;
size_t oldMax = inbuf->getSize();
// std::cerr << "ChannelData::setWindowSize(" << windowSize << ") [from " << oldSize << "]" << std::endl;
if (oldSize >= windowSize) { //!!! shurely >= realSize?
if (oldMax >= maxSize) {
// 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
//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
//RT mode with proper initialisation
ffts[windowSize] = new FFT(windowSize * oversample);
ffts[windowSize]->initDouble();
ffts[fftSize] = new FFT(fftSize);
ffts[fftSize]->initDouble();
}
fft = ffts[windowSize];
fft = ffts[fftSize];
dblbuf = fft->getDoubleTimeBuffer();
for (size_t i = 0; i < windowSize * oversample; ++i) {
for (size_t i = 0; i < maxSize; ++i) {
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
//general use in RT mode)
RingBuffer<float> *newbuf = inbuf->resized(windowSize);
RingBuffer<float> *newbuf = inbuf->resized(maxSize);
delete inbuf;
inbuf = newbuf;
// We don't want to preserve data in these arrays
mag = reallocate<double>(mag, oldSize, realSize);
phase = reallocate<double>(phase, oldSize, realSize);
prevPhase = reallocate<double>(prevPhase, oldSize, realSize);
prevError = reallocate<double>(prevError, oldSize, realSize);
unwrappedPhase = reallocate<double>(unwrappedPhase, oldSize, realSize);
envelope = reallocate<double>(envelope, oldSize, realSize);
mag = reallocate<double>(mag, oldMax, realSize);
phase = reallocate<double>(phase, oldMax, realSize);
prevPhase = reallocate<double>(prevPhase, oldMax, realSize);
prevError = reallocate<double>(prevError, oldMax, realSize);
unwrappedPhase = reallocate<double>(unwrappedPhase, oldMax, realSize);
envelope = reallocate<double>(envelope, oldMax, realSize);
delete[] freqPeak;
freqPeak = new size_t[realSize];
deallocate(fltbuf);
fltbuf = allocate<float>(windowSize);
fltbuf = allocate<float>(maxSize);
// 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);
accumulator = newAcc;
newAcc = allocate<float>(windowSize);
newAcc = allocate<float>(maxSize);
v_copy(newAcc, windowAccumulator, oldSize);
v_copy(newAcc, windowAccumulator, oldMax);
deallocate(windowAccumulator);
windowAccumulator = newAcc;
@@ -206,20 +201,20 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
freqPeak[i] = 0;
}
for (size_t i = 0; i < windowSize; ++i) {
for (size_t i = 0; i < maxSize; ++i) {
fltbuf[i] = 0.f;
}
if (ffts.find(windowSize) == ffts.end()) {
ffts[windowSize] = new FFT(windowSize * oversample);
ffts[windowSize]->initDouble();
if (ffts.find(fftSize) == ffts.end()) {
ffts[fftSize] = new FFT(fftSize);
ffts[fftSize]->initDouble();
}
fft = ffts[windowSize];
fft = ffts[fftSize];
dblbuf = fft->getDoubleTimeBuffer();
for (size_t i = 0; i < windowSize * oversample; ++i) {
for (size_t i = 0; i < fftSize; ++i) {
dblbuf[i] = 0.0;
}
}

View File

@@ -32,31 +32,36 @@ public:
/**
* Construct a ChannelData structure.
*
* 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.
* The sizes passed in here are for the time-domain analysis
* window and FFT calculation, and most of the buffer sizes also
* depend on them. In practice they are always powers of two, the
* 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 pitch scale factor and any maximum processing block
* 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
* different FFT sizes without requiring reallocation when the
* size changes. The size can subsequently be changed with a
* 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.
* Construct a ChannelData structure that can process at different
* FFT sizes without requiring reallocation when the size changes.
* The sizes can subsequently be changed with a call to setSizes.
* Reallocation will only be necessary if setSizes is called with
* values not equal to any 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> &windowSizes,
int overSample, size_t initialWindowSize, size_t outbufSize);
ChannelData(const std::set<size_t> &sizes,
size_t initialWindowSize,
size_t initialFftSize,
size_t outbufSize);
~ChannelData();
/**
@@ -65,12 +70,12 @@ public:
void reset();
/**
* Set the FFT and buffer sizes from the given processing
* 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.
* Set the FFT, analysis window, and buffer sizes. If this
* ChannelData was constructed with a set of sizes and the given
* window and FFT sizes here were among them, no reallocation will
* be required.
*/
void setWindowSize(size_t windowSize);
void setSizes(size_t windowSize, size_t fftSizes);
/**
* Set the outbufSize for the channel data. Reallocation will
@@ -94,7 +99,6 @@ public:
double *prevError;
double *unwrappedPhase;
size_t *freqPeak;
float *accumulator;
@@ -123,11 +127,10 @@ public:
float *resamplebuf;
size_t resamplebufSize;
int oversample;
private:
void construct(const std::set<size_t> &windowSizes,
size_t initialWindowSize, size_t outbufSize);
void construct(const std::set<size_t> &sizes,
size_t initialWindowSize, size_t initialFftSize,
size_t outbufSize);
};
}

View File

@@ -52,7 +52,7 @@ const size_t
RubberBandStretcher::Impl::m_defaultIncrement = 256;
const size_t
RubberBandStretcher::Impl::m_defaultWindowSize = 2048;
RubberBandStretcher::Impl::m_defaultFftSize = 2048;
int
RubberBandStretcher::Impl::m_defaultDebugLevel = 0;
@@ -68,17 +68,20 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
m_channels(channels),
m_timeRatio(initialTimeRatio),
m_pitchScale(initialPitchScale),
m_windowSize(m_defaultWindowSize),
m_fftSize(m_defaultFftSize),
m_aWindowSize(m_defaultFftSize),
m_sWindowSize(m_defaultFftSize),
m_increment(m_defaultIncrement),
m_outbufSize(m_defaultWindowSize * 2),
m_maxProcessSize(m_defaultWindowSize),
m_outbufSize(m_defaultFftSize * 2),
m_maxProcessSize(m_defaultFftSize),
m_expectedInputDuration(0),
m_threaded(false),
m_realtime(false),
m_options(options),
m_debugLevel(m_defaultDebugLevel),
m_mode(JustCreated),
m_window(0),
m_awindow(0),
m_swindow(0),
m_studyFFT(0),
m_spaceAvailable("space"),
m_inputDuration(0),
@@ -94,7 +97,7 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
m_freq0(600),
m_freq1(1200),
m_freq2(12000),
m_baseWindowSize(m_defaultWindowSize)
m_baseFftSize(m_defaultFftSize)
{
if (!_initialised) {
system_specific_initialise();
@@ -109,25 +112,27 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
// we don't let it drop below the 48k default
m_rateMultiple = float(m_sampleRate) / 48000.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)) {
cerr << "RubberBandStretcher::Impl::Impl: Cannot specify OptionWindowLong and OptionWindowShort together; falling back to OptionWindowStandard" << endl;
} else if (options & OptionWindowShort) {
m_baseWindowSize = m_baseWindowSize / 2;
m_baseFftSize = m_baseFftSize / 2;
if (m_debugLevel > 0) {
cerr << "setting baseWindowSize to " << m_baseWindowSize << endl;
cerr << "setting baseFftSize to " << m_baseFftSize << endl;
}
} else if (options & OptionWindowLong) {
m_baseWindowSize = m_baseWindowSize * 2;
m_baseFftSize = m_baseFftSize * 2;
if (m_debugLevel > 0) {
cerr << "setting baseWindowSize to " << m_baseWindowSize << endl;
cerr << "setting baseFftSize to " << m_baseFftSize << endl;
}
}
m_windowSize = m_baseWindowSize;
m_outbufSize = m_baseWindowSize * 2;
m_maxProcessSize = m_baseWindowSize;
m_fftSize = m_baseFftSize;
m_aWindowSize = m_baseFftSize;
m_sWindowSize = m_baseFftSize;
m_outbufSize = m_sWindowSize * 2;
m_maxProcessSize = m_aWindowSize;
}
if (m_options & OptionProcessRealTime) {
@@ -378,7 +383,7 @@ void
RubberBandStretcher::Impl::calculateSizes()
{
size_t inputIncrement = m_defaultIncrement;
size_t windowSize = m_baseWindowSize;
size_t windowSize = m_baseFftSize;
size_t outputIncrement;
if (m_pitchScale <= 0.0) {
@@ -413,7 +418,7 @@ RubberBandStretcher::Impl::calculateSizes()
if (outputIncrement < m_defaultIncrement / 4) {
if (outputIncrement < 1) outputIncrement = 1;
while (outputIncrement < m_defaultIncrement / 4 &&
windowSize < m_baseWindowSize * 4) {
windowSize < m_baseFftSize * 4) {
outputIncrement *= 2;
inputIncrement = lrint(ceil(outputIncrement / r));
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
// 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;
// When squashing, the greatest theoretically possible output
@@ -497,18 +504,18 @@ RubberBandStretcher::Impl::calculateSizes()
if (m_debugLevel > 0) {
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) {
m_maxProcessSize = m_windowSize;
if (std::max(m_aWindowSize, m_sWindowSize) > m_maxProcessSize) {
m_maxProcessSize = std::max(m_aWindowSize, m_sWindowSize);
}
m_outbufSize =
size_t
(ceil(max
(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) {
// 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 = "
// << 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;
if (m_windows.empty()) {
prevWindowSize = 0;
prevFftSize = 0;
prevAWindowSize = 0;
prevSWindowSize = 0;
prevOutbufSize = 0;
}
calculateSizes();
bool windowSizeChanged = (prevWindowSize != m_windowSize);
bool fftSizeChanged = (prevFftSize != m_fftSize);
bool windowSizeChanged = ((prevAWindowSize != m_aWindowSize) ||
(prevSWindowSize != m_sWindowSize));
bool outbufSizeChanged = (prevOutbufSize != m_outbufSize);
// 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;
if (m_realtime) {
windowSizes.insert(m_baseWindowSize);
windowSizes.insert(m_baseWindowSize / 2);
windowSizes.insert(m_baseWindowSize * 2);
// windowSizes.insert(m_baseWindowSize * 4);
windowSizes.insert(m_baseFftSize);
windowSizes.insert(m_baseFftSize / 2);
windowSizes.insert(m_baseFftSize * 2);
// windowSizes.insert(m_baseFftSize * 4);
}
windowSizes.insert(m_windowSize);
windowSizes.insert(m_fftSize);
windowSizes.insert(m_aWindowSize);
windowSizes.insert(m_sWindowSize);
if (windowSizeChanged) {
@@ -572,10 +587,11 @@ RubberBandStretcher::Impl::configure()
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) {
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) {
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;
m_studyFFT = new FFT(m_windowSize, m_debugLevel);
m_studyFFT = new FFT(m_fftSize, m_debugLevel);
m_studyFFT->initFloat();
}
@@ -626,21 +645,21 @@ RubberBandStretcher::Impl::configure()
delete m_phaseResetAudioCurve;
m_phaseResetAudioCurve = new CompoundAudioCurve
(CompoundAudioCurve::Parameters(m_sampleRate, m_windowSize));
(CompoundAudioCurve::Parameters(m_sampleRate, m_fftSize));
m_phaseResetAudioCurve->setType(m_detectorType);
delete m_silentAudioCurve;
m_silentAudioCurve = new SilentAudioCurve
(SilentAudioCurve::Parameters(m_sampleRate, m_windowSize));
(SilentAudioCurve::Parameters(m_sampleRate, m_fftSize));
if (!m_realtime) {
delete m_stretchAudioCurve;
if (!(m_options & OptionStretchPrecise)) {
m_stretchAudioCurve = new SpectralDifferenceAudioCurve
(SpectralDifferenceAudioCurve::Parameters(m_sampleRate, m_windowSize));
(SpectralDifferenceAudioCurve::Parameters(m_sampleRate, m_fftSize));
} else {
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) {
for (size_t c = 0; c < m_channels; ++c) {
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();
}
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;
calculateSizes();
@@ -698,18 +719,29 @@ 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 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()) {
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);
if (m_windows.find(m_aWindowSize) == m_windows.end()) {
std::cerr << "WARNING: reconfigure(): window allocation (size " << m_aWindowSize << ") required in RT mode" << std::endl;
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) {
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;
m_channelData[c]->resampler =
new Resampler(Resampler::FastestTolerable, 1, m_windowSize,
new Resampler(Resampler::FastestTolerable, 1, m_sWindowSize,
m_debugLevel);
m_channelData[c]->setResampleBufSize
@@ -735,8 +767,8 @@ RubberBandStretcher::Impl::reconfigure()
}
}
if (m_windowSize != prevWindowSize) {
m_phaseResetAudioCurve->setWindowSize(m_windowSize);
if (m_fftSize != prevFftSize) {
m_phaseResetAudioCurve->setFftSize(m_fftSize);
}
}
@@ -744,7 +776,7 @@ size_t
RubberBandStretcher::Impl::getLatency() const
{
if (!m_realtime) return 0;
return int((m_windowSize/2) / m_pitchScale + 1);
return int((m_aWindowSize/2) / m_pitchScale + 1);
}
void
@@ -887,21 +919,24 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
consumed += writable;
}
while ((inbuf.getReadSpace() >= int(m_windowSize)) ||
(final && (inbuf.getReadSpace() >= int(m_windowSize/2)))) {
while ((inbuf.getReadSpace() >= int(m_aWindowSize)) ||
(final && (inbuf.getReadSpace() >= int(m_aWindowSize/2)))) {
// 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.
// We know we have at least m_aWindowSize samples
// available in m_inbuf. We need to peek m_aWindowSize 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_windowSize);
assert(final || got == m_windowSize);
size_t got = inbuf.peek(cd.accumulator, m_aWindowSize);
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
// interested in magnitude
@@ -925,12 +960,12 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
// cout << df << endl;
// 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
// here, and deduct the extra afterwards.
// We have augmented the input by m_aWindowSize/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 here, and deduct the
// extra afterwards.
m_inputDuration += m_increment;
// 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;
// cerr << "incr input duration by read space: " << rs << " -> " << m_inputDuration << endl;
if (m_inputDuration > m_windowSize/2) { // deducting the extra
m_inputDuration -= m_windowSize/2;
if (m_inputDuration > m_aWindowSize/2) { // deducting the extra
m_inputDuration -= m_aWindowSize/2;
}
}
@@ -1029,7 +1064,7 @@ RubberBandStretcher::Impl::calculateStretch()
if (i >= m_silence.size()) break;
if (m_silence[i]) ++history;
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];
if (m_debugLevel > 1) {
std::cerr << "phase reset on silence (silent history == "
@@ -1073,16 +1108,16 @@ RubberBandStretcher::Impl::getSamplesRequired() const
// See notes in testInbufReadSpace
if (rs < m_windowSize && !cd.draining) {
if (rs < m_aWindowSize && !cd.draining) {
if (cd.inputSize == -1) {
reqdHere = m_windowSize - rs;
reqdHere = m_aWindowSize - rs;
if (reqdHere > reqd) reqd = reqdHere;
continue;
}
if (rs == 0) {
reqdHere = m_windowSize;
reqdHere = m_aWindowSize;
if (reqdHere > reqd) reqd = reqdHere;
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) {
m_channelData[c]->reset();
m_channelData[c]->inbuf->zero(m_windowSize/2);
m_channelData[c]->inbuf->zero(m_aWindowSize/2);
}
if (m_threaded) {

View File

@@ -123,7 +123,11 @@ protected:
double m_timeRatio;
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_outbufSize;
@@ -145,7 +149,8 @@ protected:
ProcessMode m_mode;
std::map<size_t, Window<float> *> m_windows;
Window<float> *m_window;
Window<float> *m_awindow;
Window<float> *m_swindow;
FFT *m_studyFFT;
Condition m_spaceAvailable;
@@ -194,7 +199,7 @@ protected:
float m_freq1;
float m_freq2;
size_t m_baseWindowSize;
size_t m_baseFftSize;
float m_rateMultiple;
void writeOutput(RingBuffer<float> &to, float *from,
@@ -202,7 +207,7 @@ protected:
static int m_defaultDebugLevel;
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;
if (!cd.draining) {
size_t got = cd.inbuf->peek(cd.fltbuf, m_windowSize);
assert(got == m_windowSize || cd.inputSize >= 0);
size_t got = cd.inbuf->peek(cd.fltbuf, m_aWindowSize);
assert(got == m_aWindowSize || cd.inputSize >= 0);
cd.inbuf->skip(m_increment);
}
@@ -224,20 +224,20 @@ RubberBandStretcher::Impl::processChunks(size_t c, bool &any, bool &last)
size_t phaseIncrement, shiftIncrement;
getIncrements(c, phaseIncrement, shiftIncrement, phaseReset);
if (shiftIncrement <= m_windowSize) {
if (shiftIncrement <= m_aWindowSize) {
analyseChunk(c);
last = processChunkForChannel
(c, phaseIncrement, shiftIncrement, phaseReset);
} else {
size_t bit = m_windowSize/4;
size_t bit = m_aWindowSize/4;
if (m_debugLevel > 1) {
cerr << "channel " << c << " breaking down overlong increment " << shiftIncrement << " into " << bit << "-size bits" << endl;
}
analyseChunk(c);
float *tmp = (float *)alloca(m_windowSize * sizeof(float));
v_copy(tmp, cd.fltbuf, m_windowSize);
float *tmp = (float *)alloca(m_aWindowSize * sizeof(float));
v_copy(tmp, cd.fltbuf, m_aWindowSize);
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;
if (i + thisIncrement > shiftIncrement) {
thisIncrement = shiftIncrement - i;
@@ -270,8 +270,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_windowSize);
assert(got == m_windowSize || cd.inputSize >= 0);
size_t got = cd.inbuf->peek(cd.fltbuf, m_aWindowSize);
assert(got == m_aWindowSize || cd.inputSize >= 0);
cd.inbuf->skip(m_increment);
analyseChunk(c);
}
@@ -302,7 +302,7 @@ RubberBandStretcher::Impl::testInbufReadSpace(size_t c)
size_t rs = inbuf.getReadSpace();
if (rs < m_windowSize && !cd.draining) {
if (rs < m_aWindowSize && !cd.draining) {
if (cd.inputSize == -1) {
@@ -328,7 +328,7 @@ RubberBandStretcher::Impl::testInbufReadSpace(size_t c)
}
return false;
} else if (rs < m_windowSize/2) {
} else if (rs < m_aWindowSize/2) {
if (m_debugLevel > 1) {
cerr << "read space = " << rs << ", setting draining true" << endl;
@@ -356,7 +356,7 @@ RubberBandStretcher::Impl::processChunkForChannel(size_t c,
if (phaseReset && (m_debugLevel > 1)) {
cerr << "processChunkForChannel: phase reset found, incrs "
<< phaseIncrement << ":" << shiftIncrement << endl;
<< phaseIncrement << ":" << shiftIncrement << endl;
}
ChannelData &cd = *m_channelData[c];
@@ -368,12 +368,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_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
// (which the ring buffer will provide) because we've
// 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.
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
// 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;
else m_silentHistory = 0;
if (m_silentHistory >= int(m_windowSize / m_increment) && !phaseReset) {
if (m_silentHistory >= int(m_aWindowSize / m_increment) && !phaseReset) {
phaseReset = true;
if (m_debugLevel > 1) {
cerr << "calculateIncrements: phase reset on silence (silent history == "
@@ -641,37 +641,24 @@ RubberBandStretcher::Impl::analyseChunk(size_t channel)
double *const R__ dblbuf = cd.dblbuf;
float *const R__ fltbuf = cd.fltbuf;
int sz = m_windowSize;
int hs = m_windowSize/2;
int sz = m_fftSize;
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) {
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 {
if (m_aWindowSize == m_fftSize) {
v_convert(dblbuf, fltbuf + hs, 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);
@@ -691,15 +678,14 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel,
}
const double rate = m_sampleRate;
const int sz = m_windowSize;
const int count = (sz * cd.oversample) / 2;
const int count = m_fftSize / 2;
bool unchanged = cd.unchanged && (outputIncrement == m_increment);
bool fullReset = phaseReset;
bool laminar = !(m_options & OptionPhaseIndependent);
bool bandlimited = (m_options & OptionTransientsMixed);
int bandlow = lrint((150 * sz * cd.oversample) / rate);
int bandhigh = lrint((1000 * sz * cd.oversample) / rate);
int bandlow = lrint((150 * m_fftSize) / rate);
int bandhigh = lrint((1000 * m_fftSize) / rate);
float freq0 = m_freq0;
float freq1 = m_freq1;
@@ -717,9 +703,9 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel,
}
}
int limit0 = lrint((freq0 * sz * cd.oversample) / rate);
int limit1 = lrint((freq1 * sz * cd.oversample) / rate);
int limit2 = lrint((freq2 * sz * cd.oversample) / rate);
int limit0 = lrint((freq0 * m_fftSize) / rate);
int limit1 = lrint((freq1 * m_fftSize) / rate);
int limit2 = lrint((freq2 * m_fftSize) / rate);
if (limit1 < limit0) limit1 = limit0;
if (limit2 < limit1) limit2 = limit1;
@@ -758,7 +744,7 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel,
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 ep = pp + omega;
@@ -833,8 +819,8 @@ RubberBandStretcher::Impl::formantShiftChunk(size_t channel)
double *const R__ envelope = cd.envelope;
double *const R__ dblbuf = cd.dblbuf;
const int sz = m_windowSize;
const int hs = m_windowSize/2;
const int sz = m_fftSize;
const int hs = sz / 2;
const double factor = 1.0 / sz;
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
for (int target = 0; target <= hs; ++target) {
int source = lrint(target * m_pitchScale);
if (source > int(m_windowSize)) {
if (source > sz) {
envelope[target] = 0.0;
} else {
envelope[target] = envelope[source];
@@ -899,47 +885,40 @@ RubberBandStretcher::Impl::synthesiseChunk(size_t channel)
float *const R__ accumulator = cd.accumulator;
float *const R__ windowAccumulator = cd.windowAccumulator;
int sz = m_windowSize;
int hs = m_windowSize/2;
int sz = m_fftSize;
int hs = sz / 2;
int i;
if (!cd.unchanged) {
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;
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 {
if (m_sWindowSize == m_fftSize) {
v_convert(fltbuf, dblbuf + hs, 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;
m_window->add(windowAccumulator, fixed);
float fixed = m_swindow->getArea() * 1.5f;
m_swindow->add(windowAccumulator, fixed);
}
void
@@ -952,7 +931,7 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
float *const R__ accumulator = cd.accumulator;
float *const R__ windowAccumulator = cd.windowAccumulator;
const int sz = m_windowSize;
const int sz = m_sWindowSize;
const int si = shiftIncrement;
int i;
@@ -1035,7 +1014,7 @@ RubberBandStretcher::Impl::writeOutput(RingBuffer<float> &to, float *from, size_
size_t startSkip = 0;
if (!m_realtime) {
startSkip = lrintf((m_windowSize/2) / m_pitchScale);
startSkip = lrintf((m_sWindowSize/2) / m_pitchScale);
}
if (outCount > startSkip) {

View File

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

View File

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

View File

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

View File

@@ -37,7 +37,7 @@ public:
};
virtual void setType(Type);
virtual void setWindowSize(int newSize);
virtual void setFftSize(int newSize);
virtual float processFloat(const float *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) :
AudioCurveCalculator(parameters)
{
m_prevMag = allocate_and_zero<double>(m_windowSize/2 + 1);
m_prevMag = allocate_and_zero<double>(m_fftSize/2 + 1);
}
PercussiveAudioCurve::~PercussiveAudioCurve()
@@ -37,14 +37,14 @@ PercussiveAudioCurve::~PercussiveAudioCurve()
void
PercussiveAudioCurve::reset()
{
v_zero(m_prevMag, m_windowSize/2 + 1);
v_zero(m_prevMag, m_fftSize/2 + 1);
}
void
PercussiveAudioCurve::setWindowSize(int newSize)
PercussiveAudioCurve::setFftSize(int newSize)
{
m_prevMag = reallocate(m_prevMag, m_windowSize, newSize);
AudioCurveCalculator::setWindowSize(newSize);
m_prevMag = reallocate(m_prevMag, m_fftSize, newSize);
AudioCurveCalculator::setFftSize(newSize);
reset();
}

View File

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

View File

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

View File

@@ -28,7 +28,7 @@ public:
virtual ~SpectralDifferenceAudioCurve();
virtual void setWindowSize(int newSize);
virtual void setFftSize(int newSize);
virtual float processFloat(const float *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))) {
ptr = malloc(count * sizeof(T));
}
#else
#ifdef __MSVC__
ptr = _aligned_malloc(count * sizeof(T), 16);
#else
// Note that malloc always aligns to 16 byte boundaries on OS/X,
// so we don't need posix_memalign there (which is fortunate,
// since it doesn't exist)
ptr = malloc(count * sizeof(T));
#endif
#endif
if (!ptr) throw(std::bad_alloc());
return (T *)ptr;
@@ -70,11 +66,7 @@ T *allocate_and_zero(size_t count)
template <typename T>
void deallocate(T *ptr)
{
#ifdef __MSVC__
if (ptr) _aligned_free((void *)ptr);
#else
if (ptr) free((void *)ptr);
#endif
}

View File

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