* Share dblbuf with FFT object to avoid a copy; fix reset(); add spectral
difference audio curve; some tidying; add FLOAT_ONLY FFT option
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
|
||||
CXX := @CXX@
|
||||
CXXFLAGS := @CXXFLAGS@ @SRC_CFLAGS@ @SNDFILE_CFLAGS@ @FFTW_CFLAGS@ @Vamp_CFLAGS@ -Irubberband -Isrc $(OPTFLAGS)
|
||||
CXXFLAGS := -DFFTW_DOUBLE_ONLY @CXXFLAGS@ @SRC_CFLAGS@ @SNDFILE_CFLAGS@ @FFTW_CFLAGS@ @Vamp_CFLAGS@ -Irubberband -Isrc $(OPTFLAGS)
|
||||
LDFLAGS := @LDFLAGS@ -lpthread $(LDFLAGS)
|
||||
|
||||
LIBRARY_LIBS := @SRC_LIBS@ @FFTW_LIBS@
|
||||
@@ -42,6 +42,7 @@ LIBRARY_INCLUDES := \
|
||||
src/Resampler.h \
|
||||
src/RingBuffer.h \
|
||||
src/Scavenger.h \
|
||||
src/SpectralDifferenceAudioCurve.h \
|
||||
src/StretchCalculator.h \
|
||||
src/StretcherImpl.h \
|
||||
src/StretcherChannelData.h \
|
||||
@@ -56,6 +57,7 @@ LIBRARY_SOURCES := \
|
||||
src/PercussiveAudioCurve.cpp \
|
||||
src/AudioCurve.cpp \
|
||||
src/Resampler.cpp \
|
||||
src/SpectralDifferenceAudioCurve.cpp \
|
||||
src/StretchCalculator.cpp \
|
||||
src/StretcherImpl.cpp \
|
||||
src/StretcherProcess.cpp \
|
||||
|
||||
2
TODO
2
TODO
@@ -3,10 +3,10 @@
|
||||
* LADSPA plugin has too much "artificial latency"
|
||||
* LADSPA plugin probably doesn't want to go any higher than about +2 octaves
|
||||
* Return value check in FFT and resampler!
|
||||
* implement+test, or remove, reset()
|
||||
* sweeps & tones
|
||||
* ensure default options don't produce garbage at any extreme
|
||||
|
||||
DONE * implement+test, or remove, reset()
|
||||
DONE * Add and test Win32 threading primitives in Thread.cpp
|
||||
DONE * Threading lock structure is very slow if it becomes starved of CPUs
|
||||
DONE * Rationalise naming further (e.g. use of "lock" for both peak phases
|
||||
|
||||
232
src/FFT.cpp
232
src/FFT.cpp
@@ -47,33 +47,79 @@ public:
|
||||
|
||||
virtual void inverse(float *realIn, float *imagIn, float *realOut) = 0;
|
||||
virtual void inversePolar(float *magIn, float *phaseIn, float *realOut) = 0;
|
||||
|
||||
virtual float *getFloatTimeBuffer() = 0;
|
||||
virtual double *getDoubleTimeBuffer() = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Remove this define to make float FFTs be carried out using fftwf_*
|
||||
// functions instead of converting to doubles and using fftw_*.
|
||||
#define FFTW_DOUBLE_ONLY 1
|
||||
// Define FFTW_DOUBLE_ONLY to make all uses of FFTW functions be
|
||||
// double-precision (so "float" FFTs are calculated by casting to
|
||||
// doubles and using the double-precision FFTW function).
|
||||
//
|
||||
// Define FFTW_FLOAT_ONLY to make all uses of FFTW functions be
|
||||
// single-precision (so "double" FFTs are calculated by casting to
|
||||
// floats and using the single-precision FFTW function).
|
||||
//
|
||||
// Neither of these flags is terribly desirable -- FFTW_FLOAT_ONLY
|
||||
// obviously loses you precision, and neither is handled in the most
|
||||
// efficient way so any performance improvement will be small at best.
|
||||
// The only real reason to define either flag would be to avoid
|
||||
// linking against both fftw3 and fftw3f libraries.
|
||||
|
||||
//#define FFTW_DOUBLE_ONLY 1
|
||||
//#define FFTW_FLOAT_ONLY 1
|
||||
|
||||
#ifdef FFTW_DOUBLE_ONLY
|
||||
#ifdef FFTW_FLOAT_ONLY
|
||||
// Can't meaningfully define both
|
||||
#undef FFTW_DOUBLE_ONLY
|
||||
#undef FFTW_FLOAT_ONLY
|
||||
#else /* !FFTW_FLOAT_ONLY */
|
||||
#define fftwf_complex fftw_complex
|
||||
#define fftwf_plan fftw_plan
|
||||
#define fftwf_plan_dft_r2c_1d fftw_plan_dft_r2c_1d
|
||||
#define fftwf_plan_dft_c2r_1d fftw_plan_dft_c2r_1d
|
||||
#define fftwf_destroy_plan fftw_destroy_plan
|
||||
#define fftwf_malloc fftw_malloc
|
||||
#define fftwf_free fftw_free
|
||||
#define fftwf_execute fftw_execute
|
||||
#define atan2f atan2
|
||||
#define sqrtf sqrt
|
||||
#define cosf cos
|
||||
#define sinf sin
|
||||
#endif
|
||||
#endif /* !FFTW_FLOAT_ONLY */
|
||||
|
||||
#ifdef FFTW_FLOAT_ONLY
|
||||
#define fftw_complex fftwf_complex
|
||||
#define fftw_plan fftwf_plan
|
||||
#define fftw_plan_dft_r2c_1d fftwf_plan_dft_r2c_1d
|
||||
#define fftw_plan_dft_c2r_1d fftwf_plan_dft_c2r_1d
|
||||
#define fftw_destroy_plan fftwf_destroy_plan
|
||||
#define fftw_malloc fftwf_malloc
|
||||
#define fftw_free fftwf_free
|
||||
#define fftw_execute fftwf_execute
|
||||
#define atan2 atan2f
|
||||
#define sqrt sqrtf
|
||||
#define cos cosf
|
||||
#define sif sinf
|
||||
#endif /* FFTW_FLOAT_ONLY */
|
||||
|
||||
class D_FFTW : public FFTImpl
|
||||
{
|
||||
public:
|
||||
D_FFTW(unsigned int size) : m_size(size), m_fplanf(0), m_dplanf(0) {
|
||||
D_FFTW(unsigned 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() {
|
||||
@@ -87,6 +133,9 @@ 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
|
||||
}
|
||||
if (m_dplanf) {
|
||||
bool save = false;
|
||||
@@ -98,6 +147,9 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,11 +159,12 @@ public:
|
||||
m_extantMutex.lock();
|
||||
if (m_extantf++ == 0) load = true;
|
||||
m_extantMutex.unlock();
|
||||
if (load) loadWisdom('f');
|
||||
#ifdef FFTW_DOUBLE_ONLY
|
||||
if (load) loadWisdom('d');
|
||||
m_fbuf = (double *)fftw_malloc(m_size * sizeof(double));
|
||||
#else
|
||||
m_fbuf = (float *)fftw_malloc(m_size * sizeof(float));
|
||||
if (load) loadWisdom('f');
|
||||
m_fbuf = (float *)fftwf_malloc(m_size * sizeof(float));
|
||||
#endif
|
||||
m_fpacked = (fftwf_complex *)fftw_malloc
|
||||
((m_size/2 + 1) * sizeof(fftwf_complex));
|
||||
@@ -127,8 +180,13 @@ public:
|
||||
m_extantMutex.lock();
|
||||
if (m_extantd++ == 0) load = true;
|
||||
m_extantMutex.unlock();
|
||||
#ifdef FFTW_FLOAT_ONLY
|
||||
if (load) loadWisdom('f');
|
||||
m_dbuf = (float *)fftwf_malloc(m_size * sizeof(float));
|
||||
#else
|
||||
if (load) loadWisdom('d');
|
||||
m_dbuf = (double *)fftw_malloc(m_size * sizeof(double));
|
||||
#endif
|
||||
m_dpacked = (fftw_complex *)fftw_malloc
|
||||
((m_size/2 + 1) * sizeof(fftw_complex));
|
||||
m_dplanf = fftw_plan_dft_r2c_1d
|
||||
@@ -145,6 +203,9 @@ public:
|
||||
#ifdef FFTW_DOUBLE_ONLY
|
||||
if (type == 'f') return;
|
||||
#endif
|
||||
#ifdef FFTW_FLOAT_ONLY
|
||||
if (type == 'd') return;
|
||||
#endif
|
||||
|
||||
const char *home = getenv("HOME");
|
||||
if (!home) return;
|
||||
@@ -162,7 +223,11 @@ public:
|
||||
#else
|
||||
case 'f': fftwf_export_wisdom_to_file(f); break;
|
||||
#endif
|
||||
#ifdef FFTW_FLOAT_ONLY
|
||||
case 'd': break;
|
||||
#else
|
||||
case 'd': fftw_export_wisdom_to_file(f); break;
|
||||
#endif
|
||||
default: break;
|
||||
}
|
||||
} else {
|
||||
@@ -172,7 +237,11 @@ public:
|
||||
#else
|
||||
case 'f': fftwf_import_wisdom_from_file(f); break;
|
||||
#endif
|
||||
#ifdef FFTW_FLOAT_ONLY
|
||||
case 'd': break;
|
||||
#else
|
||||
case 'd': fftw_import_wisdom_from_file(f); break;
|
||||
#endif
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@@ -210,31 +279,42 @@ public:
|
||||
|
||||
void forward(double *realIn, double *realOut, double *imagOut) {
|
||||
if (!m_dplanf) initDouble();
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
m_dbuf[i] = realIn[i];
|
||||
}
|
||||
#ifndef FFTW_FLOAT_ONLY
|
||||
if (realIn != m_dbuf)
|
||||
#endif
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
m_dbuf[i] = realIn[i];
|
||||
}
|
||||
fftw_execute(m_dplanf);
|
||||
unpackDouble(realOut, imagOut);
|
||||
}
|
||||
|
||||
void forwardPolar(double *realIn, double *magOut, double *phaseOut) {
|
||||
if (!m_dplanf) initDouble();
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
m_dbuf[i] = realIn[i];
|
||||
}
|
||||
#ifndef FFTW_FLOAT_ONLY
|
||||
if (realIn != m_dbuf)
|
||||
#endif
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
m_dbuf[i] = realIn[i];
|
||||
}
|
||||
fftw_execute(m_dplanf);
|
||||
for (unsigned int i = 0; i <= m_size/2; ++i) {
|
||||
magOut[i] = sqrt(m_dpacked[i][0] * m_dpacked[i][0] +
|
||||
m_dpacked[i][1] * m_dpacked[i][1]);
|
||||
}
|
||||
for (unsigned int i = 0; i <= m_size/2; ++i) {
|
||||
phaseOut[i] = atan2(m_dpacked[i][1], m_dpacked[i][0]);
|
||||
}
|
||||
}
|
||||
|
||||
void forwardMagnitude(double *realIn, double *magOut) {
|
||||
if (!m_dplanf) initDouble();
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
m_dbuf[i] = realIn[i];
|
||||
}
|
||||
#ifndef FFTW_FLOAT_ONLY
|
||||
if (realIn != m_dbuf)
|
||||
#endif
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
m_dbuf[i] = realIn[i];
|
||||
}
|
||||
fftw_execute(m_dplanf);
|
||||
for (unsigned int i = 0; i <= m_size/2; ++i) {
|
||||
magOut[i] = sqrt(m_dpacked[i][0] * m_dpacked[i][0] +
|
||||
@@ -244,31 +324,42 @@ public:
|
||||
|
||||
void forward(float *realIn, float *realOut, float *imagOut) {
|
||||
if (!m_fplanf) initFloat();
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
m_fbuf[i] = realIn[i];
|
||||
}
|
||||
#ifndef FFTW_DOUBLE_ONLY
|
||||
if (realIn != m_fbuf)
|
||||
#endif
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
m_fbuf[i] = realIn[i];
|
||||
}
|
||||
fftwf_execute(m_fplanf);
|
||||
unpackFloat(realOut, imagOut);
|
||||
}
|
||||
|
||||
void forwardPolar(float *realIn, float *magOut, float *phaseOut) {
|
||||
if (!m_fplanf) initFloat();
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
m_fbuf[i] = realIn[i];
|
||||
}
|
||||
#ifndef FFTW_DOUBLE_ONLY
|
||||
if (realIn != m_fbuf)
|
||||
#endif
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
m_fbuf[i] = realIn[i];
|
||||
}
|
||||
fftwf_execute(m_fplanf);
|
||||
for (unsigned int i = 0; i <= m_size/2; ++i) {
|
||||
magOut[i] = sqrtf(m_fpacked[i][0] * m_fpacked[i][0] +
|
||||
m_fpacked[i][1] * m_fpacked[i][1]);
|
||||
}
|
||||
for (unsigned int i = 0; i <= m_size/2; ++i) {
|
||||
phaseOut[i] = atan2f(m_fpacked[i][1], m_fpacked[i][0]) ;
|
||||
}
|
||||
}
|
||||
|
||||
void forwardMagnitude(float *realIn, float *magOut) {
|
||||
if (!m_fplanf) initFloat();
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
m_fbuf[i] = realIn[i];
|
||||
}
|
||||
#ifndef FFTW_DOUBLE_ONLY
|
||||
if (realIn != m_fbuf)
|
||||
#endif
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
m_fbuf[i] = realIn[i];
|
||||
}
|
||||
fftwf_execute(m_fplanf);
|
||||
for (unsigned int i = 0; i <= m_size/2; ++i) {
|
||||
magOut[i] = sqrtf(m_fpacked[i][0] * m_fpacked[i][0] +
|
||||
@@ -280,9 +371,12 @@ public:
|
||||
if (!m_dplanf) initDouble();
|
||||
packDouble(realIn, imagIn);
|
||||
fftw_execute(m_dplani);
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
realOut[i] = m_dbuf[i];
|
||||
}
|
||||
#ifndef FFTW_FLOAT_ONLY
|
||||
if (realOut != m_dbuf)
|
||||
#endif
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
realOut[i] = m_dbuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
void inversePolar(double *magIn, double *phaseIn, double *realOut) {
|
||||
@@ -292,18 +386,24 @@ public:
|
||||
m_dpacked[i][1] = magIn[i] * sin(phaseIn[i]);
|
||||
}
|
||||
fftw_execute(m_dplani);
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
realOut[i] = m_dbuf[i];
|
||||
}
|
||||
#ifndef FFTW_FLOAT_ONLY
|
||||
if (realOut != m_dbuf)
|
||||
#endif
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
realOut[i] = m_dbuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
void inverse(float *realIn, float *imagIn, float *realOut) {
|
||||
if (!m_fplanf) initFloat();
|
||||
packFloat(realIn, imagIn);
|
||||
fftwf_execute(m_fplani);
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
realOut[i] = m_fbuf[i];
|
||||
}
|
||||
#ifndef FFTW_DOUBLE_ONLY
|
||||
if (realOut != m_fbuf)
|
||||
#endif
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
realOut[i] = m_fbuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
void inversePolar(float *magIn, float *phaseIn, float *realOut) {
|
||||
@@ -313,15 +413,39 @@ public:
|
||||
m_fpacked[i][1] = magIn[i] * sinf(phaseIn[i]);
|
||||
}
|
||||
fftwf_execute(m_fplani);
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
realOut[i] = m_fbuf[i];
|
||||
}
|
||||
#ifndef FFTW_DOUBLE_ONLY
|
||||
if (realOut != m_fbuf)
|
||||
#endif
|
||||
for (unsigned int i = 0; i < m_size; ++i) {
|
||||
realOut[i] = m_fbuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -329,7 +453,12 @@ private:
|
||||
fftwf_complex *m_fpacked;
|
||||
fftw_plan m_dplanf;
|
||||
fftw_plan m_dplani;
|
||||
#ifdef FFTW_FLOAT_ONLY
|
||||
float *m_dbuf;
|
||||
double *m_drb;
|
||||
#else
|
||||
double *m_dbuf;
|
||||
#endif
|
||||
fftw_complex *m_dpacked;
|
||||
unsigned int m_size;
|
||||
static unsigned int m_extantf;
|
||||
@@ -346,11 +475,12 @@ D_FFTW::m_extantd = 0;
|
||||
Mutex
|
||||
D_FFTW::m_extantMutex;
|
||||
|
||||
#endif
|
||||
|
||||
class D_Cross : public FFTImpl
|
||||
{
|
||||
public:
|
||||
D_Cross(unsigned int size) : m_size(size), m_table(0) {
|
||||
D_Cross(unsigned int size) : m_size(size), m_table(0), m_frb(0), m_drb(0) {
|
||||
|
||||
m_a = new double[size];
|
||||
m_b = new double[size];
|
||||
@@ -388,6 +518,8 @@ public:
|
||||
delete[] m_b;
|
||||
delete[] m_c;
|
||||
delete[] m_d;
|
||||
delete[] m_frb;
|
||||
delete[] m_drb;
|
||||
}
|
||||
|
||||
void initFloat() { }
|
||||
@@ -496,9 +628,21 @@ public:
|
||||
for (unsigned int i = 0; i < m_size; ++i) realOut[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:
|
||||
unsigned int m_size;
|
||||
int *m_table;
|
||||
float *m_frb;
|
||||
double *m_drb;
|
||||
double *m_a;
|
||||
double *m_b;
|
||||
double *m_c;
|
||||
@@ -701,6 +845,18 @@ FFT::initDouble()
|
||||
d->initDouble();
|
||||
}
|
||||
|
||||
float *
|
||||
FFT::getFloatTimeBuffer()
|
||||
{
|
||||
return d->getFloatTimeBuffer();
|
||||
}
|
||||
|
||||
double *
|
||||
FFT::getDoubleTimeBuffer()
|
||||
{
|
||||
return d->getDoubleTimeBuffer();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FFT::tune()
|
||||
|
||||
@@ -60,6 +60,9 @@ public:
|
||||
void initFloat();
|
||||
void initDouble();
|
||||
|
||||
float *getFloatTimeBuffer();
|
||||
double *getDoubleTimeBuffer();
|
||||
|
||||
static void tune();
|
||||
|
||||
protected:
|
||||
|
||||
@@ -20,24 +20,15 @@ namespace RubberBand
|
||||
HighFrequencyAudioCurve::HighFrequencyAudioCurve(size_t sampleRate, size_t windowSize) :
|
||||
AudioCurve(sampleRate, windowSize)
|
||||
{
|
||||
m_prevMag = new double[m_windowSize/2 + 1];
|
||||
|
||||
for (size_t i = 0; i <= m_windowSize/2; ++i) {
|
||||
m_prevMag[i] = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
HighFrequencyAudioCurve::~HighFrequencyAudioCurve()
|
||||
{
|
||||
delete[] m_prevMag;
|
||||
}
|
||||
|
||||
void
|
||||
HighFrequencyAudioCurve::reset()
|
||||
{
|
||||
for (size_t i = 0; i <= m_windowSize/2; ++i) {
|
||||
m_prevMag[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -52,7 +43,7 @@ HighFrequencyAudioCurve::process(float *mag, size_t increment)
|
||||
float result = 0.0;
|
||||
|
||||
for (size_t n = 0; n <= m_windowSize / 2; ++n) {
|
||||
result += mag[n];
|
||||
result += mag[n] * n;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -32,9 +32,6 @@ public:
|
||||
|
||||
virtual float process(float *mag, size_t increment);
|
||||
virtual void reset();
|
||||
|
||||
protected:
|
||||
double *m_prevMag;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -63,7 +63,6 @@ PercussiveAudioCurve::process(float *mag, size_t increment)
|
||||
size_t nonZeroCount = 0;
|
||||
|
||||
for (size_t n = 1; n <= m_windowSize / 2; ++n) {
|
||||
//!!! adjust threshold so that this multiplication is unnecessary
|
||||
float sqrmag = mag[n] * mag[n];
|
||||
bool above = ((sqrmag / m_prevMag[n]) >= threshold);
|
||||
if (above) ++count;
|
||||
@@ -71,7 +70,6 @@ PercussiveAudioCurve::process(float *mag, size_t increment)
|
||||
m_prevMag[n] = sqrmag;
|
||||
}
|
||||
|
||||
//!!! return float(count) / float(m_windowSize);
|
||||
if (nonZeroCount == 0) return 0;
|
||||
else return float(count) / float(nonZeroCount);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,6 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
|
||||
windowAccumulator = new float[maxSize];
|
||||
|
||||
fltbuf = new float[maxSize];
|
||||
dblbuf = new double[maxSize];
|
||||
|
||||
for (std::set<size_t>::const_iterator i = windowSizes.begin();
|
||||
i != windowSizes.end(); ++i) {
|
||||
@@ -69,6 +68,8 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
|
||||
}
|
||||
fft = ffts[initialWindowSize];
|
||||
|
||||
dblbuf = fft->getDoubleTimeBuffer();
|
||||
|
||||
resampler = 0;
|
||||
resamplebuf = 0;
|
||||
resamplebufSize = 0;
|
||||
@@ -83,10 +84,13 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
|
||||
freqPeak[i] = 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < initialWindowSize; ++i) {
|
||||
dblbuf[i] = 0.0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < maxSize; ++i) {
|
||||
accumulator[i] = 0.f;
|
||||
windowAccumulator[i] = 0.f;
|
||||
dblbuf[i] = 0.0;
|
||||
fltbuf[i] = 0.0;
|
||||
}
|
||||
}
|
||||
@@ -116,6 +120,12 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
|
||||
|
||||
fft = ffts[windowSize];
|
||||
|
||||
dblbuf = fft->getDoubleTimeBuffer();
|
||||
|
||||
for (size_t i = 0; i < windowSize; ++i) {
|
||||
dblbuf[i] = 0.0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < realSize; ++i) {
|
||||
mag[i] = 0.0;
|
||||
phase[i] = 0.0;
|
||||
@@ -153,10 +163,7 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
|
||||
freqPeak = new size_t[realSize];
|
||||
|
||||
delete[] fltbuf;
|
||||
delete[] dblbuf;
|
||||
|
||||
fltbuf = new float[windowSize];
|
||||
dblbuf = new double[windowSize];
|
||||
|
||||
// But we do want to preserve data in these
|
||||
|
||||
@@ -181,7 +188,6 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < windowSize; ++i) {
|
||||
dblbuf[i] = 0.0;
|
||||
fltbuf[i] = 0.0;
|
||||
}
|
||||
|
||||
@@ -196,6 +202,12 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
|
||||
}
|
||||
|
||||
fft = ffts[windowSize];
|
||||
|
||||
dblbuf = fft->getDoubleTimeBuffer();
|
||||
|
||||
for (size_t i = 0; i < windowSize; ++i) {
|
||||
dblbuf[i] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -231,7 +243,6 @@ RubberBandStretcher::Impl::ChannelData::~ChannelData()
|
||||
delete[] accumulator;
|
||||
delete[] windowAccumulator;
|
||||
delete[] fltbuf;
|
||||
delete[] dblbuf;
|
||||
|
||||
for (std::map<size_t, FFT *>::iterator i = ffts.begin();
|
||||
i != ffts.end(); ++i) {
|
||||
|
||||
@@ -92,7 +92,7 @@ public:
|
||||
float *windowAccumulator;
|
||||
|
||||
float *fltbuf;
|
||||
double *dblbuf;
|
||||
double *dblbuf; // owned by FFT object, only used for time domain FFT i/o
|
||||
|
||||
size_t prevIncrement; // only used in RT mode
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "StretcherImpl.h"
|
||||
#include "PercussiveAudioCurve.h"
|
||||
#include "HighFrequencyAudioCurve.h"
|
||||
#include "SpectralDifferenceAudioCurve.h"
|
||||
#include "ConstantAudioCurve.h"
|
||||
#include "StretchCalculator.h"
|
||||
#include "StretcherChannelData.h"
|
||||
@@ -113,7 +114,6 @@ RubberBandStretcher::Impl::Impl(RubberBandStretcher *stretcher,
|
||||
m_realtime = true;
|
||||
|
||||
if (!(m_options & OptionStretchPrecise)) {
|
||||
cerr << "RubberBandStretcher::Impl::Impl: Real-time mode: enabling OptionStretchPrecise" << endl;
|
||||
m_options |= OptionStretchPrecise;
|
||||
}
|
||||
}
|
||||
@@ -148,6 +148,7 @@ RubberBandStretcher::Impl::~Impl()
|
||||
if (m_debugLevel > 0) {
|
||||
cerr << "RubberBandStretcher::~RubberBandStretcher: joining (channel " << *i << ")" << endl;
|
||||
}
|
||||
(*i)->abandon();
|
||||
(*i)->wait();
|
||||
delete *i;
|
||||
}
|
||||
@@ -171,21 +172,32 @@ RubberBandStretcher::Impl::~Impl()
|
||||
void
|
||||
RubberBandStretcher::Impl::reset()
|
||||
{
|
||||
//!!! does not do the right thing in threaded mode
|
||||
|
||||
if (m_threaded) m_threadSetMutex.lock();
|
||||
if (m_threaded) {
|
||||
m_threadSetMutex.lock();
|
||||
for (set<ProcessThread *>::iterator i = m_threadSet.begin();
|
||||
i != m_threadSet.end(); ++i) {
|
||||
if (m_debugLevel > 0) {
|
||||
cerr << "RubberBandStretcher::~RubberBandStretcher: joining (channel " << *i << ")" << endl;
|
||||
}
|
||||
(*i)->abandon();
|
||||
(*i)->wait();
|
||||
delete *i;
|
||||
}
|
||||
m_threadSet.clear();
|
||||
}
|
||||
|
||||
for (size_t c = 0; c < m_channels; ++c) {
|
||||
delete m_channelData[c];
|
||||
m_channelData[c] = new ChannelData(m_windowSize, m_outbufSize);
|
||||
m_channelData[c]->reset();
|
||||
}
|
||||
|
||||
m_mode = JustCreated;
|
||||
if (m_phaseResetAudioCurve) m_phaseResetAudioCurve->reset();
|
||||
if (m_stretchAudioCurve) m_stretchAudioCurve->reset();
|
||||
m_inputDuration = 0;
|
||||
|
||||
if (m_threaded) m_threadSetMutex.unlock();
|
||||
// m_done = false;
|
||||
|
||||
reconfigure();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -407,19 +419,14 @@ RubberBandStretcher::Impl::calculateSizes()
|
||||
if (m_debugLevel > 0) {
|
||||
cerr << "configure: outbuf size = " << m_outbufSize << endl;
|
||||
}
|
||||
|
||||
//!!! for very long stretches (e.g. x5), this is necessary; for
|
||||
//even longer ones (e.g. x10), even more of an outbuf is
|
||||
//necessary. clearly something wrong in our calculations... or do
|
||||
//we just need to ensure client calls setMaxProcessSize?
|
||||
// if (!m_realtime && !m_threaded) {
|
||||
// m_outbufSize = m_outbufSize * 10;
|
||||
// }
|
||||
}
|
||||
|
||||
void
|
||||
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 prevOutbufSize = m_outbufSize;
|
||||
if (m_windows.empty()) {
|
||||
@@ -512,9 +519,7 @@ RubberBandStretcher::Impl::configure()
|
||||
if (!m_realtime) {
|
||||
delete m_stretchAudioCurve;
|
||||
if (!(m_options & OptionStretchPrecise)) {
|
||||
//!!! probably adaptively-whitened spectral difference curve
|
||||
//would be better
|
||||
m_stretchAudioCurve = new HighFrequencyAudioCurve
|
||||
m_stretchAudioCurve = new SpectralDifferenceAudioCurve
|
||||
(m_stretcher->m_sampleRate, m_windowSize);
|
||||
} else {
|
||||
m_stretchAudioCurve = new ConstantAudioCurve
|
||||
@@ -550,8 +555,6 @@ RubberBandStretcher::Impl::configure()
|
||||
}
|
||||
|
||||
|
||||
//!!! separated out from configure() for the moment so we can look at
|
||||
// the logic of it
|
||||
void
|
||||
RubberBandStretcher::Impl::reconfigure()
|
||||
{
|
||||
@@ -882,9 +885,6 @@ RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bo
|
||||
|
||||
if (m_mode == JustCreated || m_mode == Studying) {
|
||||
|
||||
//!!! m_studying isn't the right test for "is this the first
|
||||
//time we've processed?"
|
||||
|
||||
if (m_mode == Studying) {
|
||||
calculateStretch();
|
||||
}
|
||||
|
||||
@@ -145,10 +145,12 @@ protected:
|
||||
ProcessThread(Impl *s, size_t c);
|
||||
void run();
|
||||
void signalDataAvailable();
|
||||
void abandon();
|
||||
private:
|
||||
Impl *m_s;
|
||||
size_t m_channel;
|
||||
Condition m_dataAvailable;
|
||||
bool m_abandoning;
|
||||
};
|
||||
|
||||
mutable Mutex m_threadSetMutex;
|
||||
|
||||
@@ -33,7 +33,8 @@ namespace RubberBand {
|
||||
RubberBandStretcher::Impl::ProcessThread::ProcessThread(Impl *s, size_t c) :
|
||||
m_s(s),
|
||||
m_channel(c),
|
||||
m_dataAvailable(std::string("data ") + char('A' + c))
|
||||
m_dataAvailable(std::string("data ") + char('A' + c)),
|
||||
m_abandoning(false)
|
||||
{ }
|
||||
|
||||
void
|
||||
@@ -61,11 +62,18 @@ RubberBandStretcher::Impl::ProcessThread::run()
|
||||
if (any) m_s->m_spaceAvailable.signal();
|
||||
|
||||
m_dataAvailable.lock();
|
||||
if (!m_s->testInbufReadSpace(m_channel)) {
|
||||
if (!m_s->testInbufReadSpace(m_channel) && !m_abandoning) {
|
||||
m_dataAvailable.wait();
|
||||
} else {
|
||||
m_dataAvailable.unlock();
|
||||
}
|
||||
|
||||
if (m_abandoning) {
|
||||
if (m_s->m_debugLevel > 1) {
|
||||
cerr << "thread " << m_channel << " abandoning" << endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool any = false, last = false;
|
||||
@@ -83,6 +91,12 @@ RubberBandStretcher::Impl::ProcessThread::signalDataAvailable()
|
||||
m_dataAvailable.signal();
|
||||
}
|
||||
|
||||
void
|
||||
RubberBandStretcher::Impl::ProcessThread::abandon()
|
||||
{
|
||||
m_abandoning = true;
|
||||
}
|
||||
|
||||
void
|
||||
RubberBandStretcher::Impl::processChunks(size_t c, bool &any, bool &last)
|
||||
{
|
||||
|
||||
@@ -59,7 +59,6 @@ Thread::start()
|
||||
{
|
||||
m_id = CreateThread(NULL, 0, staticRun, this, 0, 0);
|
||||
if (!m_id) {
|
||||
//!!!
|
||||
cerr << "ERROR: thread creation failed" << endl;
|
||||
exit(1);
|
||||
} else {
|
||||
@@ -296,7 +295,6 @@ void
|
||||
Thread::start()
|
||||
{
|
||||
if (pthread_create(&m_id, 0, staticRun, this)) {
|
||||
//!!!
|
||||
cerr << "ERROR: thread creation failed" << endl;
|
||||
exit(1);
|
||||
} else {
|
||||
|
||||
@@ -139,8 +139,8 @@ RubberBandPitchShifter::ladspaDescriptorMono =
|
||||
"rubberband-pitchshifter-mono", // Label
|
||||
properties,
|
||||
"Rubber Band Mono Pitch Shifter", // Name
|
||||
"Chris Cannam", //!!! Maker
|
||||
"GPL", //!!! Copyright
|
||||
"Chris Cannam",
|
||||
"GPL",
|
||||
PortCountMono,
|
||||
portsMono,
|
||||
portNamesMono,
|
||||
@@ -163,8 +163,8 @@ RubberBandPitchShifter::ladspaDescriptorStereo =
|
||||
"rubberband-pitchshifter-stereo", // Label
|
||||
properties,
|
||||
"Rubber Band Stereo Pitch Shifter", // Name
|
||||
"Chris Cannam", //!!! Maker
|
||||
"GPL", //!!! Copyright
|
||||
"Chris Cannam",
|
||||
"GPL",
|
||||
PortCountStereo,
|
||||
portsStereo,
|
||||
portNamesStereo,
|
||||
|
||||
Reference in New Issue
Block a user