* 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@
|
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)
|
LDFLAGS := @LDFLAGS@ -lpthread $(LDFLAGS)
|
||||||
|
|
||||||
LIBRARY_LIBS := @SRC_LIBS@ @FFTW_LIBS@
|
LIBRARY_LIBS := @SRC_LIBS@ @FFTW_LIBS@
|
||||||
@@ -42,6 +42,7 @@ LIBRARY_INCLUDES := \
|
|||||||
src/Resampler.h \
|
src/Resampler.h \
|
||||||
src/RingBuffer.h \
|
src/RingBuffer.h \
|
||||||
src/Scavenger.h \
|
src/Scavenger.h \
|
||||||
|
src/SpectralDifferenceAudioCurve.h \
|
||||||
src/StretchCalculator.h \
|
src/StretchCalculator.h \
|
||||||
src/StretcherImpl.h \
|
src/StretcherImpl.h \
|
||||||
src/StretcherChannelData.h \
|
src/StretcherChannelData.h \
|
||||||
@@ -56,6 +57,7 @@ LIBRARY_SOURCES := \
|
|||||||
src/PercussiveAudioCurve.cpp \
|
src/PercussiveAudioCurve.cpp \
|
||||||
src/AudioCurve.cpp \
|
src/AudioCurve.cpp \
|
||||||
src/Resampler.cpp \
|
src/Resampler.cpp \
|
||||||
|
src/SpectralDifferenceAudioCurve.cpp \
|
||||||
src/StretchCalculator.cpp \
|
src/StretchCalculator.cpp \
|
||||||
src/StretcherImpl.cpp \
|
src/StretcherImpl.cpp \
|
||||||
src/StretcherProcess.cpp \
|
src/StretcherProcess.cpp \
|
||||||
|
|||||||
2
TODO
2
TODO
@@ -3,10 +3,10 @@
|
|||||||
* LADSPA plugin has too much "artificial latency"
|
* LADSPA plugin has too much "artificial latency"
|
||||||
* LADSPA plugin probably doesn't want to go any higher than about +2 octaves
|
* LADSPA plugin probably doesn't want to go any higher than about +2 octaves
|
||||||
* Return value check in FFT and resampler!
|
* Return value check in FFT and resampler!
|
||||||
* implement+test, or remove, reset()
|
|
||||||
* sweeps & tones
|
* sweeps & tones
|
||||||
* ensure default options don't produce garbage at any extreme
|
* 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 * Add and test Win32 threading primitives in Thread.cpp
|
||||||
DONE * Threading lock structure is very slow if it becomes starved of CPUs
|
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
|
DONE * Rationalise naming further (e.g. use of "lock" for both peak phases
|
||||||
|
|||||||
172
src/FFT.cpp
172
src/FFT.cpp
@@ -47,33 +47,79 @@ public:
|
|||||||
|
|
||||||
virtual void inverse(float *realIn, float *imagIn, float *realOut) = 0;
|
virtual void inverse(float *realIn, float *imagIn, float *realOut) = 0;
|
||||||
virtual void inversePolar(float *magIn, float *phaseIn, 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_*
|
// Define FFTW_DOUBLE_ONLY to make all uses of FFTW functions be
|
||||||
// functions instead of converting to doubles and using fftw_*.
|
// double-precision (so "float" FFTs are calculated by casting to
|
||||||
#define FFTW_DOUBLE_ONLY 1
|
// 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_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_complex fftw_complex
|
||||||
#define fftwf_plan fftw_plan
|
#define fftwf_plan fftw_plan
|
||||||
#define fftwf_plan_dft_r2c_1d fftw_plan_dft_r2c_1d
|
#define fftwf_plan_dft_r2c_1d fftw_plan_dft_r2c_1d
|
||||||
#define fftwf_plan_dft_c2r_1d fftw_plan_dft_c2r_1d
|
#define fftwf_plan_dft_c2r_1d fftw_plan_dft_c2r_1d
|
||||||
#define fftwf_destroy_plan fftw_destroy_plan
|
#define fftwf_destroy_plan fftw_destroy_plan
|
||||||
|
#define fftwf_malloc fftw_malloc
|
||||||
#define fftwf_free fftw_free
|
#define fftwf_free fftw_free
|
||||||
#define fftwf_execute fftw_execute
|
#define fftwf_execute fftw_execute
|
||||||
#define atan2f atan2
|
#define atan2f atan2
|
||||||
#define sqrtf sqrt
|
#define sqrtf sqrt
|
||||||
#define cosf cos
|
#define cosf cos
|
||||||
#define sinf sin
|
#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
|
class D_FFTW : public FFTImpl
|
||||||
{
|
{
|
||||||
public:
|
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() {
|
~D_FFTW() {
|
||||||
@@ -87,6 +133,9 @@ public:
|
|||||||
fftwf_destroy_plan(m_fplani);
|
fftwf_destroy_plan(m_fplani);
|
||||||
fftwf_free(m_fbuf);
|
fftwf_free(m_fbuf);
|
||||||
fftwf_free(m_fpacked);
|
fftwf_free(m_fpacked);
|
||||||
|
#ifdef FFTW_DOUBLE_ONLY
|
||||||
|
if (m_frb) fftw_free(m_frb);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (m_dplanf) {
|
if (m_dplanf) {
|
||||||
bool save = false;
|
bool save = false;
|
||||||
@@ -98,6 +147,9 @@ public:
|
|||||||
fftw_destroy_plan(m_dplani);
|
fftw_destroy_plan(m_dplani);
|
||||||
fftw_free(m_dbuf);
|
fftw_free(m_dbuf);
|
||||||
fftw_free(m_dpacked);
|
fftw_free(m_dpacked);
|
||||||
|
#ifdef FFTW_FLOAT_ONLY
|
||||||
|
if (m_drb) fftwf_free(m_drb);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,11 +159,12 @@ public:
|
|||||||
m_extantMutex.lock();
|
m_extantMutex.lock();
|
||||||
if (m_extantf++ == 0) load = true;
|
if (m_extantf++ == 0) load = true;
|
||||||
m_extantMutex.unlock();
|
m_extantMutex.unlock();
|
||||||
if (load) loadWisdom('f');
|
|
||||||
#ifdef FFTW_DOUBLE_ONLY
|
#ifdef FFTW_DOUBLE_ONLY
|
||||||
|
if (load) loadWisdom('d');
|
||||||
m_fbuf = (double *)fftw_malloc(m_size * sizeof(double));
|
m_fbuf = (double *)fftw_malloc(m_size * sizeof(double));
|
||||||
#else
|
#else
|
||||||
m_fbuf = (float *)fftw_malloc(m_size * sizeof(float));
|
if (load) loadWisdom('f');
|
||||||
|
m_fbuf = (float *)fftwf_malloc(m_size * sizeof(float));
|
||||||
#endif
|
#endif
|
||||||
m_fpacked = (fftwf_complex *)fftw_malloc
|
m_fpacked = (fftwf_complex *)fftw_malloc
|
||||||
((m_size/2 + 1) * sizeof(fftwf_complex));
|
((m_size/2 + 1) * sizeof(fftwf_complex));
|
||||||
@@ -127,8 +180,13 @@ public:
|
|||||||
m_extantMutex.lock();
|
m_extantMutex.lock();
|
||||||
if (m_extantd++ == 0) load = true;
|
if (m_extantd++ == 0) load = true;
|
||||||
m_extantMutex.unlock();
|
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');
|
if (load) loadWisdom('d');
|
||||||
m_dbuf = (double *)fftw_malloc(m_size * sizeof(double));
|
m_dbuf = (double *)fftw_malloc(m_size * sizeof(double));
|
||||||
|
#endif
|
||||||
m_dpacked = (fftw_complex *)fftw_malloc
|
m_dpacked = (fftw_complex *)fftw_malloc
|
||||||
((m_size/2 + 1) * sizeof(fftw_complex));
|
((m_size/2 + 1) * sizeof(fftw_complex));
|
||||||
m_dplanf = fftw_plan_dft_r2c_1d
|
m_dplanf = fftw_plan_dft_r2c_1d
|
||||||
@@ -145,6 +203,9 @@ public:
|
|||||||
#ifdef FFTW_DOUBLE_ONLY
|
#ifdef FFTW_DOUBLE_ONLY
|
||||||
if (type == 'f') return;
|
if (type == 'f') return;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef FFTW_FLOAT_ONLY
|
||||||
|
if (type == 'd') return;
|
||||||
|
#endif
|
||||||
|
|
||||||
const char *home = getenv("HOME");
|
const char *home = getenv("HOME");
|
||||||
if (!home) return;
|
if (!home) return;
|
||||||
@@ -162,7 +223,11 @@ public:
|
|||||||
#else
|
#else
|
||||||
case 'f': fftwf_export_wisdom_to_file(f); break;
|
case 'f': fftwf_export_wisdom_to_file(f); break;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef FFTW_FLOAT_ONLY
|
||||||
|
case 'd': break;
|
||||||
|
#else
|
||||||
case 'd': fftw_export_wisdom_to_file(f); break;
|
case 'd': fftw_export_wisdom_to_file(f); break;
|
||||||
|
#endif
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -172,7 +237,11 @@ public:
|
|||||||
#else
|
#else
|
||||||
case 'f': fftwf_import_wisdom_from_file(f); break;
|
case 'f': fftwf_import_wisdom_from_file(f); break;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef FFTW_FLOAT_ONLY
|
||||||
|
case 'd': break;
|
||||||
|
#else
|
||||||
case 'd': fftw_import_wisdom_from_file(f); break;
|
case 'd': fftw_import_wisdom_from_file(f); break;
|
||||||
|
#endif
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,6 +279,9 @@ public:
|
|||||||
|
|
||||||
void forward(double *realIn, double *realOut, double *imagOut) {
|
void forward(double *realIn, double *realOut, double *imagOut) {
|
||||||
if (!m_dplanf) initDouble();
|
if (!m_dplanf) initDouble();
|
||||||
|
#ifndef FFTW_FLOAT_ONLY
|
||||||
|
if (realIn != m_dbuf)
|
||||||
|
#endif
|
||||||
for (unsigned int i = 0; i < m_size; ++i) {
|
for (unsigned int i = 0; i < m_size; ++i) {
|
||||||
m_dbuf[i] = realIn[i];
|
m_dbuf[i] = realIn[i];
|
||||||
}
|
}
|
||||||
@@ -219,6 +291,9 @@ public:
|
|||||||
|
|
||||||
void forwardPolar(double *realIn, double *magOut, double *phaseOut) {
|
void forwardPolar(double *realIn, double *magOut, double *phaseOut) {
|
||||||
if (!m_dplanf) initDouble();
|
if (!m_dplanf) initDouble();
|
||||||
|
#ifndef FFTW_FLOAT_ONLY
|
||||||
|
if (realIn != m_dbuf)
|
||||||
|
#endif
|
||||||
for (unsigned int i = 0; i < m_size; ++i) {
|
for (unsigned int i = 0; i < m_size; ++i) {
|
||||||
m_dbuf[i] = realIn[i];
|
m_dbuf[i] = realIn[i];
|
||||||
}
|
}
|
||||||
@@ -226,12 +301,17 @@ public:
|
|||||||
for (unsigned int i = 0; i <= m_size/2; ++i) {
|
for (unsigned int i = 0; i <= m_size/2; ++i) {
|
||||||
magOut[i] = sqrt(m_dpacked[i][0] * m_dpacked[i][0] +
|
magOut[i] = sqrt(m_dpacked[i][0] * m_dpacked[i][0] +
|
||||||
m_dpacked[i][1] * m_dpacked[i][1]);
|
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]);
|
phaseOut[i] = atan2(m_dpacked[i][1], m_dpacked[i][0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void forwardMagnitude(double *realIn, double *magOut) {
|
void forwardMagnitude(double *realIn, double *magOut) {
|
||||||
if (!m_dplanf) initDouble();
|
if (!m_dplanf) initDouble();
|
||||||
|
#ifndef FFTW_FLOAT_ONLY
|
||||||
|
if (realIn != m_dbuf)
|
||||||
|
#endif
|
||||||
for (unsigned int i = 0; i < m_size; ++i) {
|
for (unsigned int i = 0; i < m_size; ++i) {
|
||||||
m_dbuf[i] = realIn[i];
|
m_dbuf[i] = realIn[i];
|
||||||
}
|
}
|
||||||
@@ -244,6 +324,9 @@ public:
|
|||||||
|
|
||||||
void forward(float *realIn, float *realOut, float *imagOut) {
|
void forward(float *realIn, float *realOut, float *imagOut) {
|
||||||
if (!m_fplanf) initFloat();
|
if (!m_fplanf) initFloat();
|
||||||
|
#ifndef FFTW_DOUBLE_ONLY
|
||||||
|
if (realIn != m_fbuf)
|
||||||
|
#endif
|
||||||
for (unsigned int i = 0; i < m_size; ++i) {
|
for (unsigned int i = 0; i < m_size; ++i) {
|
||||||
m_fbuf[i] = realIn[i];
|
m_fbuf[i] = realIn[i];
|
||||||
}
|
}
|
||||||
@@ -253,6 +336,9 @@ public:
|
|||||||
|
|
||||||
void forwardPolar(float *realIn, float *magOut, float *phaseOut) {
|
void forwardPolar(float *realIn, float *magOut, float *phaseOut) {
|
||||||
if (!m_fplanf) initFloat();
|
if (!m_fplanf) initFloat();
|
||||||
|
#ifndef FFTW_DOUBLE_ONLY
|
||||||
|
if (realIn != m_fbuf)
|
||||||
|
#endif
|
||||||
for (unsigned int i = 0; i < m_size; ++i) {
|
for (unsigned int i = 0; i < m_size; ++i) {
|
||||||
m_fbuf[i] = realIn[i];
|
m_fbuf[i] = realIn[i];
|
||||||
}
|
}
|
||||||
@@ -260,12 +346,17 @@ public:
|
|||||||
for (unsigned int i = 0; i <= m_size/2; ++i) {
|
for (unsigned int i = 0; i <= m_size/2; ++i) {
|
||||||
magOut[i] = sqrtf(m_fpacked[i][0] * m_fpacked[i][0] +
|
magOut[i] = sqrtf(m_fpacked[i][0] * m_fpacked[i][0] +
|
||||||
m_fpacked[i][1] * m_fpacked[i][1]);
|
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]) ;
|
phaseOut[i] = atan2f(m_fpacked[i][1], m_fpacked[i][0]) ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void forwardMagnitude(float *realIn, float *magOut) {
|
void forwardMagnitude(float *realIn, float *magOut) {
|
||||||
if (!m_fplanf) initFloat();
|
if (!m_fplanf) initFloat();
|
||||||
|
#ifndef FFTW_DOUBLE_ONLY
|
||||||
|
if (realIn != m_fbuf)
|
||||||
|
#endif
|
||||||
for (unsigned int i = 0; i < m_size; ++i) {
|
for (unsigned int i = 0; i < m_size; ++i) {
|
||||||
m_fbuf[i] = realIn[i];
|
m_fbuf[i] = realIn[i];
|
||||||
}
|
}
|
||||||
@@ -280,6 +371,9 @@ public:
|
|||||||
if (!m_dplanf) initDouble();
|
if (!m_dplanf) initDouble();
|
||||||
packDouble(realIn, imagIn);
|
packDouble(realIn, imagIn);
|
||||||
fftw_execute(m_dplani);
|
fftw_execute(m_dplani);
|
||||||
|
#ifndef FFTW_FLOAT_ONLY
|
||||||
|
if (realOut != m_dbuf)
|
||||||
|
#endif
|
||||||
for (unsigned int i = 0; i < m_size; ++i) {
|
for (unsigned int i = 0; i < m_size; ++i) {
|
||||||
realOut[i] = m_dbuf[i];
|
realOut[i] = m_dbuf[i];
|
||||||
}
|
}
|
||||||
@@ -292,6 +386,9 @@ public:
|
|||||||
m_dpacked[i][1] = magIn[i] * sin(phaseIn[i]);
|
m_dpacked[i][1] = magIn[i] * sin(phaseIn[i]);
|
||||||
}
|
}
|
||||||
fftw_execute(m_dplani);
|
fftw_execute(m_dplani);
|
||||||
|
#ifndef FFTW_FLOAT_ONLY
|
||||||
|
if (realOut != m_dbuf)
|
||||||
|
#endif
|
||||||
for (unsigned int i = 0; i < m_size; ++i) {
|
for (unsigned int i = 0; i < m_size; ++i) {
|
||||||
realOut[i] = m_dbuf[i];
|
realOut[i] = m_dbuf[i];
|
||||||
}
|
}
|
||||||
@@ -301,6 +398,9 @@ public:
|
|||||||
if (!m_fplanf) initFloat();
|
if (!m_fplanf) initFloat();
|
||||||
packFloat(realIn, imagIn);
|
packFloat(realIn, imagIn);
|
||||||
fftwf_execute(m_fplani);
|
fftwf_execute(m_fplani);
|
||||||
|
#ifndef FFTW_DOUBLE_ONLY
|
||||||
|
if (realOut != m_fbuf)
|
||||||
|
#endif
|
||||||
for (unsigned int i = 0; i < m_size; ++i) {
|
for (unsigned int i = 0; i < m_size; ++i) {
|
||||||
realOut[i] = m_fbuf[i];
|
realOut[i] = m_fbuf[i];
|
||||||
}
|
}
|
||||||
@@ -313,15 +413,39 @@ public:
|
|||||||
m_fpacked[i][1] = magIn[i] * sinf(phaseIn[i]);
|
m_fpacked[i][1] = magIn[i] * sinf(phaseIn[i]);
|
||||||
}
|
}
|
||||||
fftwf_execute(m_fplani);
|
fftwf_execute(m_fplani);
|
||||||
|
#ifndef FFTW_DOUBLE_ONLY
|
||||||
|
if (realOut != m_fbuf)
|
||||||
|
#endif
|
||||||
for (unsigned int i = 0; i < m_size; ++i) {
|
for (unsigned int i = 0; i < m_size; ++i) {
|
||||||
realOut[i] = m_fbuf[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:
|
private:
|
||||||
fftwf_plan m_fplanf;
|
fftwf_plan m_fplanf;
|
||||||
fftwf_plan m_fplani;
|
fftwf_plan m_fplani;
|
||||||
#ifdef FFTW_DOUBLE_ONLY
|
#ifdef FFTW_DOUBLE_ONLY
|
||||||
|
float *m_frb;
|
||||||
double *m_fbuf;
|
double *m_fbuf;
|
||||||
#else
|
#else
|
||||||
float *m_fbuf;
|
float *m_fbuf;
|
||||||
@@ -329,7 +453,12 @@ private:
|
|||||||
fftwf_complex *m_fpacked;
|
fftwf_complex *m_fpacked;
|
||||||
fftw_plan m_dplanf;
|
fftw_plan m_dplanf;
|
||||||
fftw_plan m_dplani;
|
fftw_plan m_dplani;
|
||||||
|
#ifdef FFTW_FLOAT_ONLY
|
||||||
|
float *m_dbuf;
|
||||||
|
double *m_drb;
|
||||||
|
#else
|
||||||
double *m_dbuf;
|
double *m_dbuf;
|
||||||
|
#endif
|
||||||
fftw_complex *m_dpacked;
|
fftw_complex *m_dpacked;
|
||||||
unsigned int m_size;
|
unsigned int m_size;
|
||||||
static unsigned int m_extantf;
|
static unsigned int m_extantf;
|
||||||
@@ -346,11 +475,12 @@ D_FFTW::m_extantd = 0;
|
|||||||
Mutex
|
Mutex
|
||||||
D_FFTW::m_extantMutex;
|
D_FFTW::m_extantMutex;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
class D_Cross : public FFTImpl
|
class D_Cross : public FFTImpl
|
||||||
{
|
{
|
||||||
public:
|
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_a = new double[size];
|
||||||
m_b = new double[size];
|
m_b = new double[size];
|
||||||
@@ -388,6 +518,8 @@ public:
|
|||||||
delete[] m_b;
|
delete[] m_b;
|
||||||
delete[] m_c;
|
delete[] m_c;
|
||||||
delete[] m_d;
|
delete[] m_d;
|
||||||
|
delete[] m_frb;
|
||||||
|
delete[] m_drb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initFloat() { }
|
void initFloat() { }
|
||||||
@@ -496,9 +628,21 @@ public:
|
|||||||
for (unsigned int i = 0; i < m_size; ++i) realOut[i] = m_c[i];
|
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:
|
private:
|
||||||
unsigned int m_size;
|
unsigned int m_size;
|
||||||
int *m_table;
|
int *m_table;
|
||||||
|
float *m_frb;
|
||||||
|
double *m_drb;
|
||||||
double *m_a;
|
double *m_a;
|
||||||
double *m_b;
|
double *m_b;
|
||||||
double *m_c;
|
double *m_c;
|
||||||
@@ -701,6 +845,18 @@ FFT::initDouble()
|
|||||||
d->initDouble();
|
d->initDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float *
|
||||||
|
FFT::getFloatTimeBuffer()
|
||||||
|
{
|
||||||
|
return d->getFloatTimeBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
double *
|
||||||
|
FFT::getDoubleTimeBuffer()
|
||||||
|
{
|
||||||
|
return d->getDoubleTimeBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
FFT::tune()
|
FFT::tune()
|
||||||
|
|||||||
@@ -60,6 +60,9 @@ public:
|
|||||||
void initFloat();
|
void initFloat();
|
||||||
void initDouble();
|
void initDouble();
|
||||||
|
|
||||||
|
float *getFloatTimeBuffer();
|
||||||
|
double *getDoubleTimeBuffer();
|
||||||
|
|
||||||
static void tune();
|
static void tune();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -20,24 +20,15 @@ namespace RubberBand
|
|||||||
HighFrequencyAudioCurve::HighFrequencyAudioCurve(size_t sampleRate, size_t windowSize) :
|
HighFrequencyAudioCurve::HighFrequencyAudioCurve(size_t sampleRate, size_t windowSize) :
|
||||||
AudioCurve(sampleRate, 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()
|
HighFrequencyAudioCurve::~HighFrequencyAudioCurve()
|
||||||
{
|
{
|
||||||
delete[] m_prevMag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
HighFrequencyAudioCurve::reset()
|
HighFrequencyAudioCurve::reset()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i <= m_windowSize/2; ++i) {
|
|
||||||
m_prevMag[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -52,7 +43,7 @@ HighFrequencyAudioCurve::process(float *mag, size_t increment)
|
|||||||
float result = 0.0;
|
float result = 0.0;
|
||||||
|
|
||||||
for (size_t n = 0; n <= m_windowSize / 2; ++n) {
|
for (size_t n = 0; n <= m_windowSize / 2; ++n) {
|
||||||
result += mag[n];
|
result += mag[n] * n;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -32,9 +32,6 @@ public:
|
|||||||
|
|
||||||
virtual float process(float *mag, size_t increment);
|
virtual float process(float *mag, size_t increment);
|
||||||
virtual void reset();
|
virtual void reset();
|
||||||
|
|
||||||
protected:
|
|
||||||
double *m_prevMag;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ PercussiveAudioCurve::process(float *mag, size_t increment)
|
|||||||
size_t nonZeroCount = 0;
|
size_t nonZeroCount = 0;
|
||||||
|
|
||||||
for (size_t n = 1; n <= m_windowSize / 2; ++n) {
|
for (size_t n = 1; n <= m_windowSize / 2; ++n) {
|
||||||
//!!! adjust threshold so that this multiplication is unnecessary
|
|
||||||
float sqrmag = mag[n] * mag[n];
|
float sqrmag = mag[n] * mag[n];
|
||||||
bool above = ((sqrmag / m_prevMag[n]) >= threshold);
|
bool above = ((sqrmag / m_prevMag[n]) >= threshold);
|
||||||
if (above) ++count;
|
if (above) ++count;
|
||||||
@@ -71,7 +70,6 @@ PercussiveAudioCurve::process(float *mag, size_t increment)
|
|||||||
m_prevMag[n] = sqrmag;
|
m_prevMag[n] = sqrmag;
|
||||||
}
|
}
|
||||||
|
|
||||||
//!!! return float(count) / float(m_windowSize);
|
|
||||||
if (nonZeroCount == 0) return 0;
|
if (nonZeroCount == 0) return 0;
|
||||||
else return float(count) / float(nonZeroCount);
|
else return float(count) / float(nonZeroCount);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
|
|||||||
windowAccumulator = new float[maxSize];
|
windowAccumulator = new float[maxSize];
|
||||||
|
|
||||||
fltbuf = new float[maxSize];
|
fltbuf = new float[maxSize];
|
||||||
dblbuf = new double[maxSize];
|
|
||||||
|
|
||||||
for (std::set<size_t>::const_iterator i = windowSizes.begin();
|
for (std::set<size_t>::const_iterator i = windowSizes.begin();
|
||||||
i != windowSizes.end(); ++i) {
|
i != windowSizes.end(); ++i) {
|
||||||
@@ -69,6 +68,8 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
|
|||||||
}
|
}
|
||||||
fft = ffts[initialWindowSize];
|
fft = ffts[initialWindowSize];
|
||||||
|
|
||||||
|
dblbuf = fft->getDoubleTimeBuffer();
|
||||||
|
|
||||||
resampler = 0;
|
resampler = 0;
|
||||||
resamplebuf = 0;
|
resamplebuf = 0;
|
||||||
resamplebufSize = 0;
|
resamplebufSize = 0;
|
||||||
@@ -83,10 +84,13 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
|
|||||||
freqPeak[i] = 0;
|
freqPeak[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < initialWindowSize; ++i) {
|
||||||
|
dblbuf[i] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < maxSize; ++i) {
|
for (size_t i = 0; i < maxSize; ++i) {
|
||||||
accumulator[i] = 0.f;
|
accumulator[i] = 0.f;
|
||||||
windowAccumulator[i] = 0.f;
|
windowAccumulator[i] = 0.f;
|
||||||
dblbuf[i] = 0.0;
|
|
||||||
fltbuf[i] = 0.0;
|
fltbuf[i] = 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,6 +120,12 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
|
|||||||
|
|
||||||
fft = ffts[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) {
|
for (size_t i = 0; i < realSize; ++i) {
|
||||||
mag[i] = 0.0;
|
mag[i] = 0.0;
|
||||||
phase[i] = 0.0;
|
phase[i] = 0.0;
|
||||||
@@ -153,10 +163,7 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
|
|||||||
freqPeak = new size_t[realSize];
|
freqPeak = new size_t[realSize];
|
||||||
|
|
||||||
delete[] fltbuf;
|
delete[] fltbuf;
|
||||||
delete[] dblbuf;
|
|
||||||
|
|
||||||
fltbuf = new float[windowSize];
|
fltbuf = new float[windowSize];
|
||||||
dblbuf = new double[windowSize];
|
|
||||||
|
|
||||||
// But we do want to preserve data in these
|
// 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) {
|
for (size_t i = 0; i < windowSize; ++i) {
|
||||||
dblbuf[i] = 0.0;
|
|
||||||
fltbuf[i] = 0.0;
|
fltbuf[i] = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,6 +202,12 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fft = ffts[windowSize];
|
fft = ffts[windowSize];
|
||||||
|
|
||||||
|
dblbuf = fft->getDoubleTimeBuffer();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < windowSize; ++i) {
|
||||||
|
dblbuf[i] = 0.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -231,7 +243,6 @@ RubberBandStretcher::Impl::ChannelData::~ChannelData()
|
|||||||
delete[] accumulator;
|
delete[] accumulator;
|
||||||
delete[] windowAccumulator;
|
delete[] windowAccumulator;
|
||||||
delete[] fltbuf;
|
delete[] fltbuf;
|
||||||
delete[] dblbuf;
|
|
||||||
|
|
||||||
for (std::map<size_t, FFT *>::iterator i = ffts.begin();
|
for (std::map<size_t, FFT *>::iterator i = ffts.begin();
|
||||||
i != ffts.end(); ++i) {
|
i != ffts.end(); ++i) {
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ public:
|
|||||||
float *windowAccumulator;
|
float *windowAccumulator;
|
||||||
|
|
||||||
float *fltbuf;
|
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
|
size_t prevIncrement; // only used in RT mode
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "StretcherImpl.h"
|
#include "StretcherImpl.h"
|
||||||
#include "PercussiveAudioCurve.h"
|
#include "PercussiveAudioCurve.h"
|
||||||
#include "HighFrequencyAudioCurve.h"
|
#include "HighFrequencyAudioCurve.h"
|
||||||
|
#include "SpectralDifferenceAudioCurve.h"
|
||||||
#include "ConstantAudioCurve.h"
|
#include "ConstantAudioCurve.h"
|
||||||
#include "StretchCalculator.h"
|
#include "StretchCalculator.h"
|
||||||
#include "StretcherChannelData.h"
|
#include "StretcherChannelData.h"
|
||||||
@@ -113,7 +114,6 @@ RubberBandStretcher::Impl::Impl(RubberBandStretcher *stretcher,
|
|||||||
m_realtime = true;
|
m_realtime = true;
|
||||||
|
|
||||||
if (!(m_options & OptionStretchPrecise)) {
|
if (!(m_options & OptionStretchPrecise)) {
|
||||||
cerr << "RubberBandStretcher::Impl::Impl: Real-time mode: enabling OptionStretchPrecise" << endl;
|
|
||||||
m_options |= OptionStretchPrecise;
|
m_options |= OptionStretchPrecise;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,6 +148,7 @@ RubberBandStretcher::Impl::~Impl()
|
|||||||
if (m_debugLevel > 0) {
|
if (m_debugLevel > 0) {
|
||||||
cerr << "RubberBandStretcher::~RubberBandStretcher: joining (channel " << *i << ")" << endl;
|
cerr << "RubberBandStretcher::~RubberBandStretcher: joining (channel " << *i << ")" << endl;
|
||||||
}
|
}
|
||||||
|
(*i)->abandon();
|
||||||
(*i)->wait();
|
(*i)->wait();
|
||||||
delete *i;
|
delete *i;
|
||||||
}
|
}
|
||||||
@@ -171,21 +172,32 @@ RubberBandStretcher::Impl::~Impl()
|
|||||||
void
|
void
|
||||||
RubberBandStretcher::Impl::reset()
|
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) {
|
for (size_t c = 0; c < m_channels; ++c) {
|
||||||
delete m_channelData[c];
|
m_channelData[c]->reset();
|
||||||
m_channelData[c] = new ChannelData(m_windowSize, m_outbufSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_mode = JustCreated;
|
m_mode = JustCreated;
|
||||||
if (m_phaseResetAudioCurve) m_phaseResetAudioCurve->reset();
|
if (m_phaseResetAudioCurve) m_phaseResetAudioCurve->reset();
|
||||||
if (m_stretchAudioCurve) m_stretchAudioCurve->reset();
|
if (m_stretchAudioCurve) m_stretchAudioCurve->reset();
|
||||||
m_inputDuration = 0;
|
m_inputDuration = 0;
|
||||||
|
|
||||||
if (m_threaded) m_threadSetMutex.unlock();
|
if (m_threaded) m_threadSetMutex.unlock();
|
||||||
// m_done = false;
|
|
||||||
|
reconfigure();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -407,19 +419,14 @@ RubberBandStretcher::Impl::calculateSizes()
|
|||||||
if (m_debugLevel > 0) {
|
if (m_debugLevel > 0) {
|
||||||
cerr << "configure: outbuf size = " << m_outbufSize << endl;
|
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
|
void
|
||||||
RubberBandStretcher::Impl::configure()
|
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 prevWindowSize = m_windowSize;
|
||||||
size_t prevOutbufSize = m_outbufSize;
|
size_t prevOutbufSize = m_outbufSize;
|
||||||
if (m_windows.empty()) {
|
if (m_windows.empty()) {
|
||||||
@@ -512,9 +519,7 @@ RubberBandStretcher::Impl::configure()
|
|||||||
if (!m_realtime) {
|
if (!m_realtime) {
|
||||||
delete m_stretchAudioCurve;
|
delete m_stretchAudioCurve;
|
||||||
if (!(m_options & OptionStretchPrecise)) {
|
if (!(m_options & OptionStretchPrecise)) {
|
||||||
//!!! probably adaptively-whitened spectral difference curve
|
m_stretchAudioCurve = new SpectralDifferenceAudioCurve
|
||||||
//would be better
|
|
||||||
m_stretchAudioCurve = new HighFrequencyAudioCurve
|
|
||||||
(m_stretcher->m_sampleRate, m_windowSize);
|
(m_stretcher->m_sampleRate, m_windowSize);
|
||||||
} else {
|
} else {
|
||||||
m_stretchAudioCurve = new ConstantAudioCurve
|
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
|
void
|
||||||
RubberBandStretcher::Impl::reconfigure()
|
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) {
|
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) {
|
if (m_mode == Studying) {
|
||||||
calculateStretch();
|
calculateStretch();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,10 +145,12 @@ protected:
|
|||||||
ProcessThread(Impl *s, size_t c);
|
ProcessThread(Impl *s, size_t c);
|
||||||
void run();
|
void run();
|
||||||
void signalDataAvailable();
|
void signalDataAvailable();
|
||||||
|
void abandon();
|
||||||
private:
|
private:
|
||||||
Impl *m_s;
|
Impl *m_s;
|
||||||
size_t m_channel;
|
size_t m_channel;
|
||||||
Condition m_dataAvailable;
|
Condition m_dataAvailable;
|
||||||
|
bool m_abandoning;
|
||||||
};
|
};
|
||||||
|
|
||||||
mutable Mutex m_threadSetMutex;
|
mutable Mutex m_threadSetMutex;
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ namespace RubberBand {
|
|||||||
RubberBandStretcher::Impl::ProcessThread::ProcessThread(Impl *s, size_t c) :
|
RubberBandStretcher::Impl::ProcessThread::ProcessThread(Impl *s, size_t c) :
|
||||||
m_s(s),
|
m_s(s),
|
||||||
m_channel(c),
|
m_channel(c),
|
||||||
m_dataAvailable(std::string("data ") + char('A' + c))
|
m_dataAvailable(std::string("data ") + char('A' + c)),
|
||||||
|
m_abandoning(false)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -61,11 +62,18 @@ RubberBandStretcher::Impl::ProcessThread::run()
|
|||||||
if (any) m_s->m_spaceAvailable.signal();
|
if (any) m_s->m_spaceAvailable.signal();
|
||||||
|
|
||||||
m_dataAvailable.lock();
|
m_dataAvailable.lock();
|
||||||
if (!m_s->testInbufReadSpace(m_channel)) {
|
if (!m_s->testInbufReadSpace(m_channel) && !m_abandoning) {
|
||||||
m_dataAvailable.wait();
|
m_dataAvailable.wait();
|
||||||
} else {
|
} else {
|
||||||
m_dataAvailable.unlock();
|
m_dataAvailable.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_abandoning) {
|
||||||
|
if (m_s->m_debugLevel > 1) {
|
||||||
|
cerr << "thread " << m_channel << " abandoning" << endl;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool any = false, last = false;
|
bool any = false, last = false;
|
||||||
@@ -83,6 +91,12 @@ RubberBandStretcher::Impl::ProcessThread::signalDataAvailable()
|
|||||||
m_dataAvailable.signal();
|
m_dataAvailable.signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RubberBandStretcher::Impl::ProcessThread::abandon()
|
||||||
|
{
|
||||||
|
m_abandoning = true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RubberBandStretcher::Impl::processChunks(size_t c, bool &any, bool &last)
|
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);
|
m_id = CreateThread(NULL, 0, staticRun, this, 0, 0);
|
||||||
if (!m_id) {
|
if (!m_id) {
|
||||||
//!!!
|
|
||||||
cerr << "ERROR: thread creation failed" << endl;
|
cerr << "ERROR: thread creation failed" << endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
} else {
|
} else {
|
||||||
@@ -296,7 +295,6 @@ void
|
|||||||
Thread::start()
|
Thread::start()
|
||||||
{
|
{
|
||||||
if (pthread_create(&m_id, 0, staticRun, this)) {
|
if (pthread_create(&m_id, 0, staticRun, this)) {
|
||||||
//!!!
|
|
||||||
cerr << "ERROR: thread creation failed" << endl;
|
cerr << "ERROR: thread creation failed" << endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -139,8 +139,8 @@ RubberBandPitchShifter::ladspaDescriptorMono =
|
|||||||
"rubberband-pitchshifter-mono", // Label
|
"rubberband-pitchshifter-mono", // Label
|
||||||
properties,
|
properties,
|
||||||
"Rubber Band Mono Pitch Shifter", // Name
|
"Rubber Band Mono Pitch Shifter", // Name
|
||||||
"Chris Cannam", //!!! Maker
|
"Chris Cannam",
|
||||||
"GPL", //!!! Copyright
|
"GPL",
|
||||||
PortCountMono,
|
PortCountMono,
|
||||||
portsMono,
|
portsMono,
|
||||||
portNamesMono,
|
portNamesMono,
|
||||||
@@ -163,8 +163,8 @@ RubberBandPitchShifter::ladspaDescriptorStereo =
|
|||||||
"rubberband-pitchshifter-stereo", // Label
|
"rubberband-pitchshifter-stereo", // Label
|
||||||
properties,
|
properties,
|
||||||
"Rubber Band Stereo Pitch Shifter", // Name
|
"Rubber Band Stereo Pitch Shifter", // Name
|
||||||
"Chris Cannam", //!!! Maker
|
"Chris Cannam",
|
||||||
"GPL", //!!! Copyright
|
"GPL",
|
||||||
PortCountStereo,
|
PortCountStereo,
|
||||||
portsStereo,
|
portsStereo,
|
||||||
portNamesStereo,
|
portNamesStereo,
|
||||||
|
|||||||
Reference in New Issue
Block a user