commit 252953fde9d6eef498b7f9728477eff13055b089
parent de8016b3b97a9e876aadb03ac04e342f332fd431
Author: jatinchowdhury18 <jatinchowdhury18@users.noreply.github.com>
Date: Sat, 18 Apr 2020 19:45:00 -0700
Add tape degradation processing
Diffstat:
8 files changed, 206 insertions(+), 0 deletions(-)
diff --git a/Plugin/CHOWTapeModel.jucer b/Plugin/CHOWTapeModel.jucer
@@ -8,6 +8,14 @@
<GROUP id="{0178B10A-4A61-796A-5AB2-915D32AF6EEE}" name="Source">
<FILE id="Xn3V5v" name="gui.xml" compile="0" resource="1" file="Source/gui.xml"/>
<GROUP id="{43BBFC88-4D0A-01B8-2635-3748470B94F4}" name="Processors">
+ <GROUP id="{344B63D7-2DBC-F9D2-ACD7-1B0671D4D024}" name="Degrade">
+ <FILE id="ac7jRp" name="DegradeFilter.h" compile="0" resource="0" file="Source/Processors/Degrade/DegradeFilter.h"/>
+ <FILE id="qWC1GC" name="DegradeNoise.h" compile="0" resource="0" file="Source/Processors/Degrade/DegradeNoise.h"/>
+ <FILE id="VIsORm" name="DegradeProcessor.cpp" compile="1" resource="0"
+ file="Source/Processors/Degrade/DegradeProcessor.cpp"/>
+ <FILE id="pXjWJR" name="DegradeProcessor.h" compile="0" resource="0"
+ file="Source/Processors/Degrade/DegradeProcessor.h"/>
+ </GROUP>
<GROUP id="{6052B1B0-83EF-DBFA-991C-FC0B47A949C9}" name="Hysteresis">
<FILE id="Qe4tlV" name="HysteresisProcessing.cpp" compile="1" resource="0"
file="Source/Processors/Hysteresis/HysteresisProcessing.cpp"/>
diff --git a/Plugin/Source/PluginProcessor.cpp b/Plugin/Source/PluginProcessor.cpp
@@ -24,6 +24,7 @@ ChowtapeModelAudioProcessor::ChowtapeModelAudioProcessor()
#endif
vts (*this, nullptr, Identifier ("Parameters"), createParameterLayout()),
hysteresis (vts),
+ degrade (vts),
flutter (vts)
{
for (int ch = 0; ch < 2; ++ch)
@@ -46,6 +47,7 @@ AudioProcessorValueTreeState::ParameterLayout ChowtapeModelAudioProcessor::creat
HysteresisProcessor::createParameterLayout (params);
LossFilter::createParameterLayout (params);
Flutter::createParameterLayout (params);
+ DegradeProcessor::createParameterLayout (params);
return { params.begin(), params.end() };
}
@@ -117,6 +119,7 @@ void ChowtapeModelAudioProcessor::prepareToPlay (double sampleRate, int samplesP
{
inGain.prepareToPlay (sampleRate, samplesPerBlock);
hysteresis.prepareToPlay (sampleRate, samplesPerBlock);
+ degrade.prepareToPlay (sampleRate, samplesPerBlock);
for (int ch = 0; ch < 2; ++ch)
lossFilter[ch]->prepare ((float) sampleRate, samplesPerBlock);
@@ -165,6 +168,7 @@ void ChowtapeModelAudioProcessor::processBlock (AudioBuffer<float>& buffer, Midi
inGain.processBlock (buffer, midiMessages);
hysteresis.processBlock (buffer, midiMessages);
+ degrade.processBlock (buffer, midiMessages);
flutter.processBlock (buffer, midiMessages);
diff --git a/Plugin/Source/PluginProcessor.h b/Plugin/Source/PluginProcessor.h
@@ -15,6 +15,7 @@
#include "Processors/Hysteresis/HysteresisProcessor.h"
#include "Processors/Loss_Effects/LossFilter.h"
#include "Processors/Timing_Effects/Flutter.h"
+#include "Processors/Degrade/DegradeProcessor.h"
//==============================================================================
/**
@@ -67,6 +68,7 @@ private:
GainProcessor inGain;
HysteresisProcessor hysteresis;
+ DegradeProcessor degrade;
std::unique_ptr<LossFilter> lossFilter[2];
Flutter flutter;
GainProcessor outGain;
diff --git a/Plugin/Source/Processors/Degrade/DegradeFilter.h b/Plugin/Source/Processors/Degrade/DegradeFilter.h
@@ -0,0 +1,68 @@
+#ifndef DEGRADEFILTER_H_INCLUDED
+#define DEGRADEFILTER_H_INCLUDED
+
+#include "JuceHeader.h"
+
+/** Lowpass filter for tape degrade effect */
+class DegradeFilter
+{
+public:
+ DegradeFilter() { freq.reset (numSteps); }
+ ~DegradeFilter() {}
+
+ void reset (float sampleRate)
+ {
+ fs = sampleRate;
+ for (int n = 0; n < 2; ++n)
+ z[n] = 0.0f;
+
+ calcCoefs (freq.skip (numSteps));
+ }
+
+ inline void calcCoefs (float fc)
+ {
+ float wc = MathConstants<float>::twoPi * fc / fs;
+ float c = 1.0f / dsp::FastMathApproximations::tan (wc / 2.0f);
+ float a0 = c + 1.0f;
+
+ b[0] = 1 / a0;
+ b[1] = b[0];
+ a[1] = (1.0f - c) / a0;
+ }
+
+ inline void process (float* buffer, int numSamples)
+ {
+ for (int n = 0; n < numSamples; ++n)
+ {
+ if (freq.isSmoothing())
+ calcCoefs (freq.getNextValue());
+
+ buffer[n] = processSample (buffer[n]);
+ }
+ }
+
+ inline float processSample (float x)
+ {
+ float y = z[1] + x*b[0];
+ z[1] = x*b[1] - y*a[1];
+ return y;
+ }
+
+ void setFreq (float newFreq)
+ {
+ freq.setTargetValue (newFreq);
+ }
+
+private:
+ SmoothedValue<float, ValueSmoothingTypes::Multiplicative> freq = 20000.0f;
+ float fs = 44100.0f;
+ const int numSteps = 200;
+
+ float a[2] = { 1.0f, 0.0f };
+ float b[2] = { 1.0f, 0.0f };
+ float z[2] = { 1.0f, 0.0f };
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DegradeFilter)
+};
+
+#endif // DEGRADEFILTER_H_INCLUDED
diff --git a/Plugin/Source/Processors/Degrade/DegradeNoise.h b/Plugin/Source/Processors/Degrade/DegradeNoise.h
@@ -0,0 +1,45 @@
+#ifndef DEGRADENOISE_H_INCLUDED
+#define DEGRADENOISE_H_INCLUDED
+
+#include "JuceHeader.h"
+
+/** Noise for tape degrade effect */
+class DegradeNoise
+{
+public:
+ DegradeNoise() {}
+ ~DegradeNoise() {}
+
+ void setGain (float newGain) { curGain = newGain; }
+
+ void prepare()
+ {
+ prevGain = curGain;
+ }
+
+ void processBlock (float* buffer, int numSamples)
+ {
+ if (curGain == prevGain)
+ {
+ for (int n = 0; n < numSamples; ++n)
+ buffer[n] += (random.nextFloat() - 0.5f) * curGain;
+ }
+ else
+ {
+ for (int n = 0; n < numSamples; ++n)
+ buffer[n] += (random.nextFloat() - 0.5f) * ((curGain * (float) n / (float) numSamples) + (prevGain * (1.0f - (float) n / (float) numSamples)));
+
+ prevGain = curGain;
+ }
+ }
+
+private:
+ float curGain = 0.0f;
+ float prevGain = curGain;
+
+ Random random;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DegradeNoise)
+};
+
+#endif // DEGRADENOISE_H_INCLUDED
diff --git a/Plugin/Source/Processors/Degrade/DegradeProcessor.cpp b/Plugin/Source/Processors/Degrade/DegradeProcessor.cpp
@@ -0,0 +1,47 @@
+#include "DegradeProcessor.h"
+
+DegradeProcessor::DegradeProcessor (AudioProcessorValueTreeState& vts)
+{
+ depthParam = vts.getRawParameterValue ("deg_depth");
+ amtParam = vts.getRawParameterValue ("deg_amt");
+ varParam = vts.getRawParameterValue ("deg_var");
+}
+
+void DegradeProcessor::createParameterLayout (std::vector<std::unique_ptr<RangedAudioParameter>>& params)
+{
+ params.push_back (std::make_unique<AudioParameterFloat> ("deg_depth", "Depth", 0.0f, 1.0f, 0.0f));
+ params.push_back (std::make_unique<AudioParameterFloat> ("deg_amt", "Amount", 0.0f, 1.0f, 0.0f));
+ params.push_back (std::make_unique<AudioParameterFloat> ("deg_var", "Variance", 0.0f, 1.0f, 0.0f));
+}
+
+void DegradeProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
+{
+ for (int ch = 0; ch < 2; ++ch)
+ {
+ noiseProc[ch].prepare();
+ filterProc[ch].reset ((float) sampleRate);
+ }
+
+ gainProc.prepareToPlay (sampleRate, samplesPerBlock);
+}
+
+void DegradeProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& midi)
+{
+ if (*amtParam == 0.0f || *depthParam == 0.0f)
+ return;
+
+ float freqHz = 200.0f * std::powf (20000.0f / 200.0f, 1.0f - *amtParam);
+ float gainDB = -24.0f * *depthParam;
+
+ for (int ch = 0; ch < buffer.getNumChannels(); ++ch)
+ {
+ noiseProc[ch].setGain (0.5f * *depthParam * *amtParam);
+ noiseProc[ch].processBlock (buffer.getWritePointer (ch), buffer.getNumSamples());
+
+ filterProc[ch].setFreq (jmin (freqHz + (*varParam * (freqHz / 0.6f) * (random.nextFloat() - 0.5f)), 22000.0f));
+ filterProc[ch].process (buffer.getWritePointer (ch), buffer.getNumSamples());
+ }
+
+ gainProc.setGain (Decibels::decibelsToGain (jmin (gainDB + (*varParam * 36.0f * (random.nextFloat() - 0.5f)), 3.0f)));
+ gainProc.processBlock (buffer, midi);
+}
diff --git a/Plugin/Source/Processors/Degrade/DegradeProcessor.h b/Plugin/Source/Processors/Degrade/DegradeProcessor.h
@@ -0,0 +1,32 @@
+#ifndef DEGRADEPROCESSOR_H_INCLUDED
+#define DEGRADEPROCESSOR_H_INCLUDED
+
+#include "../GainProcessor.h"
+#include "DegradeNoise.h"
+#include "DegradeFilter.h"
+
+class DegradeProcessor
+{
+public:
+ DegradeProcessor (AudioProcessorValueTreeState& vts);
+
+ static void createParameterLayout (std::vector<std::unique_ptr<RangedAudioParameter>>& params);
+
+ void prepareToPlay (double sampleRate, int samplesPerBlock);
+ void processBlock (AudioBuffer<float>& buffer, MidiBuffer& midi);
+
+private:
+ float* depthParam = nullptr;
+ float* amtParam = nullptr;
+ float* varParam = nullptr;
+
+ DegradeNoise noiseProc[2];
+ DegradeFilter filterProc[2];
+ GainProcessor gainProc;
+
+ Random random;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DegradeProcessor)
+};
+
+#endif // DEGRADEPROCESSOR_H_INCLUDED
diff --git a/Plugin/Source/gui.xml b/Plugin/Source/gui.xml
Binary files differ.