diff --git a/rubberband/RubberBandStretcher.h b/rubberband/RubberBandStretcher.h index 062f2d1..b3bb6b8 100644 --- a/rubberband/RubberBandStretcher.h +++ b/rubberband/RubberBandStretcher.h @@ -26,6 +26,125 @@ class RubberBandStretcher : public TimeStretcher { public: + /** + * Processing options for the timestretcher. The preferred + * options should normally be set in the constructor, as a bitwise + * OR of the option flags. The default value (DefaultOptions) is + * intended to give good results in most situations. + * + * 1. Flags prefixed OptionProcess determine how the timestretcher + * will be invoked. These options may not be changed after + * construction. + * + * OptionProcessOffline - Run the stretcher in offline mode. In + * this mode the input data needs to be provided twice, once to + * study(), which calculates a stretch profile for the audio, + * and once to process(), which stretches it. + * + * OptionProcessRealTime - Run the stretcher in real-time mode. + * In this mode only process() should be called, and the + * stretcher adjusts dynamically in response to the input audio. + * + * The Process setting is likely to depend on your architecture: + * non-real-time operation on seekable files: Offline; real-time + * or streaming operation: RealTime. + * + * 2. Flags prefixed OptionStretch control the profile used for + * variable timestretching. Rubber Band always adjusts the + * stretch profile to minimise stretching of busy broadband + * transient sounds, but the degree to which it does so is + * adjustable. These options may not be changed after + * construction. + * + * OptionStretchElastic - Only meaningful in offline mode, and + * the default in that mode. The audio will be stretched at a + * variable rate, aimed at preserving the quality of transient + * sounds as much as possible. The timings of low activity + * regions between transients may be less exact than when the + * precise flag is set. + * + * OptionStretchPrecise - Although still using a variable + * stretch rate, the audio will be stretched so as to maintain + * as close as possible to a linear stretch ratio throughout. + * Timing may be better than when using OptionStretchElastic, at + * slight cost to the sound quality of transients. This setting + * is always used when running in real-time mode. + * + * 3. Flags prefixed OptionTransients control the component + * frequency phase-reset mechanism that may be used at transient + * points to provide clarity and realism to percussion and other + * significant transient sounds. These options may be changed + * after construction when running in real-time mode, but not when + * running in offline mode. + * + * OptionTransientsCrisp - Reset component phases at the peak of + * each transient (the start of a significant note or percussive + * event). This, the default setting, usually results in a + * clear-sounding output; but it is not always consistent, and + * may cause interruptions in stable sounds present at the same + * time as transient events. + * + * OptionTransientsMixed - Reset component phases at the peak of + * each transient, outside a frequency range typical of musical + * fundamental frequencies. The results may be more regular for + * mixed stable and percussive notes than OptionTransientsCrisp, + * but with a "phasier" sound. The balance may sound very good + * for certain types of music and fairly bad for others. + * + * OptionTransientsSmooth - Do not reset component phases at any + * point. The results will be smoother and more regular but may + * be less clear than with either of the other transients flags. + * + * 4. Flags prefixed OptionPhase control the adjustment of + * component frequency phases from one analysis window to the next + * during non-transient segments. These options may be changed at + * any time. + * + * OptionPhaseAdaptive - Lock the adjustments of phase for + * frequencies close to peak frequencies to those of the peak, + * but reduce the degree of locking as the stretch ratio gets + * longer. This, the default setting, should give a good + * balance between clarity and smoothness in most situations. + * + * OptionPhasePeakLocked - Lock the adjustments of phase for + * frequencies close to peak frequencies to those of the peak. + * This should give a clear result in situations with relatively + * low stretch ratios, but a relatively metallic sound at longer + * stretches. + * + * OptionPhaseIndependent - Do not lock phase adjustments to + * peak frequencies. This usually results in a softer, phasier + * sound. + * + * 5. Options prefixed OptionThreading control the threading model + * of the stretcher. These options may not be changed after + * construction. + * + * OptionThreadingAuto - Permit the stretcher to determine its + * own threading model. Usually this means using one processing + * thread per audio channel in offline mode, and one thread only + * in realtime mode. + * + * OptionThreadingNone - Never use more than one thread. + * + * 6. Options prefixed OptionWindow control the window size for + * FFT processing. The window size actually used will depend on + * many factors, but it can be influenced. These options may not + * be changed after construction. + * + * OptionWindowStandard - Use the default window size. The + * actual size will vary depending on other parameters. This + * option is expected to produce better results than the other + * window options in most situations. + * + * OptionWindowShort - Use a shorter window. This may result in + * crisper sound for audio that depends strongly on its timing + * qualities. + * + * OptionWindowLong - Use a longer window. This is likely to + * result in a smoother sound at the expense of clarity and + * timing. + */ typedef int Options; static const int OptionProcessOffline = 0x00000000; @@ -53,6 +172,14 @@ public: static const int PercussiveOptions = OptionWindowShort | \ OptionPhaseIndependent; + /** + * Construct a time-and-pitch-scaling object to run at the given + * sample rate, with the given number of channels. Processing + * options and the time and pitch scaling ratios may be provided. + * The time and pitch ratios may be changed after construction, + * but most of the options may not. See the option documentation + * above for more details. + */ RubberBandStretcher(size_t sampleRate, size_t channels, Options options = DefaultOptions, @@ -62,7 +189,7 @@ public: virtual void reset(); virtual void setTimeRatio(double ratio); - virtual void setPitchScale(double scale); //!!!??? pitch ratio? + virtual void setPitchScale(double scale); virtual double getTimeRatio() const; virtual double getPitchScale() const; diff --git a/src/vamp/RubberBandVampPlugin.cpp b/src/vamp/RubberBandVampPlugin.cpp index b762a56..41d7a9b 100644 --- a/src/vamp/RubberBandVampPlugin.cpp +++ b/src/vamp/RubberBandVampPlugin.cpp @@ -53,6 +53,8 @@ public: size_t m_counter; size_t m_accumulatedIncrement; + float **m_outputDump; + FeatureSet processOffline(const float *const *inputBuffers, Vamp::RealTime timestamp); @@ -92,6 +94,12 @@ RubberBandVampPlugin::RubberBandVampPlugin(float inputSampleRate) : RubberBandVampPlugin::~RubberBandVampPlugin() { + if (m_d->m_outputDump) { + for (size_t i = 0; i < m_d->m_stretcher->getChannelCount(); ++i) { + delete[] m_d->m_outputDump[i]; + } + delete[] m_d->m_outputDump; + } delete m_d->m_stretcher; delete m_d; } @@ -403,13 +411,15 @@ RubberBandVampPlugin::initialise(size_t channels, size_t stepSize, size_t blockS delete m_d->m_stretcher; m_d->m_stretcher = new RubberBand::RubberBandStretcher (m_d->m_sampleRate, channels, options); - m_d->m_stretcher->setDebugLevel(2); + m_d->m_stretcher->setDebugLevel(1); m_d->m_stretcher->setTimeRatio(m_d->m_timeRatio); m_d->m_stretcher->setPitchScale(m_d->m_pitchRatio); m_d->m_counter = 0; m_d->m_accumulatedIncrement = 0; + m_d->m_outputDump = 0; + return true; } @@ -510,6 +520,18 @@ RubberBandVampPlugin::Impl::processRealTime(const float *const *inputBuffers, m_counter, false); m_counter += outputIncrements.size(); + int available = 0; + while ((available = m_stretcher->available()) > 0) { + if (!m_outputDump) { + m_outputDump = new float *[m_stretcher->getChannelCount()]; + for (size_t i = 0; i < m_stretcher->getChannelCount(); ++i) { + m_outputDump[i] = new float[m_blockSize]; + } + } + m_stretcher->retrieve(m_outputDump, + std::min(int(m_blockSize), available)); + } + return features; }