diff --git a/modules/juce_audio_basics/utilities/juce_GenericInterpolator.h b/modules/juce_audio_basics/utilities/juce_GenericInterpolator.h index 084927d24d..acc798b24a 100644 --- a/modules/juce_audio_basics/utilities/juce_GenericInterpolator.h +++ b/modules/juce_audio_basics/utilities/juce_GenericInterpolator.h @@ -39,6 +39,16 @@ namespace juce template class JUCE_API GenericInterpolator { + static auto processReplacingCallback() + { + return [] (auto, auto newValue) { return newValue; }; + } + + static auto processAddingCallback (float gain) + { + return [gain] (auto oldValue, auto newValue) { return oldValue + gain * newValue; }; + } + public: GenericInterpolator() noexcept { reset(); } @@ -81,7 +91,11 @@ public: float* outputSamples, int numOutputSamplesToProduce) noexcept { - return interpolate (speedRatio, inputSamples, outputSamples, numOutputSamplesToProduce); + return interpolateImpl (speedRatio, + inputSamples, + outputSamples, + numOutputSamplesToProduce, + processReplacingCallback()); } /** Resamples a stream of samples. @@ -106,8 +120,13 @@ public: int numInputSamplesAvailable, int wrapAround) noexcept { - return interpolate (speedRatio, inputSamples, outputSamples, - numOutputSamplesToProduce, numInputSamplesAvailable, wrapAround); + return interpolateImpl (speedRatio, + inputSamples, + outputSamples, + numOutputSamplesToProduce, + numInputSamplesAvailable, + wrapAround, + processReplacingCallback()); } /** Resamples a stream of samples, adding the results to the output data @@ -131,7 +150,11 @@ public: int numOutputSamplesToProduce, float gain) noexcept { - return interpolateAdding (speedRatio, inputSamples, outputSamples, numOutputSamplesToProduce, gain); + return interpolateImpl (speedRatio, + inputSamples, + outputSamples, + numOutputSamplesToProduce, + processAddingCallback (gain)); } /** Resamples a stream of samples, adding the results to the output data @@ -162,8 +185,13 @@ public: int wrapAround, float gain) noexcept { - return interpolateAdding (speedRatio, inputSamples, outputSamples, - numOutputSamplesToProduce, numInputSamplesAvailable, wrapAround, gain); + return interpolateImpl (speedRatio, + inputSamples, + outputSamples, + numOutputSamplesToProduce, + numInputSamplesAvailable, + wrapAround, + processAddingCallback (gain)); } private: @@ -255,10 +283,89 @@ private: } //============================================================================== - int interpolate (double speedRatio, - const float* input, - float* output, - int numOutputSamplesToProduce) noexcept + template + int interpolateImpl (double speedRatio, + const float* input, + float* output, + int numOutputSamplesToProduce, + int numInputSamplesAvailable, + int wrap, + Process process) + { + auto originalIn = input; + auto pos = subSamplePos; + bool exceeded = false; + + const auto pushSample = [&] + { + if (exceeded) + { + pushInterpolationSample (0.0); + } + else + { + pushInterpolationSample (*input++); + + if (--numInputSamplesAvailable <= 0) + { + if (wrap > 0) + { + input -= wrap; + numInputSamplesAvailable += wrap; + } + else + { + exceeded = true; + } + } + } + }; + + if (speedRatio < 1.0) + { + for (int i = numOutputSamplesToProduce; --i >= 0;) + { + if (pos >= 1.0) + { + pushSample(); + pos -= 1.0; + } + + *output = process (*output, InterpolatorTraits::valueAtOffset (lastInputSamples, (float) pos, indexBuffer)); + ++output; + pos += speedRatio; + } + } + else + { + for (int i = numOutputSamplesToProduce; --i >= 0;) + { + while (pos < speedRatio) + { + pushSample(); + pos += 1.0; + } + + pos -= speedRatio; + *output = process (*output, InterpolatorTraits::valueAtOffset (lastInputSamples, jmax (0.0f, 1.0f - (float) pos), indexBuffer)); + ++output; + } + } + + subSamplePos = pos; + + if (wrap == 0) + return (int) (input - originalIn); + + return ((int) (input - originalIn) + wrap) % wrap; + } + + template + int interpolateImpl (double speedRatio, + const float* input, + float* output, + int numOutputSamplesToProduce, + Process process) { auto pos = subSamplePos; int numUsed = 0; @@ -271,213 +378,8 @@ private: pos -= 1.0; } - *output++ = InterpolatorTraits::valueAtOffset (lastInputSamples, (float) pos, indexBuffer); - pos += speedRatio; - --numOutputSamplesToProduce; - } - - subSamplePos = pos; - return numUsed; - } - - int interpolate (double speedRatio, - const float* input, float* output, - int numOutputSamplesToProduce, - int numInputSamplesAvailable, - int wrap) noexcept - { - auto originalIn = input; - auto pos = subSamplePos; - bool exceeded = false; - - if (speedRatio < 1.0) - { - for (int i = numOutputSamplesToProduce; --i >= 0;) - { - if (pos >= 1.0) - { - if (exceeded) - { - pushInterpolationSample (0.0f); - } - else - { - pushInterpolationSample (*input++); - - if (--numInputSamplesAvailable <= 0) - { - if (wrap > 0) - { - input -= wrap; - numInputSamplesAvailable += wrap; - } - else - { - exceeded = true; - } - } - } - - pos -= 1.0; - } - - *output++ = InterpolatorTraits::valueAtOffset (lastInputSamples, (float) pos, indexBuffer); - pos += speedRatio; - } - } - else - { - for (int i = numOutputSamplesToProduce; --i >= 0;) - { - while (pos < speedRatio) - { - if (exceeded) - { - pushInterpolationSample (0); - } - else - { - pushInterpolationSample (*input++); - - if (--numInputSamplesAvailable <= 0) - { - if (wrap > 0) - { - input -= wrap; - numInputSamplesAvailable += wrap; - } - else - { - exceeded = true; - } - } - } - - pos += 1.0; - } - - pos -= speedRatio; - *output++ = InterpolatorTraits::valueAtOffset (lastInputSamples, jmax (0.0f, 1.0f - (float) pos), indexBuffer); - } - } - - subSamplePos = pos; - - if (wrap == 0) - return (int) (input - originalIn); - - return ((int) (input - originalIn) + wrap) % wrap; - } - - int interpolateAdding (double speedRatio, - const float* input, - float* output, - int numOutputSamplesToProduce, - int numInputSamplesAvailable, - int wrap, - float gain) noexcept - { - auto originalIn = input; - auto pos = subSamplePos; - bool exceeded = false; - - if (speedRatio < 1.0) - { - for (int i = numOutputSamplesToProduce; --i >= 0;) - { - if (pos >= 1.0) - { - if (exceeded) - { - pushInterpolationSample (0.0); - } - else - { - pushInterpolationSample (*input++); - - if (--numInputSamplesAvailable <= 0) - { - if (wrap > 0) - { - input -= wrap; - numInputSamplesAvailable += wrap; - } - else - { - numInputSamplesAvailable = true; - } - } - } - - pos -= 1.0; - } - - *output++ += gain * InterpolatorTraits::valueAtOffset (lastInputSamples, (float) pos, indexBuffer); - pos += speedRatio; - } - } - else - { - for (int i = numOutputSamplesToProduce; --i >= 0;) - { - while (pos < speedRatio) - { - if (exceeded) - { - pushInterpolationSample (0.0); - } - else - { - pushInterpolationSample (*input++); - - if (--numInputSamplesAvailable <= 0) - { - if (wrap > 0) - { - input -= wrap; - numInputSamplesAvailable += wrap; - } - else - { - exceeded = true; - } - } - } - - pos += 1.0; - } - - pos -= speedRatio; - *output++ += gain * InterpolatorTraits::valueAtOffset (lastInputSamples, jmax (0.0f, 1.0f - (float) pos), indexBuffer); - } - } - - subSamplePos = pos; - - if (wrap == 0) - return (int) (input - originalIn); - - return ((int) (input - originalIn) + wrap) % wrap; - } - - int interpolateAdding (double speedRatio, - const float* input, - float* output, - int numOutputSamplesToProduce, - float gain) noexcept - { - auto pos = subSamplePos; - int numUsed = 0; - - while (numOutputSamplesToProduce > 0) - { - while (pos >= 1.0) - { - pushInterpolationSample (input[numUsed++]); - pos -= 1.0; - } - - *output++ += gain * InterpolatorTraits::valueAtOffset (lastInputSamples, (float) pos, indexBuffer); + *output = process (*output, InterpolatorTraits::valueAtOffset (lastInputSamples, (float) pos, indexBuffer)); + ++output; pos += speedRatio; --numOutputSamplesToProduce; }