NeuralPi

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

commit b2b7a6d72cb03d833ac0a88f4ebcbb6a58bedd32
parent 8095754ad2c94f93e8e3e9cb50622866d39cf01d
Author: keith <kbloemer89@gmail.com>
Date:   Thu, 12 Aug 2021 06:24:59 -0500

Added Delay and Reverb using juce dsp class

Diffstat:
MNeuralPi.jucer | 1+
MSource/AmpOSCReceiver.h | 26+++++++++++++++++++++++++-
MSource/CMakeLists.txt | 1+
ASource/Delay.h | 216+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MSource/PluginEditor.cpp | 135++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
MSource/PluginEditor.h | 10++++++++++
MSource/PluginProcessor.cpp | 46+++++++++++++++++++++++++++++++++++++++++++++-
MSource/PluginProcessor.h | 20++++++++++++++++++++
8 files changed, 446 insertions(+), 9 deletions(-)

diff --git a/NeuralPi.jucer b/NeuralPi.jucer @@ -17,6 +17,7 @@ <FILE id="VgCJPH" name="AmpOSCReceiver.h" compile="0" resource="0" file="Source/AmpOSCReceiver.h"/> <FILE id="HvJFu8" name="CabSim.h" compile="0" resource="0" file="Source/CabSim.h"/> + <FILE id="gT1tOY" name="Delay.h" compile="0" resource="0" file="Source/Delay.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" diff --git a/Source/AmpOSCReceiver.h b/Source/AmpOSCReceiver.h @@ -54,6 +54,16 @@ public: return irValue; } + Value& getDelayValue() + { + return delayValue; + } + + Value& getReverbValue() + { + return reverbValue; + } + void changePort (int port) { if (! connect (port)) @@ -90,6 +100,8 @@ private: presenceAddressPattern = "/parameter/" + ampName + "/Presence"; modelAddressPattern = "/parameter/" + ampName + "/Model"; irAddressPattern = "/parameter/" + ampName + "/Ir"; + reverbAddressPattern = "/parameter/" + ampName + "/Reverb"; + delayAddressPattern = "/parameter/" + ampName + "/Delay"; } void oscMessageReceived(const OSCMessage& message) override @@ -134,7 +146,14 @@ private: { irValue.setValue(jlimit(0.0f, 1.0f, message[0].getFloat32())); } - + else if (message.getAddressPattern().matches(reverbAddressPattern)) + { + reverbValue.setValue(jlimit(0.0f, 1.0f, message[0].getFloat32())); + } + else if (message.getAddressPattern().matches(delayAddressPattern)) + { + delayValue.setValue(jlimit(0.0f, 1.0f, message[0].getFloat32())); + } } } @@ -149,6 +168,8 @@ private: String presenceAddressPattern {"/parameter/elk_juce_example/Presence"}; String modelAddressPattern {"/parameter/elk_juce_example/Model"}; String irAddressPattern {"/parameter/elk_juce_example/Ir"}; + String delayAddressPattern {"/parameter/elk_juce_example/Delay"}; + String reverbAddressPattern {"/parameter/elk_juce_example/Reverb"}; Value gainValue {0.5f}; Value masterValue {0.5f}; @@ -160,6 +181,9 @@ private: Value modelValue {0.0f}; Value irValue {0.0f}; + Value delayValue {0.0f}; + Value reverbValue {0.0f}; + bool connected = false; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AmpOSCReceiver) diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt @@ -2,6 +2,7 @@ target_sources(NeuralPi PRIVATE AmpOSCReceiver.h + Delay.h Eq4Band.cpp Eq4Band.h PluginEditor.cpp diff --git a/Source/Delay.h b/Source/Delay.h @@ -0,0 +1,215 @@ +/* + ============================================================================== + + Delay + + ============================================================================== +*/ +#include "../JuceLibraryCode/JuceHeader.h" + +#pragma once + +//============================================================================== +template <typename Type> +class DelayLine +{ +public: + void clear() noexcept + { + std::fill (rawData.begin(), rawData.end(), Type (0)); + } + + size_t size() const noexcept + { + return rawData.size(); + } + + void resize (size_t newValue) + { + rawData.resize (newValue); + leastRecentIndex = 0; + } + + Type back() const noexcept + { + return rawData[leastRecentIndex]; + } + + Type get (size_t delayInSamples) const noexcept + { + jassert (delayInSamples >= 0 && delayInSamples < size()); + + return rawData[(leastRecentIndex + 1 + delayInSamples) % size()]; // [3] + } + + /** Set the specified sample in the delay line */ + void set (size_t delayInSamples, Type newValue) noexcept + { + jassert (delayInSamples >= 0 && delayInSamples < size()); + + rawData[(leastRecentIndex + 1 + delayInSamples) % size()] = newValue; // [4] + } + + /** Adds a new value to the delay line, overwriting the least recently added sample */ + void push (Type valueToAdd) noexcept + { + rawData[leastRecentIndex] = valueToAdd; // [1] + leastRecentIndex = leastRecentIndex == 0 ? size() - 1 : leastRecentIndex - 1; // [2] + } + +private: + std::vector<Type> rawData; + size_t leastRecentIndex = 0; +}; + +//============================================================================== +template <typename Type, size_t maxNumChannels = 2> +class Delay +{ +public: + //============================================================================== + Delay() + { + setMaxDelayTime (2.0f); + setDelayTime (0, 0.7f); + setDelayTime (1, 0.5f); + setWetLevel (0.8f); + setFeedback (0.5f); + } + + //============================================================================== + void prepare (const juce::dsp::ProcessSpec& spec) + { + jassert (spec.numChannels <= maxNumChannels); + sampleRate = (Type) spec.sampleRate; + updateDelayLineSize(); + updateDelayTime(); + + //filterCoefs = juce::dsp::IIR::Coefficients<Type>::makeFirstOrderLowPass (sampleRate, Type (1e3)); + filterCoefs = juce::dsp::IIR::Coefficients<Type>::makeFirstOrderHighPass (sampleRate, Type (1e3)); + + for (auto& f : filters) + { + f.prepare (spec); + f.coefficients = filterCoefs; + } + } + + //============================================================================== + void reset() noexcept + { + for (auto& f : filters) + f.reset(); // [5] + + for (auto& dline : delayLines) + dline.clear(); // [6] + } + + //============================================================================== + size_t getNumChannels() const noexcept + { + return delayLines.size(); + } + + //============================================================================== + void setMaxDelayTime (Type newValue) + { + jassert (newValue > Type (0)); + maxDelayTime = newValue; + updateDelayLineSize(); // [1] + } + + //============================================================================== + void setFeedback (Type newValue) noexcept + { + jassert (newValue >= Type (0) && newValue <= Type (1)); + feedback = newValue; + } + + //============================================================================== + void setWetLevel (Type newValue) noexcept + { + jassert (newValue >= Type (0) && newValue <= Type (1)); + wetLevel = newValue; + } + + //============================================================================== + void setDelayTime (size_t channel, Type newValue) + { + if (channel >= getNumChannels()) + { + jassertfalse; + return; + } + + jassert (newValue >= Type (0)); + delayTimes[channel] = newValue; + + updateDelayTime(); // [3] + } + + //============================================================================== + template <typename ProcessContext> + void process (const ProcessContext& context) noexcept + { + auto& inputBlock = context.getInputBlock(); + auto& outputBlock = context.getOutputBlock(); + auto numSamples = outputBlock.getNumSamples(); + auto numChannels = outputBlock.getNumChannels(); + + jassert (inputBlock.getNumSamples() == numSamples); + jassert (inputBlock.getNumChannels() == numChannels); + + for (size_t ch = 0; ch < numChannels; ++ch) + { + auto* input = inputBlock .getChannelPointer (ch); + auto* output = outputBlock.getChannelPointer (ch); + auto& dline = delayLines[ch]; + auto delayTime = delayTimesSample[ch]; + auto& filter = filters[ch]; + + for (size_t i = 0; i < numSamples; ++i) + { + //auto delayedSample = dline.get (delayTime); + auto delayedSample = filter.processSample (dline.get (delayTime)); + auto inputSample = input[i]; + auto dlineInputSample = std::tanh (inputSample + feedback * delayedSample); + dline.push (dlineInputSample); + auto outputSample = inputSample + wetLevel * delayedSample; + output[i] = outputSample; + } + } + } + +private: + //============================================================================== + std::array<DelayLine<Type>, maxNumChannels> delayLines; + std::array<size_t, maxNumChannels> delayTimesSample; + std::array<Type, maxNumChannels> delayTimes; + Type feedback { Type (0) }; + Type wetLevel { Type (0) }; + + std::array<juce::dsp::IIR::Filter<Type>, maxNumChannels> filters; + typename juce::dsp::IIR::Coefficients<Type>::Ptr filterCoefs; + + Type sampleRate { Type (44.1e3) }; + Type maxDelayTime { Type (2) }; + + //============================================================================== + void updateDelayLineSize() + { + auto delayLineSizeSamples = (size_t) std::ceil (maxDelayTime * sampleRate); + + for (auto& dline : delayLines) + dline.resize (delayLineSizeSamples); // [2] + } + + //============================================================================== + void updateDelayTime() noexcept + { + for (size_t ch = 0; ch < maxNumChannels; ++ch) + delayTimesSample[ch] = (size_t) juce::roundToInt (delayTimes[ch] * sampleRate); + } + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Delay) +}; +\ No newline at end of file diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp @@ -381,6 +381,82 @@ NeuralPiAudioProcessorEditor::NeuralPiAudioProcessorEditor (NeuralPiAudioProcess } }; + addAndMakeVisible(ampDelayKnob); + ampDelayKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::TextBoxBelow, false, 50, 20); + ampDelayKnob.setNumDecimalPlacesToDisplay(1); + ampDelayKnob.addListener(this); + ampDelayKnob.setRange(0.0, 1.0); + ampDelayKnob.setValue(0.0); + ampDelayKnob.setSliderStyle(juce::Slider::SliderStyle::RotaryVerticalDrag); + ampDelayKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::TextBoxBelow, false, 50, 20); + ampDelayKnob.setNumDecimalPlacesToDisplay(2); + ampDelayKnob.setDoubleClickReturnValue(true, 0.0); + + auto delayValue = getParameterValue(delayName); + Slider& delaySlider = getDelaySlider(); + delaySlider.setValue(delayValue, NotificationType::dontSendNotification); + + ampDelayKnob.onValueChange = [this] + { + const float sliderValue = static_cast<float> (getDelaySlider().getValue()); + const float delayValue = getParameterValue(delayName); + + if (!approximatelyEqual(delayValue, sliderValue)) + { + setParameterValue(delayName, sliderValue); + + // create and send an OSC message with an address and a float value: + float value = static_cast<float> (getDelaySlider().getValue()); + + if (!oscSender.send(delayAddressPattern, value)) + { + updateOutConnectedLabel(false); + } + else + { + DBG("Sent value " + String(value) + " to AP " + delayAddressPattern); + } + } + }; + + addAndMakeVisible(ampReverbKnob); + ampReverbKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::TextBoxBelow, false, 50, 20); + ampReverbKnob.setNumDecimalPlacesToDisplay(1); + ampReverbKnob.addListener(this); + ampReverbKnob.setRange(0.0, 1.0); + ampReverbKnob.setValue(0.0); + ampReverbKnob.setSliderStyle(juce::Slider::SliderStyle::RotaryVerticalDrag); + ampReverbKnob.setTextBoxStyle(juce::Slider::TextEntryBoxPosition::TextBoxBelow, false, 50, 20); + ampReverbKnob.setNumDecimalPlacesToDisplay(2); + ampReverbKnob.setDoubleClickReturnValue(true, 0.0); + + auto reverbValue = getParameterValue(reverbName); + Slider& reverbSlider = getReverbSlider(); + reverbSlider.setValue(reverbValue, NotificationType::dontSendNotification); + + ampReverbKnob.onValueChange = [this] + { + const float sliderValue = static_cast<float> (getReverbSlider().getValue()); + const float reverbValue = getParameterValue(reverbName); + + if (!approximatelyEqual(reverbValue, sliderValue)) + { + setParameterValue(reverbName, sliderValue); + + // create and send an OSC message with an address and a float value: + float value = static_cast<float> (getReverbSlider().getValue()); + + if (!oscSender.send(reverbAddressPattern, value)) + { + updateOutConnectedLabel(false); + } + else + { + DBG("Sent value " + String(value) + " to AP " + reverbAddressPattern); + } + } + }; + addAndMakeVisible(GainLabel); GainLabel.setText("Gain", juce::NotificationType::dontSendNotification); GainLabel.setJustificationType(juce::Justification::centred); @@ -401,6 +477,13 @@ NeuralPiAudioProcessorEditor::NeuralPiAudioProcessorEditor (NeuralPiAudioProcess PresenceLabel.setText("Presence", juce::NotificationType::dontSendNotification); PresenceLabel.setJustificationType(juce::Justification::centred); + addAndMakeVisible(DelayLabel); + DelayLabel.setText("Delay", juce::NotificationType::dontSendNotification); + DelayLabel.setJustificationType(juce::Justification::centred); + addAndMakeVisible(ReverbLabel); + ReverbLabel.setText("Reverb", juce::NotificationType::dontSendNotification); + ReverbLabel.setJustificationType(juce::Justification::centred); + auto font = GainLabel.getFont(); float height = font.getHeight(); font.setHeight(height); // 0.75); @@ -410,6 +493,8 @@ NeuralPiAudioProcessorEditor::NeuralPiAudioProcessorEditor (NeuralPiAudioProcess MidLabel.setFont(font); TrebleLabel.setFont(font); PresenceLabel.setFont(font); + DelayLabel.setFont(font); + ReverbLabel.setFont(font); // Name controls: addAndMakeVisible(ampNameLabel); @@ -456,7 +541,7 @@ NeuralPiAudioProcessorEditor::NeuralPiAudioProcessorEditor (NeuralPiAudioProcess connectSender(); // Size of plugin GUI - setSize(260, 455); + setSize(345, 455); } NeuralPiAudioProcessorEditor::~NeuralPiAudioProcessorEditor() @@ -481,12 +566,12 @@ void NeuralPiAudioProcessorEditor::resized() { // This is generally where you'll want to lay out the positions of any // subcomponents in your editor.. - modelSelect.setBounds(11, 10, 234, 25); - loadButton.setBounds(19, 74, 100, 25); + modelSelect.setBounds(11, 10, 270, 25); + loadButton.setBounds(11, 74, 100, 25); modelKnob.setBounds(140, 40, 75, 95); - irSelect.setBounds(11, 42, 234, 25); - loadIR.setBounds(125, 74, 100, 25); + irSelect.setBounds(11, 42, 270, 25); + loadIR.setBounds(120, 74, 100, 25); irButton.setBounds(248, 42, 257, 25); lstmButton.setBounds(248, 10, 257, 25); @@ -496,14 +581,20 @@ void NeuralPiAudioProcessorEditor::resized() ampBassKnob.setBounds(10, 250, 75, 95); ampMidKnob.setBounds(95, 250, 75, 95); ampTrebleKnob.setBounds(180, 250, 75, 95); - ampPresenceKnob.setBounds(180, 120, 75, 95); + ampPresenceKnob.setBounds(265, 250, 75, 95); + + ampDelayKnob.setBounds(180, 120, 75, 95); + ampReverbKnob.setBounds(265, 120, 75, 95); GainLabel.setBounds(6, 108, 80, 10); LevelLabel.setBounds(93, 108, 80, 10); BassLabel.setBounds(6, 238, 80, 10); MidLabel.setBounds(91, 238, 80, 10); TrebleLabel.setBounds(178, 238, 80, 10); - PresenceLabel.setBounds(178, 108, 80, 10); + PresenceLabel.setBounds(265, 238, 80, 10); + + DelayLabel.setBounds(178, 108, 80, 10); + ReverbLabel.setBounds(265, 108, 80, 10); addAndMakeVisible(ampNameLabel); ampNameField.setEditable(true, true, true); @@ -681,6 +772,16 @@ Slider& NeuralPiAudioProcessorEditor::getPresenceSlider() return ampPresenceKnob; } +Slider& NeuralPiAudioProcessorEditor::getDelaySlider() +{ + return ampDelayKnob; +} + +Slider& NeuralPiAudioProcessorEditor::getReverbSlider() +{ + return ampReverbKnob; +} + Slider& NeuralPiAudioProcessorEditor::getModelSlider() { return modelKnob; @@ -730,6 +831,8 @@ void NeuralPiAudioProcessorEditor::buildAddressPatterns() midAddressPattern = "/parameter/" + ampName + "/Mid"; trebleAddressPattern = "/parameter/" + ampName + "/Treble"; presenceAddressPattern = "/parameter/" + ampName + "/Presence"; + delayAddressPattern = "/parameter/" + ampName + "/Delay"; + reverbAddressPattern = "/parameter/" + ampName + "/Reverb"; modelAddressPattern = "/parameter/" + ampName + "/Model"; irAddressPattern = "/parameter/" + ampName + "/Ir"; } @@ -863,6 +966,22 @@ void NeuralPiAudioProcessorEditor::valueChanged(Value& value) NotificationType::sendNotification); } } + if (value.refersToSameSourceAs(oscReceiver.getDelayValue())) + { + if (!approximatelyEqual(static_cast<double> (value.getValue()), getDelaySlider().getValue())) + { + getDelaySlider().setValue(static_cast<double> (value.getValue()), + NotificationType::sendNotification); + } + } + else if (value.refersToSameSourceAs(oscReceiver.getReverbValue())) + { + if (!approximatelyEqual(static_cast<double> (value.getValue()), getReverbSlider().getValue())) + { + getReverbSlider().setValue(static_cast<double> (value.getValue()), + NotificationType::sendNotification); + } + } else if (value.refersToSameSourceAs(oscReceiver.getModelValue())) { if (!approximatelyEqual(static_cast<double> (value.getValue()), getModelSlider().getValue())) @@ -889,6 +1008,8 @@ void NeuralPiAudioProcessorEditor::timerCallback() getMidSlider().setValue(getParameterValue(midName), NotificationType::dontSendNotification); getTrebleSlider().setValue(getParameterValue(trebleName), NotificationType::dontSendNotification); getPresenceSlider().setValue(getParameterValue(presenceName), NotificationType::dontSendNotification); + getDelaySlider().setValue(getParameterValue(delayName), NotificationType::dontSendNotification); + getReverbSlider().setValue(getParameterValue(reverbName), NotificationType::dontSendNotification); getModelSlider().setValue(getParameterValue(modelName), NotificationType::dontSendNotification); getIrSlider().setValue(getParameterValue(irName), NotificationType::dontSendNotification); } diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h @@ -51,6 +51,8 @@ public: String midAddressPattern{ "/parameter/NeuralPi/Mid" }; String trebleAddressPattern{ "/parameter/NeuralPi/Treble" }; String presenceAddressPattern{ "/parameter/NeuralPi/Presence" }; + String delayAddressPattern{ "/parameter/NeuralPi/Delay" }; + String reverbAddressPattern{ "/parameter/NeuralPi/Reverb" }; const String gainName{ "gain" }; const String masterName{ "master" }; @@ -58,6 +60,8 @@ public: const String midName{ "mid" }; const String trebleName{ "treble" }; const String presenceName{ "presence" }; + const String delayName{ "delay" }; + const String reverbName{ "reverb" }; const String modelName{ "model" }; const String irName{ "ir" }; @@ -82,6 +86,8 @@ private: Slider ampMidKnob; Slider ampTrebleKnob; Slider ampPresenceKnob; + Slider ampDelayKnob; + Slider ampReverbKnob; Label GainLabel; Label LevelLabel; @@ -89,6 +95,8 @@ private: Label MidLabel; Label TrebleLabel; Label PresenceLabel; + Label DelayLabel; + Label ReverbLabel; File test_file; File model_folder; @@ -137,6 +145,8 @@ private: Slider& getMidSlider(); Slider& getTrebleSlider(); Slider& getPresenceSlider(); + Slider& getDelaySlider(); + Slider& getReverbSlider(); Label& getOutPortNumberField(); Label& getInPortNumberField(); diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp @@ -52,6 +52,8 @@ NeuralPiAudioProcessor::NeuralPiAudioProcessor() 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)); addParameter(irParam = new AudioParameterFloat(IR_ID, IR_NAME, NormalisableRange<float>(0.0f, 1.0f, 0.001f), 0.0f)); + addParameter(delayParam = new AudioParameterFloat(DELAY_ID, DELAY_NAME, NormalisableRange<float>(0.0f, 1.0f, 0.001f), 0.0f)); + addParameter(reverbParam = new AudioParameterFloat(REVERB_ID, REVERB_NAME, NormalisableRange<float>(0.0f, 1.0f, 0.001f), 0.0f)); } @@ -135,6 +137,9 @@ void NeuralPiAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlo // Set up IR cabSimIR.prepare(spec); + + // fx chain + fxChain.prepare(spec); } void NeuralPiAudioProcessor::releaseResources() @@ -177,6 +182,9 @@ void NeuralPiAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffe const int numInputChannels = getTotalNumInputChannels(); const int sampleRate = getSampleRate(); + auto block = dsp::AudioBlock<float>(buffer).getSingleChannelBlock(0); + auto context = juce::dsp::ProcessContextReplacing<float>(block); + // Amp ============================================================================= if (amp_state == 1) { auto gain = static_cast<float> (gainParam->get()); @@ -187,6 +195,9 @@ void NeuralPiAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffe auto treble = (static_cast<float> (trebleParam->get() - 0.5) * 24.0); auto presence = (static_cast<float> (presenceParam->get() - 0.5) * 24.0); + auto delay = (static_cast<float> (delayParam->get())); + auto reverb = (static_cast<float> (reverbParam->get())); + auto model = static_cast<float> (modelParam->get()); model_index = getModelIndex(model); @@ -221,9 +232,16 @@ void NeuralPiAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffe } // Master Volume - buffer.applyGain(master * 1.5); + buffer.applyGain(master); + + // Process Delay, and Reverb + set_delayParams(delay); + set_reverbParams(reverb); + fxChain.process(context); } + + // process DC blocker auto monoBlock = dsp::AudioBlock<float>(buffer).getSingleChannelBlock(0); dcBlocker.process(dsp::ProcessContextReplacing<float>(monoBlock)); @@ -256,6 +274,8 @@ void NeuralPiAudioProcessor::getStateInformation(MemoryBlock& destData) stream.writeFloat(*presenceParam); stream.writeFloat(*modelParam); stream.writeFloat(*irParam); + stream.writeFloat(*delayParam); + stream.writeFloat(*reverbParam); } void NeuralPiAudioProcessor::setStateInformation(const void* data, int sizeInBytes) @@ -270,6 +290,8 @@ void NeuralPiAudioProcessor::setStateInformation(const void* data, int sizeInByt presenceParam->setValueNotifyingHost(stream.readFloat()); modelParam->setValueNotifyingHost(stream.readFloat()); irParam->setValueNotifyingHost(stream.readFloat()); + delayParam->setValueNotifyingHost(stream.readFloat()); + reverbParam->setValueNotifyingHost(stream.readFloat()); } int NeuralPiAudioProcessor::getModelIndex(float model_param) @@ -461,6 +483,28 @@ void NeuralPiAudioProcessor::set_ampEQ(float bass_slider, float mid_slider, floa eq4band.setParameters(bass_slider, mid_slider, treble_slider, presence_slider); } +void NeuralPiAudioProcessor::set_delayParams(float paramValue) +{ + auto& del = fxChain.template get<delayIndex>(); + del.setWetLevel(paramValue); + del.setDelayTime(0, paramValue); + del.setFeedback(paramValue); +} + + +void NeuralPiAudioProcessor::set_reverbParams(float paramValue) +{ + auto& rev = fxChain.template get<reverbIndex>(); + rev_params = rev.getParameters(); + + // Sets reverb params as a function of a single reverb param value ( 0.0 to 1.0) + rev_params.wetLevel = paramValue; + rev_params.damping = 1.0 - paramValue; // decay is inverse of damping + rev_params.roomSize= paramValue; + + rev.setParameters(rev_params); +} + 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 @@ -13,6 +13,7 @@ #include "AmpOSCReceiver.h" #include "Eq4Band.h" #include "CabSim.h" +#include "Delay.h" #pragma once @@ -34,6 +35,10 @@ #define TREBLE_NAME "Treble" #define PRESENCE_ID "presence" #define PRESENCE_NAME "Presence" +#define DELAY_ID "delay" +#define DELAY_NAME "Delay" +#define REVERB_ID "reverb" +#define REVERB_NAME "Reverb" //============================================================================== /** @@ -86,6 +91,8 @@ public: void installTones(); void set_ampEQ(float bass_slider, float mid_slider, float treble_slider, float presence_slider); + void set_delayParams(float paramValue); + void set_reverbParams(float paramValue); float convertLogScale(float in_value, float x_min, float x_max, float y_min, float y_max); @@ -125,6 +132,8 @@ public: RT_LSTM LSTM; + juce::dsp::Reverb::Parameters rev_params; + private: var dummyVar; Eq4Band eq4band; // Amp EQ @@ -137,12 +146,23 @@ private: AudioParameterFloat* presenceParam; AudioParameterFloat* modelParam; AudioParameterFloat* irParam; + AudioParameterFloat* delayParam; + AudioParameterFloat* reverbParam; dsp::IIR::Filter<float> dcBlocker; // IR processing CabSim cabSimIR; + // Effects + enum + { + delayIndex, + reverbIndex + }; + + juce::dsp::ProcessorChain<Delay<float>, juce::dsp::Reverb> fxChain; + //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NeuralPiAudioProcessor) };