diff --git a/Makefile.in b/Makefile.in index 9cd7ffc..1cce180 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 $(CXXFLAGS) +CXXFLAGS := @CXXFLAGS@ @SRC_CFLAGS@ @SNDFILE_CFLAGS@ @FFTW_CFLAGS@ @Vamp_CFLAGS@ -Irubberband -Isrc $(OPTFLAGS) LDFLAGS := @LDFLAGS@ -lpthread $(LDFLAGS) LIBRARY_LIBS := @SRC_LIBS@ @FFTW_LIBS@ diff --git a/src/FFT.cpp b/src/FFT.cpp index 2f2cd58..86037f7 100644 --- a/src/FFT.cpp +++ b/src/FFT.cpp @@ -157,14 +157,19 @@ public: if (save) { switch (type) { -#ifndef FFTW_DOUBLE_ONLY +#ifdef FFTW_DOUBLE_ONLY + case 'f': break; +#else case 'f': fftwf_export_wisdom_to_file(f); break; +#endif case 'd': fftw_export_wisdom_to_file(f); break; default: break; } } else { switch (type) { -#ifndef FFTW_DOUBLE_ONLY +#ifdef FFTW_DOUBLE_ONLY + case 'f': break; +#else case 'f': fftwf_import_wisdom_from_file(f); break; #endif case 'd': fftw_import_wisdom_from_file(f); break; @@ -341,7 +346,6 @@ D_FFTW::m_extantd = 0; Mutex D_FFTW::m_extantMutex; -#endif class D_Cross : public FFTImpl { @@ -613,8 +617,8 @@ FFT::FFT(unsigned int size) break; default: -// std::cerr << "FFT::FFT(" << size << "): using built-in implementation" -// << std::endl; + std::cerr << "FFT::FFT(" << size << "): WARNING: using slow built-in implementation" + << std::endl; d = new D_Cross(size); break; } diff --git a/src/RingBuffer.h b/src/RingBuffer.h index 62a884a..a3673d3 100644 --- a/src/RingBuffer.h +++ b/src/RingBuffer.h @@ -16,14 +16,22 @@ #define _RUBBERBAND_RINGBUFFER_H_ #include + +#ifndef _WIN32 #include +#endif #include "Scavenger.h" //#define DEBUG_RINGBUFFER 1 +#ifdef _WIN32 +#define MLOCK(a,b) 1 +#define MUNLOCK(a,b) 1 +#else #define MLOCK(a,b) ::mlock(a,b) #define MUNLOCK(a,b) ::munlock(a,b) +#endif #ifdef DEBUG_RINGBUFFER #include diff --git a/src/Scavenger.h b/src/Scavenger.h index e4385f9..54af5da 100644 --- a/src/Scavenger.h +++ b/src/Scavenger.h @@ -18,9 +18,11 @@ #include #include #include -#include #include +#include "Thread.h" +#include "sysutils.h" + namespace RubberBand { /** @@ -62,7 +64,7 @@ protected: typedef std::list ObjectList; ObjectList m_excess; int m_lastExcess; - pthread_mutex_t m_excessMutex; + Mutex m_excessMutex; void pushExcess(T *); void clearExcess(int); @@ -93,7 +95,6 @@ Scavenger::Scavenger(int sec, int defaultObjectListSize) : m_claimed(0), m_scavenged(0) { - pthread_mutex_init(&m_excessMutex, 0); } template @@ -171,26 +172,26 @@ template void Scavenger::pushExcess(T *t) { - pthread_mutex_lock(&m_excessMutex); + m_excessMutex.lock(); m_excess.push_back(t); struct timeval tv; (void)gettimeofday(&tv, 0); m_lastExcess = tv.tv_sec; - pthread_mutex_unlock(&m_excessMutex); + m_excessMutex.unlock(); } template void Scavenger::clearExcess(int sec) { - pthread_mutex_lock(&m_excessMutex); + m_excessMutex.lock(); for (typename ObjectList::iterator i = m_excess.begin(); i != m_excess.end(); ++i) { delete *i; } m_excess.clear(); m_lastExcess = sec; - pthread_mutex_unlock(&m_excessMutex); + m_excessMutex.unlock(); } } diff --git a/src/StretcherProcess.cpp b/src/StretcherProcess.cpp index 983ae86..e0ead05 100644 --- a/src/StretcherProcess.cpp +++ b/src/StretcherProcess.cpp @@ -242,7 +242,7 @@ RubberBandStretcher::Impl::processChunkForChannel(size_t c, if (m_debugLevel > 2) { if (phaseReset) { for (int i = 0; i < 10; ++i) { - cd.accumulator[i] = ((drand48() * 2 - 1.0) > 0 ? 1 : -1); + cd.accumulator[i] = 1.2f - (i % 3) * 1.2f; } } } diff --git a/src/Thread.cpp b/src/Thread.cpp index c5f0570..642287b 100644 --- a/src/Thread.cpp +++ b/src/Thread.cpp @@ -30,6 +30,245 @@ using std::string; namespace RubberBand { +#ifdef _WIN32 + +Thread::Thread() : + m_id(0), + m_extant(false) +{ +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Created thread object " << this << endl; +#endif +} + +Thread::~Thread() +{ +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Destroying thread object " << this << ", id " << m_id << endl; +#endif + if (m_extant) { + WaitForSingleObject(m_id, INFINITE); + } +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Destroyed thread object " << this << endl; +#endif +} + +void +Thread::start() +{ + m_id = CreateThread(NULL, 0, staticRun, this, 0, 0); + if (!m_id) { + //!!! + cerr << "ERROR: thread creation failed" << endl; + exit(1); + } else { +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Created thread " << m_id << " for thread object " << this << endl; +#endif + m_extant = true; + } +} + +void +Thread::wait() +{ + if (m_extant) { +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Waiting on thread " << m_id << " for thread object " << this << endl; +#endif + WaitForSingleObject(m_id, INFINITE); +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Waited on thread " << m_id << " for thread object " << this << endl; +#endif + m_extant = false; + } +} + +Thread::Id +Thread::id() +{ + return m_id; +} + +bool +Thread::threadingAvailable() +{ + return true; +} + +DWORD +Thread::staticRun(LPVOID arg) +{ + Thread *thread = static_cast(arg); +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: " << (void *)GetCurrentThreadId() << ": Running thread " << thread->m_id << " for thread object " << thread << endl; +#endif + thread->run(); + return 0; +} + +Mutex::Mutex() : + m_locked(false) +{ + m_mutex = CreateMutex(NULL, FALSE, NULL); +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Initialised mutex " << &m_mutex << endl; +#endif +} + +Mutex::~Mutex() +{ +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Destroying mutex " << &m_mutex << endl; +#endif + CloseHandle(m_mutex); +} + +void +Mutex::lock() +{ + if (m_locked) { + cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl; + } +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Want to lock mutex " << &m_mutex << endl; +#endif + WaitForSingleObject(m_mutex, INFINITE); + m_locked = true; +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Locked mutex " << &m_mutex << endl; +#endif +} + +void +Mutex::unlock() +{ +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Unlocking mutex " << &m_mutex << endl; +#endif + m_locked = false; + ReleaseMutex(m_mutex); +} + +bool +Mutex::trylock() +{ + DWORD result = WaitForSingleObject(m_mutex, 0); + if (result == WAIT_TIMEOUT || result == WAIT_FAILED) { +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Mutex " << &m_mutex << " unavailable" << endl; +#endif + return false; + } else { + m_locked = true; +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Locked mutex " << &m_mutex << " (from trylock)" << endl; +#endif + return true; + } +} + +Condition::Condition(string name) : + m_name(name), + m_locked(false) +{ + m_mutex = CreateMutex(NULL, FALSE, NULL); + m_condition = CreateEvent(NULL, FALSE, FALSE, NULL); +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Initialised condition " << &m_condition << " \"" << m_name << "\"" << endl; +#endif +} + +Condition::~Condition() +{ +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Destroying condition " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + if (m_locked) ReleaseMutex(m_mutex); + CloseHandle(m_condition); + CloseHandle(m_mutex); +} + +void +Condition::lock() +{ + if (m_locked) { +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Already locked " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + return; + } +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Want to lock " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + WaitForSingleObject(m_mutex, INFINITE); + m_locked = true; +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Locked " << &m_condition << " \"" << m_name << "\"" << endl; +#endif +} + +void +Condition::unlock() +{ + if (!m_locked) { +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Not locked " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + return; + } +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Unlocking " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + m_locked = false; + ReleaseMutex(m_mutex); +} + +void +Condition::wait(int us) +{ + if (!m_locked) lock(); + + if (us == 0) { + +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Waiting on " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + SignalObjectAndWait(m_mutex, m_condition, INFINITE, FALSE); + WaitForSingleObject(m_mutex, INFINITE); + + } else { + + DWORD ms = us / 1000; + if (us > 0 && ms == 0) ms = 1; + +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Timed waiting on " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + SignalObjectAndWait(m_mutex, m_condition, ms, FALSE); + WaitForSingleObject(m_mutex, INFINITE); + } + + ReleaseMutex(m_mutex); + +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Wait done on " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + m_locked = false; +} + +void +Condition::signal() +{ +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Signalling " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + SetEvent(m_condition); +} + +#else /* !_WIN32 */ + Thread::Thread() : m_id(0), @@ -98,7 +337,7 @@ Thread::threadingAvailable() void * Thread::staticRun(void *arg) { - Thread *thread = (Thread *)arg; + Thread *thread = static_cast(arg); #ifdef DEBUG_THREAD cerr << "THREAD DEBUG: " << (void *)pthread_self() << ": Running thread " << thread->m_id << " for thread object " << thread << endl; #endif @@ -106,7 +345,8 @@ Thread::staticRun(void *arg) return 0; } -Mutex::Mutex() +Mutex::Mutex() : + m_locked(false) { pthread_mutex_init(&m_mutex, 0); #ifdef DEBUG_MUTEX @@ -166,10 +406,10 @@ Mutex::trylock() } Condition::Condition(string name) : + m_locked(false), m_name(name) { pthread_mutex_init(&m_mutex, 0); - m_locked = false; pthread_cond_init(&m_condition, 0); #ifdef DEBUG_CONDITION cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Initialised condition " << &m_condition << " \"" << m_name << "\"" << endl; @@ -254,10 +494,11 @@ Condition::wait(int us) pthread_cond_timedwait(&m_condition, &m_mutex, &timeout); } + pthread_mutex_unlock(&m_mutex); + #ifdef DEBUG_CONDITION cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Wait done on " << &m_condition << " \"" << m_name << "\"" << endl; #endif - pthread_mutex_unlock(&m_mutex); m_locked = false; } @@ -270,6 +511,7 @@ Condition::signal() pthread_cond_signal(&m_condition); } +#endif /* !_WIN32 */ MutexLocker::MutexLocker(Mutex *mutex) : m_mutex(mutex) diff --git a/src/Thread.h b/src/Thread.h index d419d85..dc37f6d 100644 --- a/src/Thread.h +++ b/src/Thread.h @@ -15,7 +15,11 @@ #ifndef _RUBBERBAND_THREAD_H_ #define _RUBBERBAND_THREAD_H_ +#ifdef _WIN32 +#include +#else /* !_WIN32 */ #include +#endif /* !_WIN32 */ #include @@ -25,7 +29,11 @@ namespace RubberBand class Thread { public: +#ifdef _WIN32 + typedef HANDLE Id; +#else typedef pthread_t Id; +#endif Thread(); virtual ~Thread(); @@ -41,9 +49,15 @@ protected: virtual void run() = 0; private: +#ifdef _WIN32 + HANDLE m_id; + bool m_extant; + static DWORD WINAPI staticRun(LPVOID lpParam); +#else pthread_t m_id; bool m_extant; static void *staticRun(void *); +#endif }; class Mutex @@ -57,8 +71,13 @@ public: bool trylock(); private: +#ifdef _WIN32 + HANDLE m_mutex; + bool m_locked; +#else pthread_mutex_t m_mutex; bool m_locked; +#endif }; class MutexLocker @@ -77,16 +96,34 @@ public: Condition(std::string name); ~Condition(); + // To wait on a condition, either simply call wait(), or call + // lock() and then wait() (perhaps testing some state in between). + // To signal a condition, call signal(). + + // Although any thread may signal on a given condition, only one + // thread should ever wait on any given condition object -- + // otherwise there will be a race conditions in the logic that + // avoids the thread code having to track whether the condition's + // mutex is locked or not. If that is your requirement, this + // Condition wrapper is not for you. void lock(); void unlock(); void wait(int us = 0); + void signal(); private: +#ifdef _WIN32 + HANDLE m_mutex; + bool m_locked; + HANDLE m_condition; + std::string m_name; +#else pthread_mutex_t m_mutex; bool m_locked; pthread_cond_t m_condition; std::string m_name; +#endif }; } diff --git a/src/ladspa/RubberBandPitchShifter.h b/src/ladspa/RubberBandPitchShifter.h index fd7474c..3adfb61 100644 --- a/src/ladspa/RubberBandPitchShifter.h +++ b/src/ladspa/RubberBandPitchShifter.h @@ -15,7 +15,7 @@ #ifndef _RUBBERBAND_PITCH_SHIFTER_H_ #define _RUBBERBAND_PITCH_SHIFTER_H_ -#include +#include "ladspa.h" #include "RingBuffer.h" diff --git a/src/ladspa/libmain.cpp b/src/ladspa/libmain.cpp index 6c40799..afc7ac0 100644 --- a/src/ladspa/libmain.cpp +++ b/src/ladspa/libmain.cpp @@ -12,8 +12,6 @@ COPYING included with this distribution for more information. */ -#include - #include "RubberBandPitchShifter.h" #include diff --git a/src/main.cpp b/src/main.cpp index 32da1a3..c537584 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,6 +19,7 @@ #include #include #include +#include "sysutils.h" #include @@ -28,6 +29,11 @@ using namespace std; using namespace RubberBand; +#ifdef _WIN32 +using RubberBand::gettimeofday; +using RubberBand::usleep; +#endif + int main(int argc, char **argv) { int c; @@ -251,7 +257,10 @@ int main(int argc, char **argv) frequencyshift *= pow(2.0, pitchshift / 12); } - struct timeval tv; +#ifdef _WIN32 + RubberBand:: +#endif + timeval tv; (void)gettimeofday(&tv, 0); RubberBandStretcher::setDefaultDebugLevel(debug); @@ -446,7 +455,10 @@ int main(int argc, char **argv) cerr << "input peak: " << inpeak << "; output peak " << outpeak << "; gain " << (inpeak > 0 ? outpeak/inpeak : 1) << endl; cerr << "input rms: " << inmean << "; output rms " << outmean << "; gain " << (inmean > 0 ? outmean/inmean : 1) << endl; - struct timeval etv; +#ifdef _WIN32 + RubberBand:: +#endif + timeval etv; (void)gettimeofday(&etv, 0); etv.tv_sec -= tv.tv_sec; diff --git a/src/sysutils.cpp b/src/sysutils.cpp index 0554fe6..fc4a17b 100644 --- a/src/sysutils.cpp +++ b/src/sysutils.cpp @@ -15,6 +15,7 @@ #include "sysutils.h" #ifdef _WIN32 +#include #else /* !_WIN32 */ #ifdef __APPLE__ #include @@ -24,6 +25,8 @@ #endif /* !__APPLE__, !_WIN32 */ #endif /* !_WIN32 */ +#include + namespace RubberBand { bool @@ -36,7 +39,9 @@ system_is_multiprocessor() #ifdef _WIN32 - //... + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + count = sysinfo.dwNumberOfProcessors; #else /* !_WIN32 */ #ifdef __APPLE__ @@ -74,6 +79,27 @@ system_is_multiprocessor() return mp; } +#ifdef _WIN32 + +void gettimeofday(struct timeval *tv, void *tz) +{ + union { + long long ns100; + FILETIME ft; + } now; + + ::GetSystemTimeAsFileTime(&now.ft); + tv->tv_usec = (long)((now.ns100 / 10LL) % 1000000LL); + tv->tv_sec = (long)((now.ns100 - 116444736000000000LL) / 10000000LL); +} + +void usleep(unsigned long usec) +{ + ::Sleep(usec == 0 ? 0 : usec < 1000 ? 1 : usec / 1000); +} + +#endif + } diff --git a/src/sysutils.h b/src/sysutils.h index 0f1ce6e..b9dd23e 100644 --- a/src/sysutils.h +++ b/src/sysutils.h @@ -19,6 +19,12 @@ namespace RubberBand { extern bool system_is_multiprocessor(); +#ifdef _WIN32 +struct timeval { long tv_sec; long tv_usec; }; +void gettimeofday(struct timeval *p, void *tz); +void usleep(unsigned long); +#endif + } #endif