Loading...
Searching...
No Matches
juce_GenericInterpolator.h
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
template <class InterpolatorTraits, int memorySize>
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(); }
GenericInterpolator (GenericInterpolator&&) noexcept = default;
GenericInterpolator& operator= (GenericInterpolator&&) noexcept = default;
static constexpr float getBaseLatency() noexcept
{
return InterpolatorTraits::algorithmicLatency;
}
void reset() noexcept
{
indexBuffer = 0;
subSamplePos = 1.0;
std::fill (std::begin (lastInputSamples), std::end (lastInputSamples), 0.0f);
}
int process (double speedRatio,
const float* inputSamples,
float* outputSamples,
int numOutputSamplesToProduce) noexcept
{
return interpolateImpl (speedRatio,
inputSamples,
outputSamples,
numOutputSamplesToProduce,
processReplacingCallback());
}
int process (double speedRatio,
const float* inputSamples,
float* outputSamples,
int numOutputSamplesToProduce,
int numInputSamplesAvailable,
int wrapAround) noexcept
{
return interpolateImpl (speedRatio,
inputSamples,
outputSamples,
numOutputSamplesToProduce,
numInputSamplesAvailable,
wrapAround,
processReplacingCallback());
}
int processAdding (double speedRatio,
const float* inputSamples,
float* outputSamples,
int numOutputSamplesToProduce,
float gain) noexcept
{
return interpolateImpl (speedRatio,
inputSamples,
outputSamples,
numOutputSamplesToProduce,
processAddingCallback (gain));
}
int processAdding (double speedRatio,
const float* inputSamples,
float* outputSamples,
int numOutputSamplesToProduce,
int numInputSamplesAvailable,
int wrapAround,
float gain) noexcept
{
return interpolateImpl (speedRatio,
inputSamples,
outputSamples,
numOutputSamplesToProduce,
numInputSamplesAvailable,
wrapAround,
processAddingCallback (gain));
}
private:
//==============================================================================
forcedinline void pushInterpolationSample (float newValue) noexcept
{
lastInputSamples[indexBuffer] = newValue;
if (++indexBuffer == memorySize)
indexBuffer = 0;
}
forcedinline void pushInterpolationSamples (const float* input,
int numOutputSamplesToProduce) noexcept
{
if (numOutputSamplesToProduce >= memorySize)
{
const auto* const offsetInput = input + (numOutputSamplesToProduce - memorySize);
for (int i = 0; i < memorySize; ++i)
pushInterpolationSample (offsetInput[i]);
}
else
{
for (int i = 0; i < numOutputSamplesToProduce; ++i)
pushInterpolationSample (input[i]);
}
}
forcedinline void pushInterpolationSamples (const float* input,
int numOutputSamplesToProduce,
int numInputSamplesAvailable,
int wrapAround) noexcept
{
if (numOutputSamplesToProduce >= memorySize)
{
if (numInputSamplesAvailable >= memorySize)
{
pushInterpolationSamples (input,
numOutputSamplesToProduce);
}
else
{
pushInterpolationSamples (input + ((numOutputSamplesToProduce - numInputSamplesAvailable) - 1),
numInputSamplesAvailable);
if (wrapAround > 0)
{
numOutputSamplesToProduce -= wrapAround;
pushInterpolationSamples (input + ((numOutputSamplesToProduce - (memorySize - numInputSamplesAvailable)) - 1),
memorySize - numInputSamplesAvailable);
}
else
{
for (int i = numInputSamplesAvailable; i < memorySize; ++i)
pushInterpolationSample (0.0f);
}
}
}
else
{
if (numOutputSamplesToProduce > numInputSamplesAvailable)
{
for (int i = 0; i < numInputSamplesAvailable; ++i)
pushInterpolationSample (input[i]);
const auto extraSamples = numOutputSamplesToProduce - numInputSamplesAvailable;
if (wrapAround > 0)
{
const auto* const offsetInput = input + (numInputSamplesAvailable - wrapAround);
for (int i = 0; i < extraSamples; ++i)
pushInterpolationSample (offsetInput[i]);
}
else
{
for (int i = 0; i < extraSamples; ++i)
pushInterpolationSample (0.0f);
}
}
else
{
for (int i = 0; i < numOutputSamplesToProduce; ++i)
pushInterpolationSample (input[i]);
}
}
}
//==============================================================================
template <typename Process>
int interpolateImpl (double speedRatio,
const float* input,
float* output,
int numOutputSamplesToProduce,
int numInputSamplesAvailable,
int wrap,
Process process)
{
auto originalIn = input;
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;
}
}
}
};
interpolateImpl (speedRatio,
output,
numOutputSamplesToProduce,
process,
pushSample);
if (wrap == 0)
return (int) (input - originalIn);
return ((int) (input - originalIn) + wrap) % wrap;
}
template <typename Process>
int interpolateImpl (double speedRatio,
const float* input,
float* output,
int numOutputSamplesToProduce,
Process process)
{
int numUsed = 0;
interpolateImpl (speedRatio,
output,
numOutputSamplesToProduce,
process,
[this, input, &numUsed] { pushInterpolationSample (input[numUsed++]); });
return numUsed;
}
template <typename Process, typename PushSample>
void interpolateImpl (double speedRatio,
float* output,
int numOutputSamplesToProduce,
Process process,
PushSample pushSample)
{
auto pos = subSamplePos;
for (auto i = 0; i < numOutputSamplesToProduce; ++i)
{
while (pos >= 1.0)
{
pushSample();
pos -= 1.0;
}
*output = process (*output, InterpolatorTraits::valueAtOffset (lastInputSamples, (float) pos, indexBuffer));
++output;
pos += speedRatio;
}
subSamplePos = pos;
}
//==============================================================================
float lastInputSamples[(size_t) memorySize];
double subSamplePos = 1.0;
int indexBuffer = 0;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GenericInterpolator)
};
} // namespace juce
juce::GenericInterpolator::process
int process(double speedRatio, const float *inputSamples, float *outputSamples, int numOutputSamplesToProduce, int numInputSamplesAvailable, int wrapAround) noexcept
Definition juce_GenericInterpolator.h:116
juce::GenericInterpolator::process
int process(double speedRatio, const float *inputSamples, float *outputSamples, int numOutputSamplesToProduce) noexcept
Definition juce_GenericInterpolator.h:89
juce::GenericInterpolator::processAdding
int processAdding(double speedRatio, const float *inputSamples, float *outputSamples, int numOutputSamplesToProduce, int numInputSamplesAvailable, int wrapAround, float gain) noexcept
Definition juce_GenericInterpolator.h:180
juce::GenericInterpolator::reset
void reset() noexcept
Definition juce_GenericInterpolator.h:72
juce::GenericInterpolator::processAdding
int processAdding(double speedRatio, const float *inputSamples, float *outputSamples, int numOutputSamplesToProduce, float gain) noexcept
Definition juce_GenericInterpolator.h:147
juce::GenericInterpolator::getBaseLatency
static constexpr float getBaseLatency() noexcept
Definition juce_GenericInterpolator.h:63