NeuralPi

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

commit be2c6621628db1cb578776db61f9da04c3790f64
parent 575a04b5984f9808089903174b8c6235cde63471
Author: keith <kbloemer89@gmail.com>
Date:   Thu, 17 Jun 2021 16:19:44 -0500

Added EQ controls

Diffstat:
MNeuralPi.jucer | 2++
MSource/AmpOSCReceiver.h | 54++++++++++++++++++++++++++++++++++++++++++++++++++++--
ASource/Eq4Band.cpp | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASource/Eq4Band.h | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MSource/PluginEditor.cpp | 284+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
MSource/PluginEditor.h | 22++++++++++++++++++++++
MSource/PluginProcessor.cpp | 29++++++++++++++++++++++++++++-
MSource/PluginProcessor.h | 17+++++++++++++++++
8 files changed, 537 insertions(+), 16 deletions(-)

diff --git a/NeuralPi.jucer b/NeuralPi.jucer @@ -15,6 +15,8 @@ <GROUP id="{70CE292C-E9C5-C029-B95A-F7DF41E5F74C}" name="Source"> <FILE id="VgCJPH" name="AmpOSCReceiver.h" compile="0" resource="0" file="Source/AmpOSCReceiver.h"/> + <FILE id="s1HQuK" name="Eq4Band.cpp" compile="1" resource="0" file="Source/Eq4Band.cpp"/> + <FILE id="xtLEtv" name="Eq4Band.h" compile="0" resource="0" file="Source/Eq4Band.h"/> <FILE id="hNjQV9" name="PluginEditor.cpp" compile="1" resource="0" file="Source/PluginEditor.cpp"/> <FILE id="BweFTe" name="PluginEditor.h" compile="0" resource="0" file="Source/PluginEditor.h"/> diff --git a/Source/AmpOSCReceiver.h b/Source/AmpOSCReceiver.h @@ -24,6 +24,26 @@ public: return masterValue; } + Value& getBassValue() + { + return bassValue; + } + + Value& getMidValue() + { + return midValue; + } + + Value& getTrebleValue() + { + return trebleValue; + } + + Value& getPresenceValue() + { + return presenceValue; + } + Value& getModelValue() { return modelValue; @@ -59,6 +79,10 @@ private: { gainAddressPattern = "/parameter/" + ampName + "/Gain"; masterAddressPattern = "/parameter/" + ampName + "/Master"; + bassAddressPattern = "/parameter/" + ampName + "/Bass"; + midAddressPattern = "/parameter/" + ampName + "/Mid"; + trebleAddressPattern = "/parameter/" + ampName + "/Treble"; + presenceAddressPattern = "/parameter/" + ampName + "/Presence"; modelAddressPattern = "/parameter/" + ampName + "/Model"; } @@ -78,6 +102,24 @@ private: { masterValue.setValue(jlimit(0.0f, 1.0f, message[0].getFloat32())); } + + if (message.getAddressPattern().matches(bassAddressPattern)) + { + bassValue.setValue(jlimit(0.0f, 1.0f, message[0].getFloat32())); + } + else if (message.getAddressPattern().matches(midAddressPattern)) + { + midValue.setValue(jlimit(0.0f, 1.0f, message[0].getFloat32())); + } + + if (message.getAddressPattern().matches(trebleAddressPattern)) + { + trebleValue.setValue(jlimit(0.0f, 1.0f, message[0].getFloat32())); + } + else if (message.getAddressPattern().matches(presenceAddressPattern)) + { + presenceValue.setValue(jlimit(0.0f, 1.0f, message[0].getFloat32())); + } else if (message.getAddressPattern().matches(modelAddressPattern)) { modelValue.setValue(jlimit(0.0f, 1.0f, message[0].getFloat32())); @@ -91,10 +133,18 @@ private: String ampName {"NeuralPi"}; String gainAddressPattern {"/parameter/elk_juce_example/Gain"}; String masterAddressPattern {"/parameter/elk_juce_example/Master"}; + String bassAddressPattern {"/parameter/elk_juce_example/Bass"}; + String midAddressPattern {"/parameter/elk_juce_example/Mid"}; + String trebleAddressPattern {"/parameter/elk_juce_example/Treble"}; + String presenceAddressPattern {"/parameter/elk_juce_example/Presence"}; String modelAddressPattern {"/parameter/elk_juce_example/Model"}; - Value gainValue {0.0f}; - Value masterValue {0.0f}; + Value gainValue {0.5f}; + Value masterValue {0.5f}; + Value bassValue {0.5f}; + Value midValue {0.5f}; + Value trebleValue {0.5f}; + Value presenceValue {0.5f}; Value modelValue {0.0f}; diff --git a/Source/Eq4Band.cpp b/Source/Eq4Band.cpp @@ -0,0 +1,76 @@ +/* + ============================================================================== + + Eq4Band + + ============================================================================== +*/ + +#include "Eq4Band.h" + +Eq4Band::Eq4Band() +{ + setParameters(0.0, 0.0, 0.0, 0.0); +} + +void Eq4Band::process (const float* inData, float* outData, + MidiBuffer& midiMessages, + const int numSamples, + const int numInputChannels, + const int sampleRate) +{ + // Reset params if new sampleRate detected + if (srate != sampleRate) { + srate = sampleRate; + resetSampleRate(); + } + for (int sample = 0; sample < numSamples; ++sample) { + spl0 = inData[sample]; + s0 = spl0; + low0 = (tmplMID = a0MID * s0 - b1MID * tmplMID + cDenorm); + spl0 = (tmplLOW = a0LOW * low0 - b1LOW * tmplLOW + cDenorm); + lowS0 = low0 - spl0; + hi0 = s0 - low0; + midS0 = (tmplHI = a0HI * hi0 - b1HI * tmplHI + cDenorm); + highS0 = hi0 - midS0; + spl0 = (spl0 * lVol + lowS0 * lmVol + midS0 * hmVol + highS0 * hVol);// * outVol; + + outData[sample] = spl0; + } +} + +void Eq4Band::setParameters(float bass_slider, float mid_slider, float treble_slider, float presence_slider) +{ + lVol = exp(bass_slider / cAmpDB); + lmVol = exp(mid_slider / cAmpDB); + hmVol = exp(treble_slider / cAmpDB); + hVol = exp(presence_slider / cAmpDB); + outVol = exp(0.0 / cAmpDB); + + xHI = exp(-2.0 * pi * treble_frequency / srate); + a0HI = 1.0 - xHI; + b1HI = -xHI; + + xMID = exp(-2.0 * pi * mid_frequency / srate); + a0MID = 1.0 - xMID; + b1MID = -xMID; + + xLOW = exp(-2.0 * pi * bass_frequency / srate); + a0LOW = 1.0 - xLOW; + b1LOW = -xLOW; +} + +void Eq4Band::resetSampleRate() +{ + xHI = exp(-2.0 * pi * treble_frequency / srate); + a0HI = 1.0 - xHI; + b1HI = -xHI; + + xMID = exp(-2.0 * pi * mid_frequency / srate); + a0MID = 1.0 - xMID; + b1MID = -xMID; + + xLOW = exp(-2.0 * pi * bass_frequency / srate); + a0LOW = 1.0 - xLOW; + b1LOW = -xLOW; +} +\ No newline at end of file diff --git a/Source/Eq4Band.h b/Source/Eq4Band.h @@ -0,0 +1,68 @@ +/* + ============================================================================== + + Eq4Band + + ============================================================================== +*/ + +#pragma once + +#include "../JuceLibraryCode/JuceHeader.h" + + +//============================================================================== + +class Eq4Band +{ +public: + Eq4Band(); + void process (const float* inData, float* outData, MidiBuffer& midiMessages, const int numSamples, const int numInputChannels, const int sampleRate); + void setParameters(float bass_slider, float mid_slider, float treble_slider, float presence_slider); + void resetSampleRate(); + +private: + // Tone Knob related variables + float cDenorm = 10e-30; + float cAmpDB = 8.65617025; + + int bass_frequency = 200; + int mid_frequency = 2000; + int treble_frequency = 5000; + //int presence_frequency = 5500; + + int srate = 44100; // Set default + + float pi = 3.1415926; + + float outVol; + float xHI = 0.0;// + float a0HI = 0.0;// + float b1HI = 0.0; + float xMID = 0.0; + float a0MID = 0.0; + float b1MID = 0.0; + float xLOW = 0.0; + float a0LOW = 0.0; + float b1LOW = 0.0; + + float lVol = 0.0; + float lmVol = 0.0; + float hmVol = 0.0; + float hVol = 0.0; + + float s0 = 0.0; + float low0 = 0.0; + float tmplMID = 0.0; + float spl0 = 0.0; + float hi0 = 0.0; + float midS0 = 0.0; + float highS0 = 0.0; + float tmplHI = 0.0; + float lowS0 = 0.0; + float tmplLOW = 0.0; + + + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Eq4Band) +}; diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp @@ -159,18 +159,188 @@ NeuralPiAudioProcessorEditor::NeuralPiAudioProcessorEditor (NeuralPiAudioProcess } }; + + addAndMakeVisible(ampBassKnob); + ampBassKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::TextBoxBelow, false, 50, 20); + ampBassKnob.setNumDecimalPlacesToDisplay(1); + ampBassKnob.addListener(this); + ampBassKnob.setRange(0.0, 1.0); + ampBassKnob.setValue(0.5); + ampBassKnob.setSliderStyle(juce::Slider::SliderStyle::RotaryVerticalDrag); + ampBassKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::NoTextBox, false, 50, 20); + ampBassKnob.setNumDecimalPlacesToDisplay(1); + ampBassKnob.setDoubleClickReturnValue(true, 0.5); + + auto bassValue = getParameterValue(bassName); + Slider& bassSlider = getBassSlider(); + bassSlider.setValue(bassValue, NotificationType::dontSendNotification); + + ampBassKnob.onValueChange = [this] + { + const float sliderValue = static_cast<float> (getBassSlider().getValue()); + const float bassValue = getParameterValue(bassName); + + if (!approximatelyEqual(bassValue, sliderValue)) + { + setParameterValue(bassName, sliderValue); + + // create and send an OSC message with an address and a float value: + float value = static_cast<float> (getBassSlider().getValue()); + + if (!oscSender.send(bassAddressPattern, value)) + { + updateOutConnectedLabel(false); + } + else + { + DBG("Sent value " + String(value) + " to AP " + bassAddressPattern); + } + } + }; + + addAndMakeVisible(ampMidKnob); + ampMidKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::TextBoxBelow, false, 50, 20); + ampMidKnob.setNumDecimalPlacesToDisplay(1); + ampMidKnob.addListener(this); + ampMidKnob.setRange(0.0, 1.0); + ampMidKnob.setValue(0.5); + ampMidKnob.setSliderStyle(juce::Slider::SliderStyle::RotaryVerticalDrag); + ampMidKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::NoTextBox, false, 50, 20); + ampMidKnob.setNumDecimalPlacesToDisplay(1); + ampMidKnob.setDoubleClickReturnValue(true, 0.5); + + auto midValue = getParameterValue(midName); + Slider& midSlider = getMidSlider(); + midSlider.setValue(midValue, NotificationType::dontSendNotification); + + ampMidKnob.onValueChange = [this] + { + const float sliderValue = static_cast<float> (getMidSlider().getValue()); + const float midValue = getParameterValue(midName); + + if (!approximatelyEqual(midValue, sliderValue)) + { + setParameterValue(midName, sliderValue); + + // create and send an OSC message with an address and a float value: + float value = static_cast<float> (getMidSlider().getValue()); + + if (!oscSender.send(midAddressPattern, value)) + { + updateOutConnectedLabel(false); + } + else + { + DBG("Sent value " + String(value) + " to AP " + midAddressPattern); + } + } + }; + + addAndMakeVisible(ampTrebleKnob); + ampTrebleKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::TextBoxBelow, false, 50, 20); + ampTrebleKnob.setNumDecimalPlacesToDisplay(1); + ampTrebleKnob.addListener(this); + ampTrebleKnob.setRange(0.0, 1.0); + ampTrebleKnob.setValue(0.5); + ampTrebleKnob.setSliderStyle(juce::Slider::SliderStyle::RotaryVerticalDrag); + ampTrebleKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::NoTextBox, false, 50, 20); + ampTrebleKnob.setNumDecimalPlacesToDisplay(1); + ampTrebleKnob.setDoubleClickReturnValue(true, 0.5); + + auto trebleValue = getParameterValue(trebleName); + Slider& trebleSlider = getTrebleSlider(); + trebleSlider.setValue(trebleValue, NotificationType::dontSendNotification); + + ampTrebleKnob.onValueChange = [this] + { + const float sliderValue = static_cast<float> (getTrebleSlider().getValue()); + const float trebleValue = getParameterValue(trebleName); + + if (!approximatelyEqual(trebleValue, sliderValue)) + { + setParameterValue(trebleName, sliderValue); + + // create and send an OSC message with an address and a float value: + float value = static_cast<float> (getTrebleSlider().getValue()); + + if (!oscSender.send(trebleAddressPattern, value)) + { + updateOutConnectedLabel(false); + } + else + { + DBG("Sent value " + String(value) + " to AP " + trebleAddressPattern); + } + } + }; + + addAndMakeVisible(ampPresenceKnob); + ampPresenceKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::TextBoxBelow, false, 50, 20); + ampPresenceKnob.setNumDecimalPlacesToDisplay(1); + ampPresenceKnob.addListener(this); + ampPresenceKnob.setRange(0.0, 1.0); + ampPresenceKnob.setValue(0.5); + ampPresenceKnob.setSliderStyle(juce::Slider::SliderStyle::RotaryVerticalDrag); + ampPresenceKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::NoTextBox, false, 50, 20); + ampPresenceKnob.setNumDecimalPlacesToDisplay(1); + ampPresenceKnob.setDoubleClickReturnValue(true, 0.5); + + auto presenceValue = getParameterValue(trebleName); + Slider& presenceSlider = getPresenceSlider(); + trebleSlider.setValue(presenceValue, NotificationType::dontSendNotification); + + ampPresenceKnob.onValueChange = [this] + { + const float sliderValue = static_cast<float> (getPresenceSlider().getValue()); + const float presenceValue = getParameterValue(presenceName); + + if (!approximatelyEqual(presenceValue, sliderValue)) + { + setParameterValue(presenceName, sliderValue); + + // create and send an OSC message with an address and a float value: + float value = static_cast<float> (getPresenceSlider().getValue()); + + if (!oscSender.send(presenceAddressPattern, value)) + { + updateOutConnectedLabel(false); + } + else + { + DBG("Sent value " + String(value) + " to AP " + presenceAddressPattern); + } + } + }; + addAndMakeVisible(GainLabel); GainLabel.setText("Gain", juce::NotificationType::dontSendNotification); GainLabel.setJustificationType(juce::Justification::centred); addAndMakeVisible(LevelLabel); LevelLabel.setText("Level", juce::NotificationType::dontSendNotification); LevelLabel.setJustificationType(juce::Justification::centred); + + addAndMakeVisible(BassLabel); + BassLabel.setText("Bass", juce::NotificationType::dontSendNotification); + BassLabel.setJustificationType(juce::Justification::centred); + addAndMakeVisible(MidLabel); + MidLabel.setText("Mid", juce::NotificationType::dontSendNotification); + MidLabel.setJustificationType(juce::Justification::centred); + addAndMakeVisible(TrebleLabel); + TrebleLabel.setText("Treble", juce::NotificationType::dontSendNotification); + TrebleLabel.setJustificationType(juce::Justification::centred); + addAndMakeVisible(PresenceLabel); + PresenceLabel.setText("Presence", juce::NotificationType::dontSendNotification); + PresenceLabel.setJustificationType(juce::Justification::centred); + auto font = GainLabel.getFont(); float height = font.getHeight(); font.setHeight(height); // 0.75); GainLabel.setFont(font); LevelLabel.setFont(font); - + BassLabel.setFont(font); + MidLabel.setFont(font); + TrebleLabel.setFont(font); + PresenceLabel.setFont(font); // Name controls: addAndMakeVisible(ampNameLabel); @@ -204,6 +374,11 @@ NeuralPiAudioProcessorEditor::NeuralPiAudioProcessorEditor (NeuralPiAudioProcess oscReceiver.getGainValue().addListener(this); oscReceiver.getMasterValue().addListener(this); + oscReceiver.getBassValue().addListener(this); + oscReceiver.getMidValue().addListener(this); + oscReceiver.getTrebleValue().addListener(this); + oscReceiver.getPresenceValue().addListener(this); + oscReceiver.getModelValue().addListener(this); updateInConnectedLabel(); @@ -211,7 +386,7 @@ NeuralPiAudioProcessorEditor::NeuralPiAudioProcessorEditor (NeuralPiAudioProcess connectSender(); // Size of plugin GUI - setSize(250, 350); + setSize(250, 430); } @@ -235,24 +410,33 @@ void NeuralPiAudioProcessorEditor::resized() modelKnob.setBounds(140, 40, 75, 95); // Amp Widgets - ampGainKnob.setBounds(30, 85, 75, 95); - ampMasterKnob.setBounds(140, 85, 75, 95); - GainLabel.setBounds(28, 163, 80, 10); - LevelLabel.setBounds(138, 163, 80, 10); + ampGainKnob.setBounds(30, 72, 75, 95); + ampMasterKnob.setBounds(140, 72, 75, 95); + ampBassKnob.setBounds(30, 155, 75, 95); + ampMidKnob.setBounds(140, 155, 75, 95); + ampTrebleKnob.setBounds(30, 235, 75, 95); + ampPresenceKnob.setBounds(140, 235, 75, 95); + + GainLabel.setBounds(28, 150, 80, 10); + LevelLabel.setBounds(138, 150, 80, 10); + BassLabel.setBounds(28, 233, 80, 10); + MidLabel.setBounds(138, 233, 80, 10); + TrebleLabel.setBounds(28, 313, 80, 10); + PresenceLabel.setBounds(138, 313, 80, 10); addAndMakeVisible(ampNameLabel); ampNameField.setEditable(true, true, true); addAndMakeVisible(ampNameField); // IP controls: - ipField.setBounds(150, 220, 100, 25); - ipLabel.setBounds(15, 220, 150, 25); + ipField.setBounds(150, 330, 100, 25); + ipLabel.setBounds(15, 330, 150, 25); // Port controls: - outPortNumberLabel.setBounds(15, 260, 150, 25); - outPortNumberField.setBounds(160, 260, 75, 25); - inPortNumberLabel.setBounds(15, 300, 150, 25); - inPortNumberField.setBounds(160, 300, 75, 25); + outPortNumberLabel.setBounds(15, 365, 150, 25); + outPortNumberField.setBounds(160, 365, 75, 25); + inPortNumberLabel.setBounds(15, 400, 150, 25); + inPortNumberField.setBounds(160, 400, 75, 25); } void NeuralPiAudioProcessorEditor::modelSelectChanged() @@ -316,8 +500,22 @@ void NeuralPiAudioProcessorEditor::sliderValueChanged(Slider* slider) if (slider == &modelKnob) if (slider->getValue() >= 0 && slider->getValue() < processor.jsonFiles.size()) { modelSelect.setSelectedItemIndex(processor.getModelIndex(slider->getValue()), juce::NotificationType::dontSendNotification); - } + } } +/* + else if (slider == &ampBassKnob || slider == &ampMidKnob || slider == &ampTrebleKnob) { + processor.set_ampEQ(ampBassKnob.getValue(), ampMidKnob.getValue(), ampTrebleKnob.getValue(), ampPresenceKnob.getValue()); + // Set knob states for saving positions when closing/reopening GUI + processor.ampBassKnobState = ampBassKnob.getValue(); + processor.ampMidKnobState = ampMidKnob.getValue(); + processor.ampTrebleKnobState = ampTrebleKnob.getValue(); + } + else if (slider == &ampPresenceKnob) { + processor.set_ampEQ(ampBassKnob.getValue(), ampMidKnob.getValue(), ampTrebleKnob.getValue(), ampPresenceKnob.getValue()); + } +} +*/ + // OSC Messages Slider& NeuralPiAudioProcessorEditor::getGainSlider() @@ -330,6 +528,26 @@ Slider& NeuralPiAudioProcessorEditor::getMasterSlider() return ampMasterKnob; } +Slider& NeuralPiAudioProcessorEditor::getBassSlider() +{ + return ampBassKnob; +} + +Slider& NeuralPiAudioProcessorEditor::getMidSlider() +{ + return ampMidKnob; +} + +Slider& NeuralPiAudioProcessorEditor::getTrebleSlider() +{ + return ampTrebleKnob; +} + +Slider& NeuralPiAudioProcessorEditor::getPresenceSlider() +{ + return ampPresenceKnob; +} + Slider& NeuralPiAudioProcessorEditor::getModelSlider() { return modelKnob; @@ -370,6 +588,10 @@ void NeuralPiAudioProcessorEditor::buildAddressPatterns() { gainAddressPattern = "/parameter/" + ampName + "/Gain"; masterAddressPattern = "/parameter/" + ampName + "/Master"; + bassAddressPattern = "/parameter/" + ampName + "/Bass"; + midAddressPattern = "/parameter/" + ampName + "/Mid"; + trebleAddressPattern = "/parameter/" + ampName + "/Treble"; + presenceAddressPattern = "/parameter/" + ampName + "/Presence"; modelAddressPattern = "/parameter/" + ampName + "/Model"; } @@ -470,6 +692,38 @@ void NeuralPiAudioProcessorEditor::valueChanged(Value& value) NotificationType::sendNotification); } } + if (value.refersToSameSourceAs(oscReceiver.getBassValue())) + { + if (!approximatelyEqual(static_cast<double> (value.getValue()), getBassSlider().getValue())) + { + getBassSlider().setValue(static_cast<double> (value.getValue()), + NotificationType::sendNotification); + } + } + else if (value.refersToSameSourceAs(oscReceiver.getMidValue())) + { + if (!approximatelyEqual(static_cast<double> (value.getValue()), getMidSlider().getValue())) + { + getMidSlider().setValue(static_cast<double> (value.getValue()), + NotificationType::sendNotification); + } + } + if (value.refersToSameSourceAs(oscReceiver.getTrebleValue())) + { + if (!approximatelyEqual(static_cast<double> (value.getValue()), getTrebleSlider().getValue())) + { + getTrebleSlider().setValue(static_cast<double> (value.getValue()), + NotificationType::sendNotification); + } + } + else if (value.refersToSameSourceAs(oscReceiver.getPresenceValue())) + { + if (!approximatelyEqual(static_cast<double> (value.getValue()), getPresenceSlider().getValue())) + { + getPresenceSlider().setValue(static_cast<double> (value.getValue()), + NotificationType::sendNotification); + } + } else if (value.refersToSameSourceAs(oscReceiver.getModelValue())) { if (!approximatelyEqual(static_cast<double> (value.getValue()), getModelSlider().getValue())) @@ -484,6 +738,10 @@ void NeuralPiAudioProcessorEditor::timerCallback() { getGainSlider().setValue(getParameterValue(gainName), NotificationType::dontSendNotification); getMasterSlider().setValue(getParameterValue(masterName), NotificationType::dontSendNotification); + getBassSlider().setValue(getParameterValue(bassName), NotificationType::dontSendNotification); + getMidSlider().setValue(getParameterValue(midName), NotificationType::dontSendNotification); + getTrebleSlider().setValue(getParameterValue(trebleName), NotificationType::dontSendNotification); + getPresenceSlider().setValue(getParameterValue(presenceName), NotificationType::dontSendNotification); getModelSlider().setValue(getParameterValue(modelName), NotificationType::dontSendNotification); } diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h @@ -46,9 +46,17 @@ public: String gainAddressPattern{ "/parameter/NeuralPi/Gain" }; String masterAddressPattern{ "/parameter/NeuralPi/Master" }; String modelAddressPattern{ "/parameter/NeuralPi/Model" }; + String bassAddressPattern{ "/parameter/NeuralPi/Bass" }; + String midAddressPattern{ "/parameter/NeuralPi/Mid" }; + String trebleAddressPattern{ "/parameter/NeuralPi/Treble" }; + String presenceAddressPattern{ "/parameter/NeuralPi/Presence" }; const String gainName{ "gain" }; const String masterName{ "master" }; + const String bassName{ "bass" }; + const String midName{ "mid" }; + const String trebleName{ "treble" }; + const String presenceName{ "presence" }; const String modelName{ "model" }; @@ -65,8 +73,17 @@ private: //ImageButton ampOnButton; //ImageButton ampLED; ComboBox modelSelect; + Slider ampBassKnob; + Slider ampMidKnob; + Slider ampTrebleKnob; + Slider ampPresenceKnob; + Label GainLabel; Label LevelLabel; + Label BassLabel; + Label MidLabel; + Label TrebleLabel; + Label PresenceLabel; File test_file; File model_folder; @@ -103,6 +120,11 @@ private: Slider& getGainSlider(); Slider& getMasterSlider(); Slider& getModelSlider(); + Slider& getBassSlider(); + Slider& getMidSlider(); + Slider& getTrebleSlider(); + Slider& getPresenceSlider(); + Label& getOutPortNumberField(); Label& getInPortNumberField(); Label& getIPField(); diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp @@ -40,6 +40,10 @@ NeuralPiAudioProcessor::NeuralPiAudioProcessor() // initialize parameters: addParameter(gainParam = new AudioParameterFloat(GAIN_ID, GAIN_NAME, NormalisableRange<float>(0.0f, 1.0f, 0.01f), 0.5f)); addParameter(masterParam = new AudioParameterFloat(MASTER_ID, MASTER_NAME, NormalisableRange<float>(0.0f, 1.0f, 0.01f), 0.5f)); + addParameter(bassParam = new AudioParameterFloat(BASS_ID, BASS_NAME, NormalisableRange<float>(0.0f, 1.0f, 0.01f), 0.5f)); + addParameter(midParam = new AudioParameterFloat(MID_ID, MID_NAME, NormalisableRange<float>(0.0f, 1.0f, 0.01f), 0.5f)); + addParameter(trebleParam = new AudioParameterFloat(TREBLE_ID, TREBLE_NAME, NormalisableRange<float>(0.0f, 1.0f, 0.01f), 0.5f)); + addParameter(presenceParam = new AudioParameterFloat(PRESENCE_ID, PRESENCE_NAME, NormalisableRange<float>(0.0f, 1.0f, 0.01f), 0.5f)); addParameter(modelParam = new AudioParameterFloat(MODEL_ID, MODEL_NAME, NormalisableRange<float>(0.0f, 1.0f, 0.001f), 0.0f)); } @@ -156,17 +160,26 @@ void NeuralPiAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffe // Setup Audio Data const int numSamples = buffer.getNumSamples(); const int numInputChannels = getTotalNumInputChannels(); + const int sampleRate = getSampleRate(); // Amp ============================================================================= if (amp_state == 1) { auto gain = static_cast<float> (gainParam->get()); auto master = static_cast<float> (masterParam->get()); + // Note: Default 0.0 -> 1.0 param range is converted to +-8.0 here + auto bass = (static_cast<float> (bassParam->get() - 0.5) * 8.0); + auto mid = (static_cast<float> (midParam->get() - 0.5) * 8.0); + auto treble = (static_cast<float> (trebleParam->get() - 0.5) * 8.0); + auto presence = (static_cast<float> (presenceParam->get() - 0.5) * 8.0); + auto model = static_cast<float> (modelParam->get()); model_index = getModelIndex(model); buffer.applyGain(gain); + eq4band.setParameters(bass, mid, treble, presence);// Better to move this somewhere else? Only need to set when value changes + eq4band.process(buffer.getReadPointer(0), buffer.getWritePointer(0), midiMessages, numSamples, numInputChannels, sampleRate); - // Apply LSTM model + // Apply LSTM model if (model_loaded == 1) { if (current_model_index != model_index) { loadConfig(jsonFiles[model_index]); @@ -201,6 +214,10 @@ void NeuralPiAudioProcessor::getStateInformation(MemoryBlock& destData) stream.writeFloat(*gainParam); stream.writeFloat(*masterParam); + stream.writeFloat(*bassParam); + stream.writeFloat(*midParam); + stream.writeFloat(*trebleParam); + stream.writeFloat(*presenceParam); stream.writeFloat(*modelParam); } @@ -210,6 +227,10 @@ void NeuralPiAudioProcessor::setStateInformation(const void* data, int sizeInByt gainParam->setValueNotifyingHost(stream.readFloat()); masterParam->setValueNotifyingHost(stream.readFloat()); + bassParam->setValueNotifyingHost(stream.readFloat()); + midParam->setValueNotifyingHost(stream.readFloat()); + trebleParam->setValueNotifyingHost(stream.readFloat()); + presenceParam->setValueNotifyingHost(stream.readFloat()); modelParam->setValueNotifyingHost(stream.readFloat()); } @@ -225,6 +246,7 @@ void NeuralPiAudioProcessor::loadConfig(File configFile) model_loaded = 1; String path = configFile.getFullPathName(); char_filename = path.toUTF8(); + // TODO Add check here for invalid files LSTM.load_json(char_filename); @@ -322,6 +344,11 @@ void NeuralPiAudioProcessor::installTones() } +void NeuralPiAudioProcessor::set_ampEQ(float bass_slider, float mid_slider, float treble_slider, float presence_slider) +{ + eq4band.setParameters(bass_slider, mid_slider, treble_slider, presence_slider); +} + float NeuralPiAudioProcessor::convertLogScale(float in_value, float x_min, float x_max, float y_min, float y_max) { float b = log(y_max / y_min) / (x_max - x_min); diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h @@ -11,6 +11,7 @@ #include <nlohmann/json.hpp> #include "RTNeuralLSTM.h" #include "AmpOSCReceiver.h" +#include "Eq4Band.h" #pragma once @@ -22,6 +23,14 @@ #define MODEL_NAME "Model" #define MASTER_ID "master" #define MASTER_NAME "Master" +#define BASS_ID "bass" +#define BASS_NAME "Bass" +#define MID_ID "mid" +#define MID_NAME "Mid" +#define TREBLE_ID "treble" +#define TREBLE_NAME "Treble" +#define PRESENCE_ID "presence" +#define PRESENCE_NAME "Presence" //============================================================================== /** @@ -71,6 +80,8 @@ public: void loadConfig(File configFile); void setupDataDirectories(); void installTones(); + + void set_ampEQ(float bass_slider, float mid_slider, float treble_slider, float presence_slider); // Overdrive Pedal float convertLogScale(float in_value, float x_min, float x_max, float y_min, float y_max); @@ -79,6 +90,7 @@ public: /* void set_ampDrive(float db_ampCleanDrive); void set_ampMaster(float db_ampMaster); + void set_ampEQ(float bass_slider, float mid_slider, float treble_slider, float presence_slider); */ float decibelToLinear(float dbValue); @@ -104,9 +116,14 @@ public: private: var dummyVar; + Eq4Band eq4band; // Amp EQ AudioParameterFloat* gainParam; AudioParameterFloat* masterParam; + AudioParameterFloat* bassParam; + AudioParameterFloat* midParam; + AudioParameterFloat* trebleParam; + AudioParameterFloat* presenceParam; AudioParameterFloat* modelParam; //==============================================================================