* Fix failure to remember that we have constructed an interpolator

window already (#25).  Also avoid using alloca for substantial buffers
* Lose FFT::getFloatTimeBuffer and getDoubleTimeBuffer -- it's too
unclear when it's safe to use them and it's safer to control sizes externally.
In RB with smoothing on, these buffers were incorrectly being used for window-si
zed calculations (larger than FFT-sized).
* Fix some incorrect buffer resize sizes
* Build fixes for OS/X
This commit is contained in:
Chris Cannam
2011-03-19 12:41:38 +00:00
parent 0b8c1bd90b
commit c45acda473
15 changed files with 133 additions and 205 deletions

View File

@@ -70,9 +70,10 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &sizes,
unwrappedPhase = allocate_and_zero<process_t>(realSize);
envelope = allocate_and_zero<process_t>(realSize);
freqPeak = new size_t[realSize];
freqPeak = allocate_and_zero<size_t>(realSize);
fltbuf = allocate_and_zero<float>(maxSize);
dblbuf = allocate_and_zero<process_t>(maxSize);
accumulator = allocate_and_zero<float>(maxSize);
windowAccumulator = allocate_and_zero<float>(maxSize);
@@ -90,31 +91,12 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &sizes,
}
fft = ffts[initialFftSize];
if (sizeof(process_t) == sizeof(double)) {
dblbuf = (process_t *)fft->getDoubleTimeBuffer();
} else {
dblbuf = (process_t *)fft->getFloatTimeBuffer();
}
resampler = 0;
resamplebuf = 0;
resamplebufSize = 0;
reset();
for (size_t i = 0; i < realSize; ++i) {
freqPeak[i] = 0;
}
for (size_t i = 0; i < initialFftSize; ++i) {
dblbuf[i] = 0.0;
}
for (size_t i = 0; i < maxSize; ++i) {
accumulator[i] = 0.f;
windowAccumulator[i] = 0.f;
}
// Avoid dividing opening sample (which will be discarded anyway) by zero
windowAccumulator[0] = 1.f;
}
@@ -127,6 +109,7 @@ RubberBandStretcher::Impl::ChannelData::setSizes(size_t windowSize,
size_t maxSize = std::max(windowSize, fftSize);
size_t realSize = maxSize / 2 + 1;
size_t oldMax = inbuf->getSize();
size_t oldReal = oldMax / 2 + 1;
if (oldMax >= maxSize) {
@@ -149,12 +132,7 @@ RubberBandStretcher::Impl::ChannelData::setSizes(size_t windowSize,
fft = ffts[fftSize];
if (sizeof(process_t) == sizeof(double)) {
dblbuf = (process_t *)fft->getDoubleTimeBuffer();
} else {
dblbuf = (process_t *)fft->getFloatTimeBuffer();
}
v_zero(fltbuf, maxSize);
v_zero(dblbuf, maxSize);
v_zero(mag, realSize);
@@ -180,34 +158,25 @@ RubberBandStretcher::Impl::ChannelData::setSizes(size_t windowSize,
// We don't want to preserve data in these arrays
mag = reallocate_and_zero<process_t>(mag, oldMax, realSize);
phase = reallocate_and_zero<process_t>(phase, oldMax, realSize);
prevPhase = reallocate_and_zero<process_t>(prevPhase, oldMax, realSize);
prevError = reallocate_and_zero<process_t>(prevError, oldMax, realSize);
unwrappedPhase = reallocate_and_zero<process_t>(unwrappedPhase, oldMax, realSize);
envelope = reallocate_and_zero<process_t>(envelope, oldMax, realSize);
mag = reallocate_and_zero(mag, oldReal, realSize);
phase = reallocate_and_zero(phase, oldReal, realSize);
prevPhase = reallocate_and_zero(prevPhase, oldReal, realSize);
prevError = reallocate_and_zero(prevError, oldReal, realSize);
unwrappedPhase = reallocate_and_zero(unwrappedPhase, oldReal, realSize);
envelope = reallocate_and_zero(envelope, oldReal, realSize);
freqPeak = reallocate_and_zero(freqPeak, oldReal, realSize);
fltbuf = reallocate_and_zero(fltbuf, oldMax, maxSize);
dblbuf = reallocate_and_zero(dblbuf, oldMax, maxSize);
delete[] freqPeak;
freqPeak = new size_t[realSize];
deallocate(fltbuf);
fltbuf = allocate_and_zero<float>(maxSize);
interpolator = reallocate_and_zero<float>(interpolator, oldMax, maxSize);
// But we do want to preserve data in these
float *newAcc = allocate_and_zero<float>(maxSize);
accumulator = reallocate_and_zero_extension
(accumulator, oldMax, maxSize);
v_copy(newAcc, accumulator, oldMax);
deallocate(accumulator);
accumulator = newAcc;
newAcc = allocate_and_zero<float>(maxSize);
v_copy(newAcc, windowAccumulator, oldMax);
deallocate(windowAccumulator);
windowAccumulator = newAcc;
windowAccumulator = reallocate_and_zero_extension
(windowAccumulator, oldMax, maxSize);
interpolatorScale = 0;
@@ -223,14 +192,6 @@ RubberBandStretcher::Impl::ChannelData::setSizes(size_t windowSize,
}
fft = ffts[fftSize];
if (sizeof(process_t) == sizeof(double)) {
dblbuf = (process_t *)fft->getDoubleTimeBuffer();
} else {
dblbuf = (process_t *)fft->getFloatTimeBuffer();
}
v_zero(dblbuf, fftSize);
}
void
@@ -273,7 +234,7 @@ RubberBandStretcher::Impl::ChannelData::~ChannelData()
deallocate(prevError);
deallocate(unwrappedPhase);
deallocate(envelope);
delete[] freqPeak;
deallocate(freqPeak);
deallocate(accumulator);
deallocate(windowAccumulator);
deallocate(fltbuf);

View File

@@ -783,8 +783,10 @@ RubberBandStretcher::Impl::reconfigure()
new Resampler(Resampler::FastestTolerable, 1, m_sWindowSize,
m_debugLevel);
m_channelData[c]->setResampleBufSize
(lrintf(ceil((m_increment * m_timeRatio * 2) / m_pitchScale)));
size_t rbs =
lrintf(ceil((m_increment * m_timeRatio * 2) / m_pitchScale));
if (rbs < m_increment * 16) rbs = m_increment * 16;
m_channelData[c]->setResampleBufSize(rbs);
}
}

View File

@@ -886,7 +886,7 @@ RubberBandStretcher::Impl::synthesiseChunk(size_t channel,
const int hs = fsz / 2;
const int wsz = m_sWindowSize;
if (!cd.unchanged) {
cd.fft->inversePolar(cd.mag, cd.phase, cd.dblbuf);
@@ -910,22 +910,27 @@ RubberBandStretcher::Impl::synthesiseChunk(size_t channel,
}
if (wsz > fsz) {
float *tmp = (float *)alloca(wsz * sizeof(float));
int p = shiftIncrement * 2;
if (cd.interpolatorScale != p) {
SincWindow<float>::write(cd.interpolator, wsz, p);
cd.interpolatorScale = p;
}
v_multiply(fltbuf, cd.interpolator, wsz);
v_copy(tmp, cd.interpolator, wsz);
m_swindow->cut(tmp);
v_add(windowAccumulator, tmp, wsz);
} else {
m_swindow->add(windowAccumulator, m_awindow->getArea() * 1.5f);
}
m_swindow->cut(fltbuf);
v_add(accumulator, fltbuf, wsz);
cd.accumulatorFill = wsz;
if (wsz > fsz) {
// reuse fltbuf to calculate interpolating window shape for
// window accumulator
v_copy(fltbuf, cd.interpolator, wsz);
m_swindow->cut(fltbuf);
v_add(windowAccumulator, fltbuf, wsz);
} else {
m_swindow->add(windowAccumulator, m_awindow->getArea() * 1.5f);
}
}
void

View File

@@ -43,6 +43,9 @@ namespace RubberBand {
* -- it's just a quick hack for use with things like plugins.
*/
//!!! should review this, it's not really thread safe owing to lack of
//!!! atomic updates
template <typename T>
class Scavenger
{

View File

@@ -28,6 +28,7 @@ CompoundAudioCurve::CompoundAudioCurve(Parameters parameters) :
m_hf(parameters),
m_hfFilter(new MovingMedian<double>(19, 85)),
m_hfDerivFilter(new MovingMedian<double>(19, 90)),
m_type(CompoundDetector),
m_lastHf(0.0),
m_lastResult(0.0),
m_risingCount(0)

View File

@@ -35,7 +35,7 @@ public:
CompoundDetector,
SoftDetector
};
virtual void setType(Type);
virtual void setType(Type); // default is CompoundDetector
virtual void setFftSize(int newSize);

View File

@@ -17,8 +17,9 @@
#include "base/Profiler.h"
#include "system/Allocators.h"
#include "system/VectorOps.h"
#include "system/VectorOpsComplex.h"
//#define FFT_MEASUREMENT 1
#define FFT_MEASUREMENT 1
#ifdef HAVE_FFTW3
@@ -77,9 +78,6 @@ public:
virtual void inverseInterleaved(const float *R__ complexIn, float *R__ realOut) = 0;
virtual void inversePolar(const float *R__ magIn, const float *R__ phaseIn, float *R__ realOut) = 0;
virtual void inverseCepstral(const float *R__ magIn, float *R__ cepOut) = 0;
virtual float *getFloatTimeBuffer() = 0;
virtual double *getDoubleTimeBuffer() = 0;
};
namespace FFTs {
@@ -152,15 +150,8 @@ namespace FFTs {
class D_FFTW : public FFTImpl
{
public:
D_FFTW(int size) : m_fplanf(0)
#ifdef FFTW_DOUBLE_ONLY
, m_frb(0)
#endif
, m_dplanf(0)
#ifdef FFTW_FLOAT_ONLY
, m_drb(0)
#endif
, m_size(size)
D_FFTW(int size) :
m_fplanf(0), m_dplanf(0), m_size(size)
{
}
@@ -176,9 +167,6 @@ public:
fftwf_destroy_plan(m_fplani);
fftwf_free(m_fbuf);
fftwf_free(m_fpacked);
#ifdef FFTW_DOUBLE_ONLY
if (m_frb) fftw_free(m_frb);
#endif
m_commonMutex.unlock();
}
if (m_dplanf) {
@@ -192,9 +180,6 @@ public:
fftw_destroy_plan(m_dplani);
fftw_free(m_dbuf);
fftw_free(m_dpacked);
#ifdef FFTW_FLOAT_ONLY
if (m_drb) fftwf_free(m_drb);
#endif
m_commonMutex.unlock();
}
}
@@ -390,14 +375,8 @@ public:
dbuf[i] = realIn[i];
}
fftw_execute(m_dplanf);
const int hs = m_size/2;
for (int i = 0; i <= hs; ++i) {
magOut[i] = sqrt(m_dpacked[i][0] * m_dpacked[i][0] +
m_dpacked[i][1] * m_dpacked[i][1]);
}
for (int i = 0; i <= hs; ++i) {
phaseOut[i] = atan2(m_dpacked[i][1], m_dpacked[i][0]);
}
v_cartesian_interleaved_to_polar(magOut, phaseOut,
(double *)m_dpacked, m_size/2+1);
}
void forwardMagnitude(const double *R__ realIn, double *R__ magOut) {
@@ -457,14 +436,8 @@ public:
fbuf[i] = realIn[i];
}
fftwf_execute(m_fplanf);
const int hs = m_size/2;
for (int i = 0; i <= hs; ++i) {
magOut[i] = sqrtf(m_fpacked[i][0] * m_fpacked[i][0] +
m_fpacked[i][1] * m_fpacked[i][1]);
}
for (int i = 0; i <= hs; ++i) {
phaseOut[i] = atan2f(m_fpacked[i][1], m_fpacked[i][0]) ;
}
v_cartesian_interleaved_to_polar(magOut, phaseOut,
(float *)m_fpacked, m_size/2+1);
}
void forwardMagnitude(const float *R__ realIn, float *R__ magOut) {
@@ -625,31 +598,10 @@ public:
}
}
float *getFloatTimeBuffer() {
initFloat();
#ifdef FFTW_DOUBLE_ONLY
if (!m_frb) m_frb = (float *)fftw_malloc(m_size * sizeof(float));
return m_frb;
#else
return m_fbuf;
#endif
}
double *getDoubleTimeBuffer() {
initDouble();
#ifdef FFTW_FLOAT_ONLY
if (!m_drb) m_drb = (double *)fftwf_malloc(m_size * sizeof(double));
return m_drb;
#else
return m_dbuf;
#endif
}
private:
fftwf_plan m_fplanf;
fftwf_plan m_fplani;
#ifdef FFTW_DOUBLE_ONLY
float *m_frb;
double *m_fbuf;
#else
float *m_fbuf;
@@ -659,11 +611,10 @@ private:
fftw_plan m_dplani;
#ifdef FFTW_FLOAT_ONLY
float *m_dbuf;
double *m_drb;
#else
double *m_dbuf;
#endif
fftw_complex * m_dpacked;
fftw_complex *m_dpacked;
const int m_size;
static int m_extantf;
static int m_extantd;
@@ -688,8 +639,6 @@ class D_KISSFFT : public FFTImpl
public:
D_KISSFFT(int size) :
m_size(size),
m_frb(0),
m_drb(0),
m_fplanf(0),
m_fplani(0)
{
@@ -714,9 +663,6 @@ public:
delete[] m_fbuf;
delete[] m_fpacked;
if (m_frb) delete[] m_frb;
if (m_drb) delete[] m_drb;
}
void initFloat() { }
@@ -956,21 +902,9 @@ public:
kiss_fftri(m_fplani, m_fpacked, cepOut);
}
float *getFloatTimeBuffer() {
if (!m_frb) m_frb = new float[m_size];
return m_frb;
}
double *getDoubleTimeBuffer() {
if (!m_drb) m_drb = new double[m_size];
return m_drb;
}
private:
const int m_size;
float* m_frb;
double* m_drb;
kiss_fftr_cfg m_fplanf;
kiss_fftr_cfg m_fplani;
kiss_fft_scalar *m_fbuf;
@@ -984,7 +918,7 @@ private:
class D_Cross : public FFTImpl
{
public:
D_Cross(int size) : m_size(size), m_table(0), m_frb(0), m_drb(0) {
D_Cross(int size) : m_size(size), m_table(0) {
m_a = new double[size];
m_b = new double[size];
@@ -1022,8 +956,6 @@ public:
delete[] m_b;
delete[] m_c;
delete[] m_d;
delete[] m_frb;
delete[] m_drb;
}
void initFloat() { }
@@ -1221,21 +1153,9 @@ public:
for (int i = 0; i < m_size; ++i) cepOut[i] = m_c[i];
}
float *getFloatTimeBuffer() {
if (!m_frb) m_frb = new float[m_size];
return m_frb;
}
double *getDoubleTimeBuffer() {
if (!m_drb) m_drb = new double[m_size];
return m_drb;
}
private:
const int m_size;
int *m_table;
float *m_frb;
double *m_drb;
double *m_a;
double *m_b;
double *m_c;
@@ -1561,18 +1481,6 @@ FFT::initDouble()
d->initDouble();
}
float *
FFT::getFloatTimeBuffer()
{
return d->getFloatTimeBuffer();
}
double *
FFT::getDoubleTimeBuffer()
{
return d->getDoubleTimeBuffer();
}
void
FFT::tune()

