commit 0a8da1dea339a0e8f1f8369aadf3ca314b8394c6
parent 1a3e41a9eb47d6cc5f52ba4ab0c6670d830d8712
Author: jatinchowdhury18 <jatinchowdhury18@users.noreply.github.com>
Date: Mon, 27 Jan 2020 20:14:00 -0800
First attempt at pre/post EQ
Diffstat:
11 files changed, 235 insertions(+), 3 deletions(-)
diff --git a/Plugin/CHOWTapeModel.jucer b/Plugin/CHOWTapeModel.jucer
@@ -26,6 +26,11 @@
<FILE id="gFXfuJ" name="MyLNF.h" compile="0" resource="0" file="Source/GUI Extras/MyLNF.h"/>
</GROUP>
<GROUP id="{43BBFC88-4D0A-01B8-2635-3748470B94F4}" name="Processors">
+ <GROUP id="{344B63D7-2DBC-F9D2-ACD7-1B0671D4D024}" name="PrePostEQ">
+ <FILE id="wOFjAX" name="EQFilters.h" compile="0" resource="0" file="Source/Processors/PrePostEQ/EQFilters.h"/>
+ <FILE id="YHmS1B" name="PrePostEQ.cpp" compile="1" resource="0" file="Source/Processors/PrePostEQ/PrePostEQ.cpp"/>
+ <FILE id="nI7wZD" name="PrePostEQ.h" compile="0" resource="0" file="Source/Processors/PrePostEQ/PrePostEQ.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/GUI Components/MainControls.cpp b/Plugin/Source/GUI Components/MainControls.cpp
@@ -7,6 +7,9 @@ MainControls::MainControls (ChowtapeModelAudioProcessor& proc) :
ChowtapeModelAudioProcessorEditor::createSlider (gainInKnob, proc.getVTS(), "ingain", gainInAttach, *this, myLNF, " dB");
ChowtapeModelAudioProcessorEditor::createSlider (gainOutKnob, proc.getVTS(), "outgain", gainOutAttach, *this, myLNF, " dB");
ChowtapeModelAudioProcessorEditor::createComboBox (oversampling, proc.getVTS(), "os", osAttach, this, StringArray ({"2x", "4x", "8x", "16x"}));
+ ChowtapeModelAudioProcessorEditor::createButton (prePostEQButton, proc.getVTS(), "prepost", prePostAttach, this, "ON/OFF",
+ Colours::darkred.withMultipliedBrightness (1.2f));
+
// ChowtapeModelAudioProcessorEditor::createComboBox (oversampling, processor.overSampling, this);
// ChowtapeModelAudioProcessorEditor::createComboBox (tapeSpeed, processor.tapeSpeed, this);
// //ChowtapeModelAudioProcessorEditor::createComboBox (tapeType, processor.tapeType, this);
@@ -15,6 +18,8 @@ MainControls::MainControls (ChowtapeModelAudioProcessor& proc) :
ChowtapeModelAudioProcessorEditor::createLabel (inGainLabel, gainInKnob.getName(), this);
ChowtapeModelAudioProcessorEditor::createLabel (outGainLabel, gainOutKnob.getName(), this);
ChowtapeModelAudioProcessorEditor::createLabel (oversampleLabel, oversampling.getName(), this);
+ ChowtapeModelAudioProcessorEditor::createLabel (prePostEQLabel, prePostEQButton.getName(), this);
+
// ChowtapeModelAudioProcessorEditor::createLabel (speedLabel, processor.tapeSpeed, this);
// //ChowtapeModelAudioProcessorEditor::createLabel (typeLabel, processor.tapeType, this);
}
@@ -29,6 +34,9 @@ void MainControls::resized()
oversampleLabel.setBounds (gainInKnob.getRight() - 7 * xOffset, 2 * labelY + yOffset, tapeWidth, labelHeight);
oversampling.setBounds (gainInKnob.getRight(), oversampleLabel.getBottom(), overWidth, boxHeight);
+ prePostEQLabel.setBounds (oversampleLabel.getX(), oversampling.getBottom() + 5, tapeWidth, labelHeight);
+ prePostEQButton.setBounds (prePostEQLabel.getX() + 15, prePostEQLabel.getBottom() + 3, overWidth * 4 / 5, boxHeight);
+
// speedLabel.setBounds (oversampling.getRight(), 2 * labelY + yOffset, tapeWidth, labelHeight);
// tapeSpeed.setBounds (oversampling.getRight() + 2 * xOffset, speedLabel.getBottom(), tapeWidth, boxHeight);
//
diff --git a/Plugin/Source/GUI Components/MainControls.h b/Plugin/Source/GUI Components/MainControls.h
@@ -7,6 +7,7 @@
using SliderAttachment = AudioProcessorValueTreeState::SliderAttachment;
using ComboBoxAttachment = AudioProcessorValueTreeState::ComboBoxAttachment;
+using ButtonAttachment = AudioProcessorValueTreeState::ButtonAttachment;
class MainControls : public Component
{
@@ -30,12 +31,16 @@ private:
ComboBox oversampling;
std::unique_ptr<ComboBoxAttachment> osAttach;
+ TextButton prePostEQButton;
+ std::unique_ptr<ButtonAttachment> prePostAttach;
+
// ComboBox tapeSpeed;
// ComboBox tapeType;
Label inGainLabel;
Label outGainLabel;
Label oversampleLabel;
+ Label prePostEQLabel;
// Label speedLabel;
// Label typeLabel;
diff --git a/Plugin/Source/PluginEditor.cpp b/Plugin/Source/PluginEditor.cpp
@@ -67,6 +67,24 @@ void ChowtapeModelAudioProcessorEditor::createComboBox (ComboBox& box, AudioProc
comp->addAndMakeVisible (box);
}
+void ChowtapeModelAudioProcessorEditor::createButton (TextButton& button, AudioProcessorValueTreeState& vts, String paramID,
+ std::unique_ptr<ButtonAttachment>& attachment, Component* comp, String text, Colour onColour)
+{
+ attachment.reset (new ButtonAttachment (vts, paramID, button));
+
+ button.setName (vts.getParameter (paramID)->name);
+ button.setButtonText (text);
+ button.setClickingTogglesState (true);
+
+ button.setColour (TextButton::buttonOnColourId, onColour);
+ button.setColour (TextButton::buttonColourId, Colours::transparentWhite);
+ button.setColour (TextButton::textColourOnId, Colours::antiquewhite);
+ button.setColour (TextButton::textColourOffId, Colours::antiquewhite);
+ button.setColour (ComboBox::outlineColourId, Colours::antiquewhite);
+
+ comp->addAndMakeVisible (button);
+}
+
void ChowtapeModelAudioProcessorEditor::createLabel (Label& label, String name, Component* comp)
{
label.setText (name, dontSendNotification);
diff --git a/Plugin/Source/PluginEditor.h b/Plugin/Source/PluginEditor.h
@@ -48,6 +48,8 @@ public:
std::function<String (double)> textFromValue = {}, std::function<double (String)> valueFromText = {});
static void createComboBox (ComboBox& box, AudioProcessorValueTreeState& vts, String paramID,
std::unique_ptr<ComboBoxAttachment>& attachment, Component* comp, StringArray choices);
+ static void createButton (TextButton& button, AudioProcessorValueTreeState& vts, String paramID,
+ std::unique_ptr<ButtonAttachment>& attachment, Component* comp, String text, Colour onColour);
static void createLabel (Label& label, String name, Component* comp);
private:
diff --git a/Plugin/Source/PluginProcessor.cpp b/Plugin/Source/PluginProcessor.cpp
@@ -39,8 +39,9 @@ AudioProcessorValueTreeState::ParameterLayout ChowtapeModelAudioProcessor::creat
{
std::vector<std::unique_ptr<RangedAudioParameter>> params;
- params.push_back (std::make_unique<AudioParameterFloat> ("ingain", "Input Gain", -30.0f, 6.0f, 0.0f));
+ params.push_back (std::make_unique<AudioParameterFloat> ("ingain", "Input Gain", -30.0f, 30.0f, 0.0f));
params.push_back (std::make_unique<AudioParameterFloat> ("outgain", "Output Gain", -30.0f, 30.0f, 0.0f));
+ params.push_back (std::make_unique<AudioParameterBool> ("prepost", "Pre/Post EQ", true));
HysteresisProcessor::createParameterLayout (params);
LossFilter::createParameterLayout (params);
@@ -115,6 +116,7 @@ void ChowtapeModelAudioProcessor::changeProgramName (int index, const String& ne
void ChowtapeModelAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
inGain.prepareToPlay (sampleRate, samplesPerBlock);
+ prePostEQ.prepare (sampleRate, samplesPerBlock);
hysteresis.prepareToPlay (sampleRate, samplesPerBlock);
for (int ch = 0; ch < 2; ++ch)
@@ -157,14 +159,23 @@ void ChowtapeModelAudioProcessor::processBlock (AudioBuffer<float>& buffer, Midi
{
ScopedNoDenormals noDenormals;
+ bool usePrePost = (bool) *vts.getRawParameterValue ("prepost");
+
inGain.setGain (Decibels::decibelsToGain (*vts.getRawParameterValue ("ingain")));
outGain.setGain (Decibels::decibelsToGain (*vts.getRawParameterValue ("outgain")));
inGain.processBlock (buffer, midiMessages);
+
+ if (usePrePost)
+ prePostEQ.processPreBlock (buffer, midiMessages);
+
hysteresis.processBlock (buffer, midiMessages);
+
+ if (usePrePost)
+ prePostEQ.processPostBlock (buffer, midiMessages);
flutter.processBlock (buffer, midiMessages);
-
+
for (int ch = 0; ch < buffer.getNumChannels(); ++ch)
lossFilter[ch]->processBlock (buffer.getWritePointer (ch), buffer.getNumSamples());
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/PrePostEQ/PrePostEQ.h"
//==============================================================================
/**
@@ -66,6 +67,7 @@ private:
AudioProcessorValueTreeState vts;
GainProcessor inGain;
+ PrePostEQ prePostEQ;
HysteresisProcessor hysteresis;
std::unique_ptr<LossFilter> lossFilter[2];
Flutter flutter;
diff --git a/Plugin/Source/Processors/GainProcessor.h b/Plugin/Source/Processors/GainProcessor.h
@@ -13,7 +13,8 @@ public:
oldGain = 0.0f;
}
- void processBlock (AudioBuffer<float>& buffer, MidiBuffer& /*midiMessages*/)
+ template <class FloatType>
+ void processBlock (AudioBuffer<FloatType>& buffer, MidiBuffer& /*midiMessages*/)
{
if (curGain != oldGain)
{
diff --git a/Plugin/Source/Processors/PrePostEQ/EQFilters.h b/Plugin/Source/Processors/PrePostEQ/EQFilters.h
@@ -0,0 +1,106 @@
+#ifndef EQFILTERS_H_INCLUDED
+#define EQFILTERS_H_INCLUDED
+
+#include "JuceHeader.h"
+
+/** First order Filter */
+class EQFilter
+{
+public:
+ EQFilter()
+ {
+ cutoff.reset (smoothSteps);
+ }
+
+ void reset (float sampleRate)
+ {
+ fs = sampleRate;
+
+ cutoff.skip (smoothSteps);
+ calcCoefs (cutoff.getCurrentValue());
+ }
+
+ void setCutoff (float newFc)
+ {
+ if (cutoff.getTargetValue() != newFc)
+ cutoff.setTargetValue (jlimit (5.0f, fs / 2.0f - 100.0f, newFc));
+ }
+
+ template <class FloatType>
+ void processBlock (FloatType* buffer, const int numSamples)
+ {
+ for (int n = 0; n < numSamples; ++n)
+ {
+ if (cutoff.isSmoothing())
+ calcCoefs (cutoff.getNextValue());
+ buffer[n] = process (buffer[n]);
+ }
+ }
+
+ template <class FloatType>
+ inline FloatType process (FloatType x)
+ {
+ FloatType y = z[1] + x * b[0];
+ z[1] = (float) x * b[1] - (float) y * a[1];
+ return y;
+ }
+
+ virtual void calcCoefs (float /*cutoff*/) = 0;
+
+protected:
+ float fs = 48000.0f;
+ float a[2] = {1.0f, 0.0f};
+ float b[2] = {1.0f, 0.0f};
+
+private:
+ SmoothedValue<float, ValueSmoothingTypes::Multiplicative> cutoff = 1.0f;
+ const int smoothSteps = 200;
+
+ float z[2] = {1.0f, 0.0f};
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EQFilter)
+};
+
+/** First order LPF */
+class LPF1 : public EQFilter
+{
+public:
+ LPF1() {}
+
+ void calcCoefs (float newFc)
+ {
+ float wc = MathConstants<float>::twoPi * newFc / fs;
+ float c = 1.0f / dsp::FastMathApproximations::tan (wc / 2.0f);
+ float a0 = c + 1.0f;
+
+ b[0] = 1.0f / a0;
+ b[1] = b[0];
+ a[1] = (1.0f - c) / a0;
+ }
+
+private:
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LPF1)
+};
+
+/** First order HPF */
+class HPF1 : public EQFilter
+{
+public:
+ HPF1() {}
+
+ void calcCoefs (float newFc)
+ {
+ float wc = MathConstants<float>::twoPi * newFc / fs;
+ float c = 1.0f / dsp::FastMathApproximations::tan (wc / 2.0f);
+ float a0 = c + 1.0f;
+
+ b[0] = c / a0;
+ b[1] = -b[0];
+ a[1] = (1.0f - c) / a0;
+ }
+
+private:
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HPF1)
+};
+
+#endif //EQFILTERS_H_INCLUDED
diff --git a/Plugin/Source/Processors/PrePostEQ/PrePostEQ.cpp b/Plugin/Source/Processors/PrePostEQ/PrePostEQ.cpp
@@ -0,0 +1,46 @@
+#include "PrePostEQ.h"
+
+void PrePostEQ::prepare (double sampleRate, int samplesPerBlock)
+{
+ for (int ch = 0; ch < 2; ++ch)
+ {
+ preEQ[ch].setCutoff (20.0f);
+ preEQ[ch].reset ((float) sampleRate);
+
+ postEQ[ch].setCutoff (20000.0f);
+ postEQ[ch].reset ((float) sampleRate);
+
+ for (int i = 0; i < 6; ++i)
+ {
+ postEQLow[ch][i].setCutoff (12000.0f);
+ postEQLow[ch][i].reset ((float) sampleRate);
+ }
+ }
+
+ preGain.setGain (Decibels::decibelsToGain (18.0f));
+ preGain.prepareToPlay (sampleRate, samplesPerBlock);
+
+ postGain.setGain (Decibels::decibelsToGain (54.0f));
+ postGain.prepareToPlay (sampleRate, samplesPerBlock);
+}
+
+void PrePostEQ::processPreBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
+{
+ preGain.processBlock (buffer, midiMessages);
+
+ for (int ch = 0; ch < 2; ++ch)
+ preEQ[ch].processBlock (buffer.getWritePointer (ch), buffer.getNumSamples());
+}
+
+void PrePostEQ::processPostBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
+{
+ for (int ch = 0; ch < 2; ++ch)
+ {
+ for (int i = 0; i < 6; ++i)
+ postEQLow[ch][i].processBlock (buffer.getWritePointer (ch), buffer.getNumSamples());
+
+ postEQ[ch].processBlock (buffer.getWritePointer (ch), buffer.getNumSamples());
+ }
+
+ postGain.processBlock (buffer, midiMessages);
+}
diff --git a/Plugin/Source/Processors/PrePostEQ/PrePostEQ.h b/Plugin/Source/Processors/PrePostEQ/PrePostEQ.h
@@ -0,0 +1,28 @@
+#ifndef PREPOSTEQ_H_INCLUDED
+#define PREPOSTEQ_H_INCLUDED
+
+#include "EQFilters.h"
+#include "../GainProcessor.h"
+
+class PrePostEQ
+{
+public:
+ PrePostEQ() {}
+ ~PrePostEQ() {}
+
+ void prepare (double sampleRate, int samplesPerBlock);
+ void processPreBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages);
+ void processPostBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages);
+
+private:
+ LPF1 preEQ[2];
+ LPF1 postEQLow[2][6];
+ HPF1 postEQ[2];
+
+ GainProcessor preGain;
+ GainProcessor postGain;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PrePostEQ)
+};
+
+#endif //PREPOSTEQ_H_INCLUDED