|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- /*
- ==============================================================================
-
- 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
- {
- namespace dsp
- {
-
- //==============================================================================
- /**
- A collection of structs to pass as the template argument when setting the
- interpolation type for the DelayLine class.
- */
- namespace DelayLineInterpolationTypes
- {
- /**
- No interpolation between successive samples in the delay line will be
- performed. This is useful when the delay is a constant integer or to
- create lo-fi audio effects.
-
- @tags{DSP}
- */
- struct None {};
-
- /**
- Successive samples in the delay line will be linearly interpolated. This
- type of interpolation has a low computational cost where the delay can be
- modulated in real time, but it also introduces a low-pass filtering effect
- into your audio signal.
-
- @tags{DSP}
- */
- struct Linear {};
-
- /**
- Successive samples in the delay line will be interpolated using a 3rd order
- Lagrange interpolator. This method incurs more computational overhead than
- linear interpolation but reduces the low-pass filtering effect whilst
- remaining amenable to real time delay modulation.
-
- @tags{DSP}
- */
- struct Lagrange3rd {};
-
- /**
- Successive samples in the delay line will be interpolated using 1st order
- Thiran interpolation. This method is very efficient, and features a flat
- amplitude frequency response in exchange for less accuracy in the phase
- response. This interpolation method is stateful so is unsuitable for
- applications requiring fast delay modulation.
-
- @tags{DSP}
- */
- struct Thiran {};
- }
-
- //==============================================================================
- /**
- A delay line processor featuring several algorithms for the fractional delay
- calculation, block processing, and sample-by-sample processing useful when
- modulating the delay in real time or creating a standard delay effect with
- feedback.
-
- Note: If you intend to change the delay in real time, you may want to smooth
- changes to the delay systematically using either a ramp or a low-pass filter.
-
- @see SmoothedValue, FirstOrderTPTFilter
-
- @tags{DSP}
- */
- template <typename SampleType, typename InterpolationType = DelayLineInterpolationTypes::Linear>
- class DelayLine
- {
- public:
- //==============================================================================
- /** Default constructor. */
- DelayLine();
-
- /** Constructor. */
- explicit DelayLine (int maximumDelayInSamples);
-
- //==============================================================================
- /** Sets the delay in samples. */
- void setDelay (SampleType newDelayInSamples);
-
- /** Returns the current delay in samples. */
- SampleType getDelay() const;
-
- //==============================================================================
- /** Initialises the processor. */
- void prepare (const ProcessSpec& spec);
-
- /** Sets a new maximum delay in samples.
-
- Also clears the delay line.
-
- This may allocate internally, so you should never call it from the audio thread.
- */
- void setMaximumDelayInSamples (int maxDelayInSamples);
-
- /** Gets the maximum possible delay in samples.
-
- For very short delay times, the result of getMaximumDelayInSamples() may
- differ from the last value passed to setMaximumDelayInSamples().
- */
- int getMaximumDelayInSamples() const noexcept { return totalSize - 1; }
-
- /** Resets the internal state variables of the processor. */
- void reset();
-
- //==============================================================================
- /** Pushes a single sample into one channel of the delay line.
-
- Use this function and popSample instead of process if you need to modulate
- the delay in real time instead of using a fixed delay value, or if you want
- to code a delay effect with a feedback loop.
-
- @see setDelay, popSample, process
- */
- void pushSample (int channel, SampleType sample);
-
- /** Pops a single sample from one channel of the delay line.
-
- Use this function to modulate the delay in real time or implement standard
- delay effects with feedback.
-
- @param channel the target channel for the delay line.
-
- @param delayInSamples sets the wanted fractional delay in samples, or -1
- to use the value being used before or set with
- setDelay function.
-
- @param updateReadPointer should be set to true if you use the function
- once for each sample, or false if you need
- multi-tap delay capabilities.
-
- @see setDelay, pushSample, process
- */
- SampleType popSample (int channel, SampleType delayInSamples = -1, bool updateReadPointer = true);
-
- //==============================================================================
- /** Processes the input and output samples supplied in the processing context.
-
- Can be used for block processing when the delay is not going to change
- during processing. The delay must first be set by calling setDelay.
-
- @see setDelay
- */
- 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:
- //==============================================================================
- template <typename T = InterpolationType>
- typename std::enable_if <std::is_same <T, DelayLineInterpolationTypes::None>::value, SampleType>::type
- interpolateSample (int channel) const
- {
- auto index = (readPos[(size_t) channel] + delayInt) % totalSize;
- return bufferData.getSample (channel, index);
- }
-
- template <typename T = InterpolationType>
- typename std::enable_if <std::is_same <T, DelayLineInterpolationTypes::Linear>::value, SampleType>::type
- interpolateSample (int channel) const
- {
- 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);
- }
-
- template <typename T = InterpolationType>
- typename std::enable_if <std::is_same <T, DelayLineInterpolationTypes::Lagrange3rd>::value, SampleType>::type
- interpolateSample (int channel) const
- {
- 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);
- }
-
- template <typename T = InterpolationType>
- typename std::enable_if <std::is_same <T, DelayLineInterpolationTypes::Thiran>::value, SampleType>::type
- interpolateSample (int channel)
- {
- 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 = delayFrac == 0 ? value1 : value2 + alpha * (value1 - v[(size_t) channel]);
- v[(size_t) channel] = output;
-
- return output;
- }
-
- //==============================================================================
- template <typename T = InterpolationType>
- typename std::enable_if <std::is_same <T, DelayLineInterpolationTypes::None>::value, void>::type
- updateInternalVariables()
- {
- }
-
- template <typename T = InterpolationType>
- typename std::enable_if <std::is_same <T, DelayLineInterpolationTypes::Linear>::value, void>::type
- updateInternalVariables()
- {
- }
-
- template <typename T = InterpolationType>
- typename std::enable_if <std::is_same <T, DelayLineInterpolationTypes::Lagrange3rd>::value, void>::type
- updateInternalVariables()
- {
- if (delayInt >= 1)
- {
- delayFrac++;
- delayInt--;
- }
- }
-
- template <typename T = InterpolationType>
- typename std::enable_if <std::is_same <T, DelayLineInterpolationTypes::Thiran>::value, void>::type
- updateInternalVariables()
- {
- 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 dsp
- } // namespace juce
|