# HG changeset patch # User Chris Cannam # Date 1196084024 0 # Node ID ae2627ac7db2c87ad0e1c9a56fd6ef71d7462644 # Parent 215b8b1b0308e6da085977abc32f2bcb1d0c92d9 * Add support for Rubber Band timestretcher diff -r 215b8b1b0308 -r ae2627ac7db2 audioio/AudioCallbackPlaySource.cpp --- a/audioio/AudioCallbackPlaySource.cpp Fri Nov 23 16:48:23 2007 +0000 +++ b/audioio/AudioCallbackPlaySource.cpp Mon Nov 26 13:33:44 2007 +0000 @@ -25,7 +25,13 @@ #include "data/model/WaveFileModel.h" #include "data/model/SparseOneDimensionalModel.h" #include "plugin/RealTimePluginInstance.h" + +#ifdef HAVE_RUBBERBAND +#include +using namespace RubberBand; +#else #include "PhaseVocoderTimeStretcher.h" +#endif #include #include @@ -103,7 +109,9 @@ m_bufferScavenger.scavenge(true); m_pluginScavenger.scavenge(true); +#ifndef HAVE_RUBBERBAND m_timeStretcherScavenger.scavenge(true); +#endif } void @@ -497,10 +505,16 @@ size_t latency = m_playLatency; if (resample) latency = size_t(m_playLatency * ratio + 0.1); +#ifdef HAVE_RUBBERBAND + if (m_timeStretcher) { + latency += m_timeStretcher->getLatency(); + } +#else PhaseVocoderTimeStretcher *timeStretcher = m_timeStretcher; if (timeStretcher) { latency += timeStretcher->getProcessingLatency(); } +#endif latency += readSpace; size_t bufferedFrame = m_readBufferFill; @@ -746,6 +760,22 @@ void AudioCallbackPlaySource::setTimeStretch(float factor, bool sharpen, bool mono) { +#ifdef HAVE_RUBBERBAND + if (m_timeStretcher) { + m_timeStretchRatioMutex.lock(); + m_timeStretcher->setTimeRatio(factor); + m_timeStretchRatioMutex.unlock(); + return; + } else { + RubberBandStretcher *stretcher = new RubberBandStretcher + (getTargetSampleRate(), + getTargetChannelCount(), + RubberBandStretcher::OptionProcessRealTime, + factor); + m_timeStretcher = stretcher; + return; + } +#else // Avoid locks -- create, assign, mark old one for scavenging // later (as a call to getSourceSamples may still be using it) @@ -786,6 +816,7 @@ if (existingStretcher) { m_timeStretcherScavenger.claim(existingStretcher); } +#endif } size_t @@ -829,9 +860,15 @@ if (count == 0) return 0; +#ifdef HAVE_RUBBERBAND + RubberBandStretcher *ts = m_timeStretcher; + float ratio = ts ? ts->getTimeRatio() : 1.f; +#else PhaseVocoderTimeStretcher *ts = m_timeStretcher; + float ratio = ts ? ts->getRatio() : 1.f; +#endif - if (!ts || ts->getRatio() == 1) { + if (!ts || ratio == 1.f) { size_t got = 0; @@ -866,12 +903,13 @@ return got; } - float ratio = ts->getRatio(); + size_t channels = getTargetChannelCount(); -// std::cout << "ratio = " << ratio << std::endl; - - size_t channels = getTargetChannelCount(); +#ifdef HAVE_RUBBERBAND + bool mix = false; +#else bool mix = (channels > 1 && ts->getChannelCount() == 1); +#endif size_t available; @@ -885,10 +923,19 @@ // need some additional buffer space. See the time stretcher code // and comments. +#ifdef HAVE_RUBBERBAND + m_timeStretchRatioMutex.lock(); + while ((available = ts->available()) < count) { +#else while ((available = ts->getAvailableOutputSamples()) < count) { +#endif size_t reqd = lrintf((count - available) / ratio); +#ifdef HAVE_RUBBERBAND + reqd = std::max(reqd, ts->getSamplesRequired()); +#else reqd = std::max(reqd, ts->getRequiredInputSamples()); +#endif if (reqd == 0) reqd = 1; float *ib[channels]; @@ -923,7 +970,11 @@ << got << " < " << reqd << ")" << std::endl; } +#ifdef HAVE_RUBBERBAND + ts->process(ib, got, false); +#else ts->putInput(ib, got); +#endif for (size_t c = 0; c < channels; ++c) { delete[] ib[c]; @@ -931,13 +982,22 @@ if (got == 0) break; +#ifdef HAVE_RUBBERBAND + if (ts->available() == available) { +#else if (ts->getAvailableOutputSamples() == available) { +#endif std::cerr << "WARNING: AudioCallbackPlaySource::getSamples: Added " << got << " samples to time stretcher, created no new available output samples (warned = " << warned << ")" << std::endl; if (++warned == 5) break; } } +#ifdef HAVE_RUBBERBAND + ts->retrieve(buffer, count); + m_timeStretchRatioMutex.unlock(); +#else ts->getOutput(buffer, count); +#endif if (mix) { for (size_t c = 1; c < channels; ++c) { @@ -1124,7 +1184,11 @@ int err = 0; +#ifdef HAVE_RUBBERBAND + if (m_timeStretcher && m_timeStretcher->getTimeRatio() < 0.4) { +#else if (m_timeStretcher && m_timeStretcher->getRatio() < 0.4) { +#endif #ifdef DEBUG_AUDIO_PLAY_SOURCE std::cout << "Using crappy converter" << std::endl; #endif @@ -1449,7 +1513,9 @@ s.unifyRingBuffers(); s.m_bufferScavenger.scavenge(); s.m_pluginScavenger.scavenge(); +#ifndef HAVE_RUBBERBAND s.m_timeStretcherScavenger.scavenge(); +#endif if (work && s.m_playing && s.getSourceSampleRate()) { diff -r 215b8b1b0308 -r ae2627ac7db2 audioio/AudioCallbackPlaySource.h --- a/audioio/AudioCallbackPlaySource.h Fri Nov 23 16:48:23 2007 +0000 +++ b/audioio/AudioCallbackPlaySource.h Mon Nov 26 13:33:44 2007 +0000 @@ -32,11 +32,16 @@ #include #include +#ifdef HAVE_RUBBERBAND +#include +#else +class PhaseVocoderTimeStretcher; +#endif + class Model; class ViewManager; class AudioGenerator; class PlayParameters; -class PhaseVocoderTimeStretcher; class RealTimePluginInstance; /** @@ -304,8 +309,13 @@ void clearRingBuffers(bool haveLock = false, size_t count = 0); void unifyRingBuffers(); +#ifdef HAVE_RUBBERBAND + RubberBand::RubberBandStretcher *m_timeStretcher; + QMutex m_timeStretchRatioMutex; +#else PhaseVocoderTimeStretcher *m_timeStretcher; Scavenger m_timeStretcherScavenger; +#endif // Called from fill thread, m_playing true, mutex held // Return true if work done