diff --git a/Makefile.in b/Makefile.in index 9eed588..0c7cbec 100644 --- a/Makefile.in +++ b/Makefile.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 \ diff --git a/TODO b/TODO index 95ee58f..bb88259 100644 --- a/TODO +++ b/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 diff --git a/src/FFT.cpp b/src/FFT.cpp index 86037f7..8347e09 100644 --- a/src/FFT.cpp +++ b/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() diff --git a/src/FFT.h b/src/FFT.h index e459d45..65c185d 100644 --- a/src/FFT.h +++ b/src/FFT.h @@ -60,6 +60,9 @@ public: void initFloat(); void initDouble(); + float *getFloatTimeBuffer(); + double *getDoubleTimeBuffer(); + static void tune(); protected: diff --git a/src/HighFrequencyAudioCurve.cpp b/src/HighFrequencyAudioCurve.cpp index 720cad9..1bc4399 100644 --- a/src/HighFrequencyAudioCurve.cpp +++ b/src/HighFrequencyAudioCurve.cpp @@ -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; diff --git a/src/HighFrequencyAudioCurve.h b/src/HighFrequencyAudioCurve.h index b12c6f9..e891afa 100644 --- a/src/HighFrequencyAudioCurve.h +++ b/src/HighFrequencyAudioCurve.h @@ -32,9 +32,6 @@ public: virtual float process(float *mag, size_t increment); virtual void reset(); - -protected: - double *m_prevMag; }; } diff --git a/src/PercussiveAudioCurve.cpp b/src/PercussiveAudioCurve.cpp index e127d53..98c6508 100644 --- a/src/PercussiveAudioCurve.cpp +++ b/src/PercussiveAudioCurve.cpp @@ -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); } diff --git a/src/StretcherChannelData.cpp b/src/StretcherChannelData.cpp index e431a80..ecbb9a6 100644 --- a/src/StretcherChannelData.cpp +++ b/src/StretcherChannelData.cpp @@ -56,7 +56,6 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set &window windowAccumulator = new float[maxSize]; fltbuf = new float[maxSize]; - dblbuf = new double[maxSize]; for (std::set::const_iterator i = windowSizes.begin(); i != windowSizes.end(); ++i) { @@ -69,6 +68,8 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set &window } fft = ffts[initialWindowSize]; + dblbuf = fft->getDoubleTimeBuffer(); + resampler = 0; resamplebuf = 0; resamplebufSize = 0; @@ -83,10 +84,13 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set &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::iterator i = ffts.begin(); i != ffts.end(); ++i) { diff --git a/src/StretcherChannelData.h b/src/StretcherChannelData.h index e9c4796..ff110d1 100644 --- a/src/StretcherChannelData.h +++ b/src/StretcherChannelData.h @@ -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 diff --git a/src/StretcherImpl.cpp b/src/StretcherImpl.cpp index c021194..7a9fb2e 100644 --- a/src/StretcherImpl.cpp +++ b/src/StretcherImpl.cpp @@ -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::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(); } diff --git a/src/StretcherImpl.h b/src/StretcherImpl.h index e53cb9c..0dec4aa 100644 --- a/src/StretcherImpl.h +++ b/src/StretcherImpl.h @@ -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; diff --git a/src/StretcherProcess.cpp b/src/StretcherProcess.cpp index e0ead05..f181714 100644 --- a/src/StretcherProcess.cpp +++ b/src/StretcherProcess.cpp @@ -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) { diff --git a/src/Thread.cpp b/src/Thread.cpp index 642287b..2b37875 100644 --- a/src/Thread.cpp +++ b/src/Thread.cpp @@ -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 { diff --git a/src/ladspa/RubberBandPitchShifter.cpp b/src/ladspa/RubberBandPitchShifter.cpp index e174ae0..c0b2813 100644 --- a/src/ladspa/RubberBandPitchShifter.cpp +++ b/src/ladspa/RubberBandPitchShifter.cpp @@ -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,