# HG changeset patch # User Chris Cannam # Date 1158327337 0 # Node ID 80126455d169d538282bb588fbfed2f2ff507dae # Parent 7da85e0b85e98c2c5c5bc7677712797ad273c91f * add samplerate parameter to timestretcher (not properly used yet), and update credits diff -r 7da85e0b85e9 -r 80126455d169 audioio/AudioCallbackPlaySource.cpp --- a/audioio/AudioCallbackPlaySource.cpp Thu Sep 14 16:08:23 2006 +0000 +++ b/audioio/AudioCallbackPlaySource.cpp Fri Sep 15 13:35:37 2006 +0000 @@ -603,7 +603,8 @@ if (factor != 1) { PhaseVocoderTimeStretcher *newStretcher = new PhaseVocoderTimeStretcher - (getTargetChannelCount(), + (getTargetSampleRate(), + getTargetChannelCount(), factor, sharpen, lrintf(getTargetBlockSize() / factor)); @@ -712,52 +713,6 @@ ts->getOutput(buffer, count); - -/*!!! - for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) { - - RingBuffer *rb = getReadRingBuffer(ch); - - if (rb) { - - float ratio = ts->getRatio(); - -// std::cout << "ratio = " << ratio << std::endl; - - size_t available; - - while ((available = ts->getAvailableOutputSamples()) < count) { - - size_t reqd = lrintf((count - available) / ratio); - reqd = std::max(reqd, ts->getRequiredInputSamples()); - if (reqd == 0) reqd = 1; - - float ib[reqd]; - size_t got = rb->read(ib, reqd); - -#ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING - std::cout << "AudioCallbackPlaySource::getSamples: got " << got << " samples on channel " << ch << " (reqd=" << reqd << ", count=" << count << ", ratio=" << ratio << ", got*ratio=" << got * ratio << "), running time stretcher" << std::endl; -#endif - - if (got < reqd) { - std::cerr << "WARNING: Read underrun in playback (" - << got << " < " << reqd << ")" << std::endl; - } - - ts->putInput(ib, got); - - if (got == 0) break; - - if (ts->getAvailableOutputSamples() == available) { - std::cerr << "WARNING: AudioCallbackPlaySource::getSamples: Added " << got << " samples to time stretcher, created no new available output samples" << std::endl; - break; - } - } - - ts->getOutput(buffer[ch], count); - } - } -*/ m_condition.wakeAll(); return count; diff -r 7da85e0b85e9 -r 80126455d169 audioio/PhaseVocoderTimeStretcher.cpp --- a/audioio/PhaseVocoderTimeStretcher.cpp Thu Sep 14 16:08:23 2006 +0000 +++ b/audioio/PhaseVocoderTimeStretcher.cpp Fri Sep 15 13:35:37 2006 +0000 @@ -20,10 +20,12 @@ //#define DEBUG_PHASE_VOCODER_TIME_STRETCHER 1 -PhaseVocoderTimeStretcher::PhaseVocoderTimeStretcher(size_t channels, +PhaseVocoderTimeStretcher::PhaseVocoderTimeStretcher(size_t sampleRate, + size_t channels, float ratio, bool sharpen, size_t maxProcessInputBlockSize) : + m_sampleRate(sampleRate), m_channels(channels), m_ratio(ratio), m_sharpen(sharpen), @@ -35,7 +37,10 @@ //!!! In transient sharpening mode, we need to pick the window //length so as to be more or less fixed in audio duration (i.e. we - //need to know the sample rate) + //need to exploit the sample rate) + + //!!! have to work out the relationship between wlen and transient + //threshold if (ratio < 1) { if (ratio < 0.4) { @@ -65,6 +70,8 @@ } m_n1 = m_n2 / ratio; } + + m_transientThreshold = m_wlen / 4.5; m_analysisWindow = new Window(HanningWindow, m_wlen); m_synthesisWindow = new Window(HanningWindow, m_wlen); @@ -417,7 +424,7 @@ bool isTransient = false; - if (count > m_wlen / 4.5 && //!!! + if (count > m_transientThreshold && count > m_prevTransientScore * 1.2) { isTransient = true; std::cerr << "isTransient (count = " << count << ", prev = " << m_prevTransientScore << ")" << std::endl; diff -r 7da85e0b85e9 -r 80126455d169 audioio/PhaseVocoderTimeStretcher.h --- a/audioio/PhaseVocoderTimeStretcher.h Thu Sep 14 16:08:23 2006 +0000 +++ b/audioio/PhaseVocoderTimeStretcher.h Fri Sep 15 13:35:37 2006 +0000 @@ -23,17 +23,22 @@ /** * A time stretcher that alters the performance speed of audio, - * preserving pitch. This uses the simple phase vocoder technique - * from DAFX pp275-276, adding a block-based stream oriented API. + * preserving pitch. * - * Causes significant transient smearing, but sounds good for steady - * notes and is generally predictable. + * This is based on the straightforward phase vocoder with phase + * unwrapping (as in e.g. the DAFX book pp275-), with optional + * percussive transient detection to avoid smearing percussive notes + * and resynchronise phases, and adding a stream API for real-time + * use. Principles and methods from Chris Duxbury, AES 2002 and 2004 + * thesis; Emmanuel Ravelli, DAFX 2005; Dan Barry, ISSC 2005 on + * percussion detection; code by Chris Cannam. */ class PhaseVocoderTimeStretcher { public: - PhaseVocoderTimeStretcher(size_t channels, + PhaseVocoderTimeStretcher(size_t sampleRate, + size_t channels, float ratio, bool sharpen, size_t maxProcessInputBlockSize); @@ -131,6 +136,7 @@ void synthesiseBlock(size_t channel, float *out, float *modulation, size_t lastStep); + size_t m_sampleRate; size_t m_channels; float m_ratio; bool m_sharpen; @@ -149,6 +155,7 @@ float *m_prevTransientMag; int m_prevTransientScore; + int m_transientThreshold; bool m_prevTransient; float *m_tempbuf;