* 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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user