View File

@@ -73,9 +73,6 @@ public:
void initFloat();
void initDouble();
float *getFloatTimeBuffer();
double *getDoubleTimeBuffer();
static void tune();
protected:

View File

@@ -43,7 +43,7 @@ PercussiveAudioCurve::reset()
void
PercussiveAudioCurve::setFftSize(int newSize)
{
m_prevMag = reallocate(m_prevMag, m_fftSize, newSize);
m_prevMag = reallocate(m_prevMag, m_fftSize/2 + 1, newSize/2 + 1);
AudioCurveCalculator::setFftSize(newSize);
reset();
}

View File

@@ -506,6 +506,14 @@ Resampler::Resampler(Resampler::Quality quality, int channels,
#endif
break;
}
if (!d) {
std::cerr << "Resampler::Resampler(" << quality << ", " << channels
<< ", " << maxBufferSize
<< "): Internal error: No implementation selected"
<< std::endl;
abort();
}
}
Resampler::~Resampler()

View File

@@ -69,7 +69,8 @@ void deallocate(T *ptr)
if (ptr) free((void *)ptr);
}
/// Reallocate preserving contents but leaving additional memory uninitialised
template <typename T>
T *reallocate(T *ptr, size_t oldcount, size_t count)
{
@@ -86,7 +87,8 @@ T *reallocate(T *ptr, size_t oldcount, size_t count)
if (ptr) deallocate<T>(ptr);
return newptr;
}
/// Reallocate, zeroing all contents
template <typename T>
T *reallocate_and_zero(T *ptr, size_t oldcount, size_t count)
{
@@ -94,6 +96,15 @@ T *reallocate_and_zero(T *ptr, size_t oldcount, size_t count)
v_zero(ptr, count);
return ptr;
}
/// Reallocate preserving contents and zeroing any additional memory
template <typename T>
T *reallocate_and_zero_extension(T *ptr, size_t oldcount, size_t count)
{
ptr = reallocate(ptr, oldcount, count);
if (count > oldcount) v_zero(ptr + oldcount, count - oldcount);
return ptr;
}
template <typename T>
T **allocate_channels(size_t channels, size_t count)

View File

@@ -99,26 +99,26 @@ private:
Mutex *m_mutex;
};
/**
The Condition class bundles a condition variable and mutex.
To wait on a condition, call lock(), test the termination condition
if desired, then wait(). The condition will be unlocked during the
wait and re-locked when wait() returns (which will happen when the
condition is signalled or the timer times out).
To signal a condition, call signal(). If the condition is signalled
between lock() and wait(), the signal may be missed by the waiting
thread. To avoid this, the signalling thread should also lock the
condition before calling signal() and unlock it afterwards.
*/
class Condition
{
public:
Condition(std::string name);
~Condition();
// The Condition class bundles a condition variable and mutex.
// To wait on a condition, call lock(), test the termination
// condition if desired, then wait(). The condition will be
// unlocked during the wait and re-locked when wait() returns
// (which will happen when the condition is signalled or the timer
// times out).
// To signal a condition, call signal(). If the condition is
// signalled between lock() and wait(), the signal may be missed
// by the waiting thread. To avoid this, the signalling thread
// should also lock the condition before calling signal() and
// unlock it afterwards.
void lock();
void unlock();
void wait(int us = 0);