Loading...
Searching...
No Matches
juce_DelayLine.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.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
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::dsp
{
//==============================================================================
namespace DelayLineInterpolationTypes
{
struct None {};
struct Linear {};
struct Lagrange3rd {};
struct Thiran {};
}
//==============================================================================
template <typename SampleType, typename InterpolationType = DelayLineInterpolationTypes::Linear>
class DelayLine
{
public:
//==============================================================================
DelayLine();
explicit DelayLine (int maximumDelayInSamples);
//==============================================================================
void setDelay (SampleType newDelayInSamples);
SampleType getDelay() const;
//==============================================================================
void prepare (const ProcessSpec& spec);
void setMaximumDelayInSamples (int maxDelayInSamples);
int getMaximumDelayInSamples() const noexcept { return totalSize - 2; }
void reset();
//==============================================================================
void pushSample (int channel, SampleType sample);
SampleType popSample (int channel, SampleType delayInSamples = -1, bool updateReadPointer = true);
//==============================================================================
template <typename ProcessContext>
void process (const ProcessContext& context) noexcept
{
const auto& inputBlock = context.getInputBlock();
auto& outputBlock = context.getOutputBlock();
const auto numChannels = outputBlock.getNumChannels();
const auto numSamples = outputBlock.getNumSamples();
jassert (inputBlock.getNumChannels() == numChannels);
jassert (inputBlock.getNumChannels() == writePos.size());
jassert (inputBlock.getNumSamples() == numSamples);
if (context.isBypassed)
{
outputBlock.copyFrom (inputBlock);
return;
}
for (size_t channel = 0; channel < numChannels; ++channel)
{
auto* inputSamples = inputBlock.getChannelPointer (channel);
auto* outputSamples = outputBlock.getChannelPointer (channel);
for (size_t i = 0; i < numSamples; ++i)
{
pushSample ((int) channel, inputSamples[i]);
outputSamples[i] = popSample ((int) channel);
}
}
}
private:
//==============================================================================
SampleType interpolateSample (int channel)
{
if constexpr (std::is_same_v<InterpolationType, DelayLineInterpolationTypes::None>)
{
auto index = (readPos[(size_t) channel] + delayInt) % totalSize;
return bufferData.getSample (channel, index);
}
else if constexpr (std::is_same_v<InterpolationType, DelayLineInterpolationTypes::Linear>)
{
auto index1 = readPos[(size_t) channel] + delayInt;
auto index2 = index1 + 1;
if (index2 >= totalSize)
{
index1 %= totalSize;
index2 %= totalSize;
}
auto value1 = bufferData.getSample (channel, index1);
auto value2 = bufferData.getSample (channel, index2);
return value1 + delayFrac * (value2 - value1);
}
else if constexpr (std::is_same_v<InterpolationType, DelayLineInterpolationTypes::Lagrange3rd>)
{
auto index1 = readPos[(size_t) channel] + delayInt;
auto index2 = index1 + 1;
auto index3 = index2 + 1;
auto index4 = index3 + 1;
if (index4 >= totalSize)
{
index1 %= totalSize;
index2 %= totalSize;
index3 %= totalSize;
index4 %= totalSize;
}
auto* samples = bufferData.getReadPointer (channel);
auto value1 = samples[index1];
auto value2 = samples[index2];
auto value3 = samples[index3];
auto value4 = samples[index4];
auto d1 = delayFrac - 1.f;
auto d2 = delayFrac - 2.f;
auto d3 = delayFrac - 3.f;
auto c1 = -d1 * d2 * d3 / 6.f;
auto c2 = d2 * d3 * 0.5f;
auto c3 = -d1 * d3 * 0.5f;
auto c4 = d1 * d2 / 6.f;
return value1 * c1 + delayFrac * (value2 * c2 + value3 * c3 + value4 * c4);
}
else if constexpr (std::is_same_v<InterpolationType, DelayLineInterpolationTypes::Thiran>)
{
auto index1 = readPos[(size_t) channel] + delayInt;
auto index2 = index1 + 1;
if (index2 >= totalSize)
{
index1 %= totalSize;
index2 %= totalSize;
}
auto value1 = bufferData.getSample (channel, index1);
auto value2 = bufferData.getSample (channel, index2);
auto output = approximatelyEqual (delayFrac, (SampleType) 0) ? value1 : value2 + alpha * (value1 - v[(size_t) channel]);
v[(size_t) channel] = output;
return output;
}
}
//==============================================================================
void updateInternalVariables()
{
if constexpr (std::is_same_v<InterpolationType, DelayLineInterpolationTypes::Lagrange3rd>)
{
if (delayFrac < (SampleType) 2.0 && delayInt >= 1)
{
delayFrac++;
delayInt--;
}
}
else if constexpr (std::is_same_v<InterpolationType, DelayLineInterpolationTypes::Thiran>)
{
if (delayFrac < (SampleType) 0.618 && delayInt >= 1)
{
delayFrac++;
delayInt--;
}
alpha = (1 - delayFrac) / (1 + delayFrac);
}
}
//==============================================================================
double sampleRate;
//==============================================================================
AudioBuffer<SampleType> bufferData;
std::vector<SampleType> v;
std::vector<int> writePos, readPos;
SampleType delay = 0.0, delayFrac = 0.0;
int delayInt = 0, totalSize = 4;
SampleType alpha = 0.0;
};
} // namespace juce::dsp
juce::AudioBuffer::getSample
Type getSample(int channel, int sampleIndex) const noexcept
Definition juce_AudioSampleBuffer.h:640
juce::dsp::DelayLine::prepare
void prepare(const ProcessSpec &spec)
Definition juce_DelayLine.cpp:68
juce::dsp::DelayLine::getMaximumDelayInSamples
int getMaximumDelayInSamples() const noexcept
Definition juce_DelayLine.h:126
juce::dsp::DelayLine::setDelay
void setDelay(SampleType newDelayInSamples)
Definition juce_DelayLine.cpp:48
juce::dsp::DelayLine::popSample
SampleType popSample(int channel, SampleType delayInSamples=-1, bool updateReadPointer=true)
Definition juce_DelayLine.cpp:112
juce::dsp::DelayLine::DelayLine
DelayLine()
Definition juce_DelayLine.cpp:31
juce::dsp::DelayLine::setMaximumDelayInSamples
void setMaximumDelayInSamples(int maxDelayInSamples)
Definition juce_DelayLine.cpp:84
juce::dsp::DelayLine::getDelay
SampleType getDelay() const
Definition juce_DelayLine.cpp:61
juce::dsp::DelayLine::process
void process(const ProcessContext &context) noexcept
Definition juce_DelayLine.h:170
juce::dsp::DelayLine::reset
void reset()
Definition juce_DelayLine.cpp:93
juce::dsp::DelayLine::pushSample
void pushSample(int channel, SampleType sample)
Definition juce_DelayLine.cpp:105
juce::dsp::DelayLineInterpolationTypes
Definition juce_DelayLine.h:35
juce::dsp::DelayLineInterpolationTypes::Lagrange3rd
Definition juce_DelayLine.h:63
juce::dsp::DelayLineInterpolationTypes::Linear
Definition juce_DelayLine.h:53
juce::dsp::DelayLineInterpolationTypes::None
Definition juce_DelayLine.h:43
juce::dsp::DelayLineInterpolationTypes::Thiran
Definition juce_DelayLine.h:74
juce::dsp::ProcessSpec
Definition juce_ProcessContext.h:36