From 8a793ba5b4f1d73695f962dfee9b967775530f31 Mon Sep 17 00:00:00 2001 From: Roland Rabien Date: Sun, 8 Oct 2023 14:31:14 -0700 Subject: [PATCH] Add drag to reorder fx --- modules/gin | 2 +- plugin/Resources/layout.json | 86 +++++++++++++++++-------------- plugin/Source/Editor.cpp | 77 ++++++++++++++++++++++++--- plugin/Source/Editor.h | 10 +++- plugin/Source/Panels.h | 5 ++ plugin/Source/PluginProcessor.cpp | 32 +++++++++--- plugin/Source/PluginProcessor.h | 20 +++++++ 7 files changed, 178 insertions(+), 54 deletions(-) diff --git a/modules/gin b/modules/gin index 33d8c95..f79efd9 160000 --- a/modules/gin +++ b/modules/gin @@ -1 +1 @@ -Subproject commit 33d8c95b10958b79c2a018ba4cb73e99c2e2b528 +Subproject commit f79efd9b83a7a546df4ba8c437cc7d487144aa89 diff --git a/plugin/Resources/layout.json b/plugin/Resources/layout.json index b28e02e..dd9e6ac 100644 --- a/plugin/Resources/layout.json +++ b/plugin/Resources/layout.json @@ -104,47 +104,52 @@ { "id": "matrix", "x": 0, "y": 23, "r": "parW()", "b": "parH()" } ] }, - { "id": "gate", "x": "0", "y": "prevB()+1", "w": 290, "h": 137, "children": + { "id": "fx", "x": 0, "y": "prevB()+1", "w": "parW() - 169", "h": 137, "children": [ - { "id": "Beat", "x": 61, "y": 30, "w": 42, "h": 57 }, - { "id": "Length", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, - { "id": "A", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, - { "id": "R", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, - { "id": "pattern", "x": 2, "y": "prevB() + 5", "w": "parW() - 6", "b": "parH() - 15" } - ] + { "id": "gate", "x": "0", "y": 0, "w": 290, "h": 137, "children": + [ + { "id": "Beat", "x": 61, "y": 30, "w": 42, "h": 57 }, + { "id": "Length", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, + { "id": "A", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, + { "id": "R", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, + { "id": "pattern", "x": 2, "y": "prevB() + 5", "w": "parW() - 6", "b": "parH() - 15" } + ] + }, + { "id": "chorus", "x": "prevR()+1", "y": "prevY()", "w": 126, "h": 137, "children": + [ + { "id": "Delay", "x": 0, "y": 23, "w": 42, "h": 57 }, + { "id": "Speed", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, + { "id": "Mix", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, + { "id": "Depth", "x": 21, "y": "prevB()", "w": 42, "h": 57 }, + { "id": "Width", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 } + ] + }, + { "id": "distort", "x": "prevR()+1", "y": "prevY()", "w": 100, "h": 137, "children": + [ + { "id": "Amount", "x": 22, "y": "23 + 22", "w": 56, "h": 70 } + ] + }, + { "id": "delay", "x": "prevR()+1", "y": "prevY()", "w": 126, "h": 137, "children": + [ + { "id": "Sync", "x": 0, "y": 23, "w": 42, "h": 57 }, + { "id": "Delay1", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, + { "id": "Delay2", "x": "prevX()", "y": "prevY()", "w": 42, "h": 57 }, + { "id": "Mix", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, + { "id": "FB", "x": 21, "y": "prevB()", "w": 42, "h": 57 }, + { "id": "CF", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 } + ] }, + { "id": "reverb", "x": "prevR()+1", "y": "prevY()", "w": 126, "h": 137, "children": + [ + { "id": "Size", "x": 0, "y": 23, "w": 42, "h": 57 }, + { "id": "Decay", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, + { "id": "Lowpass", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, + { "id": "Damping", "x": 0, "y": "prevB()", "w": 42, "h": 57 }, + { "id": "Predelay", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, + { "id": "Mix", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 } + ] + } + ] }, - { "id": "chorus", "x": "prevR()+1", "y": "prevY()", "w": 126, "h": 137, "children": - [ - { "id": "Delay", "x": 0, "y": 23, "w": 42, "h": 57 }, - { "id": "Speed", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, - { "id": "Mix", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, - { "id": "Depth", "x": 21, "y": "prevB()", "w": 42, "h": 57 }, - { "id": "Width", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 } - ] - }, - { "id": "distort", "x": "prevR()+1", "y": "prevY()", "w": 100, "h": 137, "children": - [ - { "id": "Amount", "x": 22, "y": "23 + 22", "w": 56, "h": 70 } - ] - }, - { "id": "delay", "x": "prevR()+1", "y": "prevY()", "w": 126, "h": 137, "children": - [ - { "id": "Sync", "x": 0, "y": 23, "w": 42, "h": 57 }, - { "id": "Delay1", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, - { "id": "Delay2", "x": "prevX()", "y": "prevY()", "w": 42, "h": 57 }, - { "id": "Mix", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, - { "id": "FB", "x": 21, "y": "prevB()", "w": 42, "h": 57 }, - { "id": "CF", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 } - ] }, - { "id": "reverb", "x": "prevR()+1", "y": "prevY()", "w": 126, "h": 137, "children": - [ - { "id": "Size", "x": 0, "y": 23, "w": 42, "h": 57 }, - { "id": "Decay", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, - { "id": "Lowpass", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, - { "id": "Damping", "x": 0, "y": "prevB()", "w": 42, "h": 57 }, - { "id": "Predelay", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, - { "id": "Mix", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 } - ] }, { "id": "global", "x": "prevR()+1", "y": "prevY()", "w": 168, "h": 137, "children": [ { "id": "Mono", "x": 0, "y": 23, "w": 42, "h": 57 }, @@ -154,6 +159,7 @@ { "id": "PB Range", "x": 0, "y": "prevB()", "w": 42, "h": 57 }, { "id": "Voices", "x": "prevR()", "y": "prevY()", "w": 42, "h": 57 }, { "id": "Level", "x": "prevR() + 42", "y": "prevY()", "w": 42, "h": 57 } - ] } + ] + } ] } \ No newline at end of file diff --git a/plugin/Source/Editor.cpp b/plugin/Source/Editor.cpp index 4d6bd41..32e55c6 100644 --- a/plugin/Source/Editor.cpp +++ b/plugin/Source/Editor.cpp @@ -1,7 +1,7 @@ #include "Editor.h" Editor::Editor (WavetableAudioProcessor& proc_) - : proc ( proc_ ) + : proc (proc_) { for (auto& o : oscillators) addAndMakeVisible (o); for (auto& l : lfos) addAndMakeVisible (l); @@ -15,13 +15,78 @@ Editor::Editor (WavetableAudioProcessor& proc_) addAndMakeVisible (mod); addAndMakeVisible (mtx); addAndMakeVisible (global); - addAndMakeVisible (gate); - addAndMakeVisible (chorus); - addAndMakeVisible (distort); - addAndMakeVisible (delay); - addAndMakeVisible (reverb); + + fx.addAndMakeVisible (gate); + fx.addAndMakeVisible (chorus); + fx.addAndMakeVisible (distort); + fx.addAndMakeVisible (delay); + fx.addAndMakeVisible (reverb); + + fx.onDragStart = [] (const juce::MouseEvent& e) + { + if (dynamic_cast (e.originalComponent)) + return true; + return false; + }; + fx.onOrderChanged = [this] + { + proc.fxParams.fx1->setUserValue (fx.getChildComponent(0)->getProperties()["fxId"]); + proc.fxParams.fx2->setUserValue (fx.getChildComponent(1)->getProperties()["fxId"]); + proc.fxParams.fx3->setUserValue (fx.getChildComponent(2)->getProperties()["fxId"]); + proc.fxParams.fx4->setUserValue (fx.getChildComponent(3)->getProperties()["fxId"]); + proc.fxParams.fx5->setUserValue (fx.getChildComponent(4)->getProperties()["fxId"]); + + handleAsyncUpdate(); + }; + + proc.fxParams.fx1->addListener (this); + proc.fxParams.fx2->addListener (this); + proc.fxParams.fx3->addListener (this); + proc.fxParams.fx4->addListener (this); + proc.fxParams.fx5->addListener (this); + + addAndMakeVisible (fx); setupCallbacks(); + handleAsyncUpdate(); +} + +Editor::~Editor() +{ + proc.fxParams.fx1->removeListener (this); + proc.fxParams.fx2->removeListener (this); + proc.fxParams.fx3->removeListener (this); + proc.fxParams.fx4->removeListener (this); + proc.fxParams.fx5->removeListener (this); +} + +void Editor::handleAsyncUpdate() +{ + if (fx.isDragInProgress()) + return; + + fx.removeAllChildren(); + + auto getComp = [this] (int fxId) -> juce::Component* + { + if (fxId == fxGate) return &gate; + if (fxId == fxChorus) return &chorus; + if (fxId == fxDistort) return &distort; + if (fxId == fxDelay) return &delay; + if (fxId == fxReverb) return &reverb; + + jassertfalse; + return nullptr; + }; + + fx.addAndMakeVisible (getComp (proc.fxParams.fx1->getUserValueInt())); + fx.addAndMakeVisible (getComp (proc.fxParams.fx2->getUserValueInt())); + fx.addAndMakeVisible (getComp (proc.fxParams.fx3->getUserValueInt())); + fx.addAndMakeVisible (getComp (proc.fxParams.fx4->getUserValueInt())); + fx.addAndMakeVisible (getComp (proc.fxParams.fx5->getUserValueInt())); + + if (fx.getWidth() > 0) + fx.resized(); } void Editor::setupCallbacks() diff --git a/plugin/Source/Editor.h b/plugin/Source/Editor.h index 131cbb2..d5ea700 100644 --- a/plugin/Source/Editor.h +++ b/plugin/Source/Editor.h @@ -5,15 +5,21 @@ #include "Panels.h" //============================================================================== -class Editor : public juce::Component +class Editor : public juce::Component, + private gin::Parameter::ParameterListener, + private juce::AsyncUpdater { public: Editor (WavetableAudioProcessor& proc_); + ~Editor() override; void setupCallbacks(); void resized() override; private: + void valueUpdated (gin::Parameter*) override { triggerAsyncUpdate(); } + void handleAsyncUpdate() override; + WavetableAudioProcessor& proc; OscillatorBox oscillators[Cfg::numOSCs] { { "oscillator 1", proc, 0 }, { "oscillator 2", proc, 1 } }; @@ -36,5 +42,7 @@ private: DelayBox delay { proc }; ReverbBox reverb { proc }; + gin::ComponentGrid fx { "fx" }; + gin::Layout layout { *this }; }; diff --git a/plugin/Source/Panels.h b/plugin/Source/Panels.h index 2412fcb..9268748 100644 --- a/plugin/Source/Panels.h +++ b/plugin/Source/Panels.h @@ -635,6 +635,7 @@ public: : gin::ParamBox ("Gate"), proc (proc_) { setName ("gate"); + getProperties().set ("fxId", fxGate); addEnable (proc.gateParams.enable); @@ -659,6 +660,7 @@ public: : gin::ParamBox ("Chorus"), proc (proc_) { setName ("chorus"); + getProperties().set ("fxId", fxChorus); addEnable (proc.chorusParams.enable); @@ -681,6 +683,7 @@ public: : gin::ParamBox ("Distort"), proc (proc_) { setName ("distort"); + getProperties().set ("fxId", fxDistort); addEnable (proc.distortionParams.enable); @@ -698,6 +701,7 @@ public: : gin::ParamBox ("Delay"), proc (proc_) { setName ("delay"); + getProperties().set ("fxId", fxDelay); addEnable (proc.delayParams.enable); @@ -735,6 +739,7 @@ public: : gin::ParamBox ("Reverb"), proc (proc_) { setName ("reverb"); + getProperties().set ("fxId", fxReverb); addEnable (proc.reverbParams.enable); diff --git a/plugin/Source/PluginProcessor.cpp b/plugin/Source/PluginProcessor.cpp index 6d6ebe7..9c735dd 100644 --- a/plugin/Source/PluginProcessor.cpp +++ b/plugin/Source/PluginProcessor.cpp @@ -362,6 +362,16 @@ void WavetableAudioProcessor::ReverbParams::setup (WavetableAudioProcessor& p) mix = p.addExtParam ("rvbMix", "Mix", "", "", {0.0f, 1.0f, 0.0f, 1.0f}, 0.0f, 0.0f); } +//============================================================================== +void WavetableAudioProcessor::FXParams::setup (WavetableAudioProcessor& p) +{ + fx1 = p.addIntParam ("fxOrder1", "FX1", "", "", { 0.0, 4.0, 1.0, 1.0 }, fxGate, 0.0f); + fx2 = p.addIntParam ("fxOrder2", "FX2", "", "", { 0.0, 4.0, 1.0, 1.0 }, fxChorus, 0.0f); + fx3 = p.addIntParam ("fxOrder3", "FX3", "", "", { 0.0, 4.0, 1.0, 1.0 }, fxDistort, 0.0f); + fx4 = p.addIntParam ("fxOrder4", "FX4", "", "", { 0.0, 4.0, 1.0, 1.0 }, fxDelay, 0.0f); + fx5 = p.addIntParam ("fxOrder5", "FX5", "", "", { 0.0, 4.0, 1.0, 1.0 }, fxReverb, 0.0f); +} + #if 0 void convertWavetables() { @@ -498,6 +508,7 @@ WavetableAudioProcessor::WavetableAudioProcessor() distortionParams.setup (*this); delayParams.setup (*this); reverbParams.setup (*this); + fxParams.setup (*this); for (int i = 0; i < 50; i++) { @@ -861,25 +872,25 @@ gin::WTOscillator::Params WavetableAudioProcessor::getLiveWTParams (int osc) return p; } -void WavetableAudioProcessor::applyEffects (juce::AudioSampleBuffer& buffer) +void WavetableAudioProcessor::applyEffect (juce::AudioSampleBuffer& buffer, int fxId) { // Apply gate - if (gateParams.enable->isOn()) + if (fxId == fxGate && gateParams.enable->isOn()) gate.process (buffer, noteOnIndex, noteOffIndex); // Apply Chorus - if (chorusParams.enable->isOn()) + if (fxId == fxChorus && chorusParams.enable->isOn()) chorus.process (buffer); // Apply Distortion - if (distortionParams.enable->isOn()) + if (fxId == fxDistort && distortionParams.enable->isOn()) { auto clip = 1.0f / (2.0f * distortionVal); gin::Distortion::processBlock (buffer, distortionVal, -clip, clip); } // Apply Delay - if (delayParams.enable->isOn()) + if (fxId == fxDelay && delayParams.enable->isOn()) { if (delayParams.sync->isOn()) stereoDelay.process (buffer); @@ -888,8 +899,17 @@ void WavetableAudioProcessor::applyEffects (juce::AudioSampleBuffer& buffer) } // Apply Reverb - if (reverbParams.enable->isOn()) + if (fxId == fxReverb && reverbParams.enable->isOn()) reverb.process (buffer.getWritePointer (0), buffer.getWritePointer (1), buffer.getNumSamples ()); +} + +void WavetableAudioProcessor::applyEffects (juce::AudioSampleBuffer& buffer) +{ + applyEffect (buffer, fxParams.fx1->getUserValueInt()); + applyEffect (buffer, fxParams.fx2->getUserValueInt()); + applyEffect (buffer, fxParams.fx3->getUserValueInt()); + applyEffect (buffer, fxParams.fx4->getUserValueInt()); + applyEffect (buffer, fxParams.fx5->getUserValueInt()); // Output gain outputGain.process (buffer); diff --git a/plugin/Source/PluginProcessor.h b/plugin/Source/PluginProcessor.h index 7165afa..4eb4526 100644 --- a/plugin/Source/PluginProcessor.h +++ b/plugin/Source/PluginProcessor.h @@ -4,6 +4,12 @@ #include "WavetableVoice.h" +constexpr auto fxGate = 0; +constexpr auto fxChorus = 1; +constexpr auto fxDistort = 2; +constexpr auto fxDelay = 3; +constexpr auto fxReverb = 4; + //============================================================================== class WavetableAudioProcessor : public gin::Processor, public gin::Synthesiser @@ -45,6 +51,8 @@ public: bool loadUserWavetable (int osc, const juce::File& f, int sz); void applyEffects (juce::AudioSampleBuffer& buffer); + void applyEffect (juce::AudioSampleBuffer& buffer, int fxId); + bool loadWaveTable (juce::OwnedArray& table, double sr, const juce::MemoryBlock& wav, const juce::String& format, int size); // Voice Params @@ -220,6 +228,17 @@ public: JUCE_DECLARE_NON_COPYABLE (ReverbParams) }; + struct FXParams + { + FXParams() = default; + + gin::Parameter::Ptr fx1, fx2, fx3, fx4, fx5; + + void setup (WavetableAudioProcessor& p); + + JUCE_DECLARE_NON_COPYABLE (FXParams) + }; + //============================================================================== gin::ModSrcId modSrcPressure, modSrcTimbre, modSrcPitchbend, modScrPitchBend, modSrcFilter, modSrcNote, modSrcVelocity, modSrcStep, modSrcMonoStep; @@ -235,6 +254,7 @@ public: EnvParams envParams[Cfg::numENVs]; LFOParams lfoParams[Cfg::numLFOs]; StepLFOParams stepLfoParams; + FXParams fxParams; ADSRParams adsrParams;