diff --git a/src/engine/bufferscalers/enginebufferscalerubberband.cpp b/src/engine/bufferscalers/enginebufferscalerubberband.cpp index 6f2e60d74fe0..fe9dc65abf8b 100644 --- a/src/engine/bufferscalers/enginebufferscalerubberband.cpp +++ b/src/engine/bufferscalers/enginebufferscalerubberband.cpp @@ -17,9 +17,13 @@ using RubberBand::RubberBandStretcher; namespace { +// TODO (XXX): this should be removed. It is only needed to work around +// a Rubberband 1.3 bug. // This is the default increment from RubberBand 1.8.1. size_t kRubberBandBlockSize = 256; +#define RUBBERBANDV3 (RUBBERBAND_API_MAJOR_VERSION >= 2 && RUBBERBAND_API_MINOR_VERSION >= 7) + } // namespace EngineBufferScaleRubberBand::EngineBufferScaleRubberBand( @@ -61,6 +65,14 @@ void EngineBufferScaleRubberBand::setScaleParameters(double base_rate, speed_abs = *pTempoRatio = 0; } + double speed_abs = fabs(*pTempoRatio); + if (runningEngineVersion() == 2) { + constexpr double kMinSeekSpeed = 1.0 / 128.0; + if (speed_abs < kMinSeekSpeed) { + // Let the caller know we ignored their speed. + speed_abs = *pTempoRatio = 0; + } + } // RubberBand handles checking for whether the change in pitchScale is a // no-op. double pitchScale = fabs(base_rate * *pPitchRatio); @@ -80,21 +92,22 @@ void EngineBufferScaleRubberBand::setScaleParameters(double base_rate, m_pRubberBand->setTimeRatio(1.0 / timeRatioInverse); } - if (m_pRubberBand->getInputIncrement() == 0) { - qWarning() << "EngineBufferScaleRubberBand inputIncrement is 0." - << "On RubberBand <=1.8.1 a SIGFPE is imminent despite" - << "our workaround. Taking evasive action." - << "Please report this message to mixxx-devel@lists.sourceforge.net."; - - // This is much slower than the minimum seek speed workaround above. - while (m_pRubberBand->getInputIncrement() == 0) { - timeRatioInverse += 0.001; - m_pRubberBand->setTimeRatio(1.0 / timeRatioInverse); + if (runningEngineVersion() == 2) { + if (m_pRubberBand->getInputIncrement() == 0) { + qWarning() << "EngineBufferScaleRubberBand inputIncrement is 0." + << "On RubberBand <=1.8.1 a SIGFPE is imminent despite" + << "our workaround. Taking evasive action." + << "Please file an issue on https://github.com/mixxxdj/mixxx/issues"; + + // This is much slower than the minimum seek speed workaround above. + while (m_pRubberBand->getInputIncrement() == 0) { + timeRatioInverse += 0.001; + m_pRubberBand->setTimeRatio(1.0 / timeRatioInverse); + } + speed_abs = timeRatioInverse / base_rate; + *pTempoRatio = m_bBackwards ? -speed_abs : speed_abs; } - speed_abs = timeRatioInverse / base_rate; - *pTempoRatio = m_bBackwards ? -speed_abs : speed_abs; } - // Used by other methods so we need to keep them up to date. m_dBaseRate = base_rate; m_dTempoRatio = speed_abs; @@ -109,10 +122,18 @@ void EngineBufferScaleRubberBand::onSampleRateChanged() { m_pRubberBand.reset(); return; } + RubberBandStretcher::Options rubberbandOptions = RubberBandStretcher::OptionProcessRealTime; +#if RUBBERBANDV3 + // TODO make this a runtime option + rubberbandOptions |= RubberBandStretcher::OptionEngineFiner; +#endif + m_pRubberBand = std::make_unique( getOutputSignal().getSampleRate(), getOutputSignal().getChannelCount(), - RubberBandStretcher::OptionProcessRealTime); + rubberbandOptions); + // TODO (XXX): we should always be able to provide rubberband as + // many samples as it wants. So remove this. m_pRubberBand->setMaxProcessSize(kRubberBandBlockSize); // Setting the time ratio to a very high value will cause RubberBand // to preallocate buffers large enough to (almost certainly) @@ -190,6 +211,9 @@ double EngineBufferScaleRubberBand::scaleBuffer( size_t iLenFramesRequired = m_pRubberBand->getSamplesRequired(); if (iLenFramesRequired == 0) { + // TODO (XXX): Rubberband 1.3 is not being packaged anymore. + // Remove this workaround. + // // rubberband 1.3 (packaged up through Ubuntu Quantal) has a bug // where it can report 0 samples needed forever which leads us to an // infinite loop. To work around this, we check if available() is @@ -245,3 +269,11 @@ double EngineBufferScaleRubberBand::scaleBuffer( return framesRead; } + +int EngineBufferScaleRubberBand::runningEngineVersion() { +#if RUBBERBANDV3 + return m_pRubberBand->getEngineVersion(); +#else + return 2; +#endif +} diff --git a/src/engine/bufferscalers/enginebufferscalerubberband.h b/src/engine/bufferscalers/enginebufferscalerubberband.h index dbbd3064e93b..a4e6017e539d 100644 --- a/src/engine/bufferscalers/enginebufferscalerubberband.h +++ b/src/engine/bufferscalers/enginebufferscalerubberband.h @@ -32,6 +32,8 @@ class EngineBufferScaleRubberBand : public EngineBufferScale { // Reset RubberBand library with new audio signal void onSampleRateChanged() override; + int runningEngineVersion(); + void deinterleaveAndProcess(const CSAMPLE* pBuffer, SINT frames, bool flush); SINT retrieveAndDeinterleave(CSAMPLE* pBuffer, SINT frames);