AnalogTapeModel

Physical modelling signal processing for analog tape recording
Log | Files | Refs | Submodules | README | LICENSE

ChewProcessor.cpp (4432B)


      1 #include "ChewProcessor.h"
      2 
      3 ChewProcessor::ChewProcessor (AudioProcessorValueTreeState& vts)
      4 {
      5     using namespace chowdsp::ParamUtils;
      6     loadParameterPointer (depth, vts, "chew_depth");
      7     loadParameterPointer (freq, vts, "chew_freq");
      8     loadParameterPointer (var, vts, "chew_var");
      9     onOff = vts.getRawParameterValue ("chew_onoff");
     10 }
     11 
     12 void ChewProcessor::createParameterLayout (chowdsp::Parameters& params)
     13 {
     14     using namespace chowdsp::ParamUtils;
     15     emplace_param<chowdsp::BoolParameter> (params, "chew_onoff", "Chew On/Off", false);
     16     emplace_param<chowdsp::FloatParameter> (params, "chew_depth", "Chew Depth", NormalisableRange { 0.0f, 1.0f }, 0.0f, &floatValToString, &stringToFloatVal);
     17     emplace_param<chowdsp::FloatParameter> (params, "chew_freq", "Chew Freq", NormalisableRange { 0.0f, 1.0f }, 0.0f, &floatValToString, &stringToFloatVal);
     18     emplace_param<chowdsp::FloatParameter> (params, "chew_var", "Chew Variance", NormalisableRange { 0.0f, 1.0f }, 0.0f, &floatValToString, &stringToFloatVal);
     19 }
     20 
     21 void ChewProcessor::prepare (double sr, int samplesPerBlock, int numChannels)
     22 {
     23     sampleRate = (float) sr;
     24 
     25     dropout.prepare (sr, numChannels);
     26 
     27     filt.resize ((size_t) numChannels);
     28     for (auto& filter : filt)
     29         filter.reset (sampleRate, int (sr * 0.02));
     30 
     31     isCrinkled = false;
     32     samplesUntilChange = getDryTime();
     33     sampleCounter = 0;
     34 
     35     bypass.prepare (samplesPerBlock, numChannels, bypass.toBool (onOff));
     36 }
     37 
     38 void ChewProcessor::processBlock (AudioBuffer<float>& buffer)
     39 {
     40     if (! bypass.processBlockIn (buffer, bypass.toBool (onOff)))
     41         return;
     42 
     43     const int shortBlockSize = 64;
     44     if (buffer.getNumSamples() <= shortBlockSize)
     45     {
     46         processShortBlock (buffer);
     47     }
     48     else
     49     {
     50         int sampleIdx = 0;
     51         for (; sampleIdx + shortBlockSize <= buffer.getNumSamples(); sampleIdx += shortBlockSize)
     52         {
     53             AudioBuffer<float> shortBuff (buffer.getArrayOfWritePointers(),
     54                                           buffer.getNumChannels(),
     55                                           sampleIdx,
     56                                           shortBlockSize);
     57 
     58             processShortBlock (shortBuff);
     59         }
     60 
     61         if (sampleIdx < buffer.getNumSamples())
     62         {
     63             AudioBuffer<float> shortBuff (buffer.getArrayOfWritePointers(),
     64                                           buffer.getNumChannels(),
     65                                           sampleIdx,
     66                                           buffer.getNumSamples() - sampleIdx);
     67 
     68             processShortBlock (shortBuff);
     69         }
     70     }
     71 
     72     bypass.processBlockOut (buffer, bypass.toBool (onOff));
     73 }
     74 
     75 void ChewProcessor::processShortBlock (AudioBuffer<float>& buffer)
     76 {
     77     const float highFreq = jmin (22000.0f, 0.49f * sampleRate);
     78     const float freqChange = highFreq - 5000.0f;
     79 
     80     if (*freq == 0.0f)
     81     {
     82         mix = 0.0f;
     83         for (auto& filter : filt)
     84             filter.setFreq (highFreq);
     85     }
     86     else if (*freq == 1.0f)
     87     {
     88         mix = 1.0f;
     89         power = 3.0f * *depth;
     90         const auto filterFreq = highFreq - freqChange * *depth;
     91         for (auto& filter : filt)
     92             filter.setFreq (filterFreq);
     93     }
     94     else if (sampleCounter >= samplesUntilChange)
     95     {
     96         sampleCounter = 0;
     97         isCrinkled = ! isCrinkled;
     98 
     99         if (isCrinkled) // start crinkle
    100         {
    101             mix = 1.0f;
    102             power = (1.0f + 2.0f * random.nextFloat()) * *depth;
    103             const auto filterFreq = highFreq - freqChange * *depth;
    104             for (auto& filter : filt)
    105                 filter.setFreq (filterFreq);
    106 
    107             samplesUntilChange = getWetTime();
    108         }
    109         else // end crinkle
    110         {
    111             mix = 0.0f;
    112             for (auto& filter : filt)
    113                 filter.setFreq (highFreq);
    114             samplesUntilChange = getDryTime();
    115         }
    116     }
    117     else
    118     {
    119         power = (1.0f + 2.0f * random.nextFloat()) * *depth;
    120         if (isCrinkled)
    121         {
    122             const auto filterFreq = highFreq - freqChange * *depth;
    123             for (auto& filter : filt)
    124                 filter.setFreq (filterFreq);
    125         }
    126     }
    127 
    128     dropout.setMix (mix);
    129     dropout.setPower (1.0f + power);
    130 
    131     dropout.process (buffer);
    132     for (int ch = 0; ch < buffer.getNumChannels(); ++ch)
    133         filt[ch].process (buffer.getWritePointer (ch), buffer.getNumSamples());
    134 
    135     sampleCounter += buffer.getNumSamples();
    136 }