WowFlutterProcessor.cpp (5362B)
1 #include "WowFlutterProcessor.h" 2 #include "../../GUI/Visualizers/LightMeter.h" 3 4 WowFlutterProcessor::WowFlutterProcessor (AudioProcessorValueTreeState& vts) 5 { 6 using namespace chowdsp::ParamUtils; 7 loadParameterPointer (flutterRate, vts, "rate"); 8 loadParameterPointer (flutterDepth, vts, "depth"); 9 loadParameterPointer (wowRate, vts, "wow_rate"); 10 loadParameterPointer (wowDepth, vts, "wow_depth"); 11 loadParameterPointer (wowVariance, vts, "wow_var"); 12 loadParameterPointer (wowDrift, vts, "wow_drift"); 13 flutterOnOff = vts.getRawParameterValue ("flutter_onoff"); 14 } 15 16 void WowFlutterProcessor::initialisePlots (foleys::MagicGUIState& magicState) 17 { 18 wowPlot = magicState.createAndAddObject<LightMeter> ("wow"); 19 magicState.addBackgroundProcessing (wowPlot); 20 21 flutterPlot = magicState.createAndAddObject<LightMeter> ("flutter"); 22 magicState.addBackgroundProcessing (flutterPlot); 23 } 24 25 void WowFlutterProcessor::createParameterLayout (chowdsp::Parameters& params) 26 { 27 using namespace chowdsp::ParamUtils; 28 emplace_param<chowdsp::BoolParameter> (params, "flutter_onoff", "Wow/Flutter On/Off", true); 29 emplace_param<chowdsp::FloatParameter> (params, "rate", "Flutter Rate", NormalisableRange { 0.0f, 1.0f }, 0.3f, &floatValToString, &stringToFloatVal); 30 emplace_param<chowdsp::FloatParameter> (params, "depth", "Flutter Depth", NormalisableRange { 0.0f, 1.0f }, 0.0f, &floatValToString, &stringToFloatVal); 31 emplace_param<chowdsp::FloatParameter> (params, "wow_rate", "Wow Rate", NormalisableRange { 0.0f, 1.0f }, 0.25f, &floatValToString, &stringToFloatVal); 32 emplace_param<chowdsp::FloatParameter> (params, "wow_depth", "Wow Depth", NormalisableRange { 0.0f, 1.0f }, 0.0f, &floatValToString, &stringToFloatVal); 33 emplace_param<chowdsp::FloatParameter> (params, "wow_var", "Wow Variance", NormalisableRange { 0.0f, 1.0f }, 0.0f, &floatValToString, &stringToFloatVal); 34 emplace_param<chowdsp::FloatParameter> (params, "wow_drift", "Wow Drift", NormalisableRange { 0.0f, 1.0f }, 0.0f, &floatValToString, &stringToFloatVal); 35 } 36 37 void WowFlutterProcessor::prepareToPlay (double sampleRate, int samplesPerBlock, int numChannels) 38 { 39 fs = (float) sampleRate; 40 41 bypass.prepare (samplesPerBlock, numChannels, bypass.toBool (flutterOnOff)); 42 wowProcessor.prepare (sampleRate, samplesPerBlock, numChannels); 43 flutterProcessor.prepare (sampleRate, samplesPerBlock, numChannels); 44 45 delay.prepare ({ sampleRate, (uint32) samplesPerBlock, (uint32) numChannels }); 46 delay.setDelay (0.0f); 47 48 dcBlocker.resize ((size_t) numChannels); 49 for (auto& filt : dcBlocker) 50 filt.prepare (sampleRate, 15.0f); 51 52 wowPlot->prepareToPlay (sampleRate, samplesPerBlock); 53 flutterPlot->prepareToPlay (sampleRate, samplesPerBlock); 54 } 55 56 void WowFlutterProcessor::processBlock (AudioBuffer<float>& buffer) 57 { 58 ScopedNoDenormals noDenormals; 59 60 const auto numChannels = buffer.getNumChannels(); 61 const auto numSamples = buffer.getNumSamples(); 62 63 auto curDepthWow = powf (*wowDepth, 3.0f); 64 auto wowFreq = powf (4.5, *wowRate) - 1.0f; 65 wowProcessor.prepareBlock (curDepthWow, wowFreq, wowVariance->getCurrentValue(), wowDrift->getCurrentValue(), numSamples, numChannels); 66 67 auto curDepthFlutter = powf (powf (*flutterDepth, 3.0f) * 81.0f / 625.0f, 0.5f); 68 auto flutterFreq = 0.1f * powf (1000.0f, *flutterRate); 69 flutterProcessor.prepareBlock (curDepthFlutter, flutterFreq, numSamples, numChannels); 70 71 bool shouldTurnOff = ! bypass.toBool (flutterOnOff) || (wowProcessor.shouldTurnOff() && flutterProcessor.shouldTurnOff()); 72 if (bypass.processBlockIn (buffer, ! shouldTurnOff)) 73 { 74 processWetBuffer (buffer); 75 76 for (int ch = 0; ch < buffer.getNumChannels(); ++ch) 77 dcBlocker[ch].processBlock (buffer.getWritePointer (ch), buffer.getNumSamples()); 78 79 bypass.processBlockOut (buffer, ! shouldTurnOff); 80 } 81 else 82 { 83 processBypassed (buffer); 84 } 85 86 wowProcessor.plotBuffer (wowPlot); 87 flutterProcessor.plotBuffer (flutterPlot); 88 } 89 90 void WowFlutterProcessor::processWetBuffer (AudioBuffer<float>& buffer) 91 { 92 for (int ch = 0; ch < buffer.getNumChannels(); ++ch) 93 { 94 auto* x = buffer.getWritePointer (ch); 95 for (int n = 0; n < buffer.getNumSamples(); ++n) 96 { 97 auto [wowLFO, wowOffset] = wowProcessor.getLFO (n, ch); 98 auto [flutterLFO, flutterOffset] = flutterProcessor.getLFO (n, ch); 99 100 auto newLength = (wowLFO + flutterLFO + flutterOffset + wowOffset) * fs / 1000.0f; 101 newLength = jlimit (0.0f, (float) HISTORY_SIZE, newLength); 102 103 delay.setDelay (newLength); 104 delay.pushSample (ch, x[n]); 105 x[n] = delay.popSample (ch); 106 } 107 108 wowProcessor.boundPhase (ch); 109 flutterProcessor.boundPhase (ch); 110 } 111 } 112 113 void WowFlutterProcessor::processBypassed (const AudioBuffer<float>& buffer) 114 { 115 for (int ch = 0; ch < buffer.getNumChannels(); ++ch) 116 { 117 delay.setDelay (0.0f); 118 for (int n = 0; n < buffer.getNumSamples(); ++n) 119 { 120 wowProcessor.updatePhase (ch); 121 flutterProcessor.updatePhase (ch); 122 123 delay.pushSample (ch, 0.0f); 124 delay.popSample (ch); 125 } 126 127 wowProcessor.boundPhase (ch); 128 flutterProcessor.boundPhase (ch); 129 } 130 }