1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

GenericInterpolator: Refactor to avoid repetition

Also fixes an issue in which `numInputSamplesAvailable` was assigned
instead of `exceeded`, Github issue #1114.

Co-authored-by: Tatsuya Shiozawa <shio.tatsu99@gmail.com>
This commit is contained in:
reuk 2022-08-30 14:03:49 +01:00
parent 34341bc597
commit d28815601a
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C

View file

@ -39,6 +39,16 @@ 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(); }
@ -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 <typename Process>
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 <typename Process>
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;
}