NeuralPi

Raspberry Pi guitar pedal using neural networks to emulate real amps and effects
Log | Files | Refs | Submodules | README

Delay.h (6847B)


      1 /*
      2   ==============================================================================
      3 
      4   Delay
      5 
      6   ==============================================================================
      7 */
      8 #include "../JuceLibraryCode/JuceHeader.h"
      9 
     10 #pragma once
     11 
     12 //==============================================================================
     13 template <typename Type>
     14 class DelayLine
     15 {
     16 public:
     17     void clear() noexcept
     18     {
     19         std::fill (rawData.begin(), rawData.end(), Type (0));
     20     }
     21 
     22     size_t size() const noexcept
     23     {
     24         return rawData.size();
     25     }
     26 
     27     void resize (size_t newValue)
     28     {
     29         rawData.resize (newValue);
     30         leastRecentIndex = 0;
     31     }
     32 
     33     Type back() const noexcept
     34     {
     35         return rawData[leastRecentIndex];
     36     }
     37 
     38     Type get (size_t delayInSamples) const noexcept
     39     {
     40         jassert (delayInSamples >= 0 && delayInSamples < size());
     41 
     42         return rawData[(leastRecentIndex + 1 + delayInSamples) % size()];   // [3]
     43     }
     44 
     45     /** Set the specified sample in the delay line */
     46     void set (size_t delayInSamples, Type newValue) noexcept
     47     {
     48         jassert (delayInSamples >= 0 && delayInSamples < size());
     49 
     50         rawData[(leastRecentIndex + 1 + delayInSamples) % size()] = newValue; // [4]
     51     }
     52 
     53     /** Adds a new value to the delay line, overwriting the least recently added sample */
     54     void push (Type valueToAdd) noexcept
     55     {
     56         rawData[leastRecentIndex] = valueToAdd;                                         // [1]
     57         leastRecentIndex = leastRecentIndex == 0 ? size() - 1 : leastRecentIndex - 1;   // [2]
     58     }
     59 
     60 private:
     61     std::vector<Type> rawData;
     62     size_t leastRecentIndex = 0;
     63 };
     64 
     65 //==============================================================================
     66 template <typename Type, size_t maxNumChannels = 2>
     67 class Delay
     68 {
     69 public:
     70     //==============================================================================
     71     Delay()
     72     {
     73         setMaxDelayTime (2.0f);
     74         setDelayTime (0, 0.7f);
     75         setDelayTime (1, 0.5f);
     76         setWetLevel (0.8f);
     77         setFeedback (0.5f);
     78     }
     79 
     80     //==============================================================================
     81     void prepare (const juce::dsp::ProcessSpec& spec)
     82     {
     83         jassert (spec.numChannels <= maxNumChannels);
     84         sampleRate = (Type) spec.sampleRate;
     85         updateDelayLineSize();
     86         updateDelayTime();
     87 
     88         //filterCoefs = juce::dsp::IIR::Coefficients<Type>::makeFirstOrderLowPass (sampleRate, Type (1e3));
     89         filterCoefs = juce::dsp::IIR::Coefficients<Type>::makeFirstOrderHighPass (sampleRate, Type (1e3));
     90 
     91         for (auto& f : filters)
     92         {
     93             f.prepare (spec);
     94             f.coefficients = filterCoefs;
     95         }
     96     }
     97 
     98     //==============================================================================
     99     void reset() noexcept
    100     {
    101         for (auto& f : filters)
    102             f.reset();      // [5]
    103 
    104         for (auto& dline : delayLines)
    105             dline.clear();  // [6]
    106     }
    107 
    108     //==============================================================================
    109     size_t getNumChannels() const noexcept
    110     {
    111         return delayLines.size();
    112     }
    113 
    114     //==============================================================================
    115     void setMaxDelayTime (Type newValue)
    116     {
    117         jassert (newValue > Type (0));
    118         maxDelayTime = newValue;
    119         updateDelayLineSize(); // [1]
    120     }
    121 
    122     //==============================================================================
    123     void setFeedback (Type newValue) noexcept
    124     {
    125         jassert (newValue >= Type (0) && newValue <= Type (1));
    126         feedback = newValue;
    127     }
    128 
    129     //==============================================================================
    130     void setWetLevel (Type newValue) noexcept
    131     {
    132         jassert (newValue >= Type (0) && newValue <= Type (1));
    133         wetLevel = newValue;
    134     }
    135 
    136     //==============================================================================
    137     void setDelayTime (size_t channel, Type newValue)
    138     {
    139         if (channel >= getNumChannels())
    140         {
    141             jassertfalse;
    142             return;
    143         }
    144 
    145         jassert (newValue >= Type (0));
    146         delayTimes[channel] = newValue;
    147 
    148         updateDelayTime();  // [3]
    149     }
    150 
    151     //==============================================================================
    152     template <typename ProcessContext>
    153     void process (const ProcessContext& context) noexcept
    154     {
    155         auto& inputBlock  = context.getInputBlock();
    156         auto& outputBlock = context.getOutputBlock();
    157         auto numSamples  = outputBlock.getNumSamples();
    158         auto numChannels = outputBlock.getNumChannels();
    159 
    160         jassert (inputBlock.getNumSamples() == numSamples);
    161         jassert (inputBlock.getNumChannels() == numChannels);
    162 
    163         for (size_t ch = 0; ch < numChannels; ++ch)
    164         {
    165             auto* input  = inputBlock .getChannelPointer (ch);
    166             auto* output = outputBlock.getChannelPointer (ch);
    167             auto& dline = delayLines[ch];
    168             auto delayTime = delayTimesSample[ch];
    169             auto& filter = filters[ch];
    170 
    171             for (size_t i = 0; i < numSamples; ++i)
    172             {
    173                 //auto delayedSample = dline.get (delayTime);
    174                 auto delayedSample = filter.processSample (dline.get (delayTime));
    175                 auto inputSample = input[i];
    176                 auto dlineInputSample = std::tanh (inputSample + feedback * delayedSample);
    177                 dline.push (dlineInputSample);
    178                 auto outputSample = inputSample + wetLevel * delayedSample;
    179                 output[i] = outputSample;
    180             }
    181         }
    182     }
    183 
    184 private:
    185     //==============================================================================
    186     std::array<DelayLine<Type>, maxNumChannels> delayLines;
    187     std::array<size_t, maxNumChannels> delayTimesSample;
    188     std::array<Type, maxNumChannels> delayTimes;
    189     Type feedback { Type (0) };
    190     Type wetLevel { Type (0) };
    191 
    192     std::array<juce::dsp::IIR::Filter<Type>, maxNumChannels> filters;
    193     typename juce::dsp::IIR::Coefficients<Type>::Ptr filterCoefs;
    194 
    195     Type sampleRate   { Type (44.1e3) };
    196     Type maxDelayTime { Type (2) };
    197 
    198     //==============================================================================
    199     void updateDelayLineSize()
    200     {
    201         auto delayLineSizeSamples = (size_t) std::ceil (maxDelayTime * sampleRate);
    202 
    203         for (auto& dline : delayLines)
    204             dline.resize (delayLineSizeSamples);    // [2]
    205     }
    206 
    207     //==============================================================================
    208     void updateDelayTime() noexcept
    209     {
    210         for (size_t ch = 0; ch < maxNumChannels; ++ch)
    211             delayTimesSample[ch] = (size_t) juce::roundToInt (delayTimes[ch] * sampleRate);
    212     }
    213 
    214     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Delay)
    215 };