Add wavetables. Switch to using json for component layout

This commit is contained in:
Roland Rabien 2023-08-24 13:25:21 -07:00
commit f1829adfcf
110 changed files with 326 additions and 165 deletions

70
plugin/Source/Editor.cpp Normal file
View file

@ -0,0 +1,70 @@
#include "Editor.h"
Editor::Editor (WavetableAudioProcessor& proc_)
: proc ( proc_ )
{
for (auto& o : oscillators) addAndMakeVisible (o);
for (auto& l : lfos) addAndMakeVisible (l);
for (auto& l : lfoGraphs) addAndMakeVisible (l);
addAndMakeVisible (filter);
addAndMakeVisible (fltADSR);
for (auto& i : modItems)
modHeader.addItem (i);
addAndMakeVisible (modHeader);
for (int i = 0; i < Cfg::numLFOs; i++)
{
lfoBox.addBox (i, &lfos[i]);
lfoBox.addBox (i, &lfoGraphs[i]);
}
addAndMakeVisible (lfoBox);
lfoBox.setPage (0);
for (auto& i : fxItems)
fxHeader.addItem (i);
addAndMakeVisible (fxHeader);
effects.addBox (&gate);
effects.addBox (&pattern);
effects.addBox (&chorus);
effects.addBox (&distort);
effects.addBox (&delay);
effects.addBox (&reverb);
effects.addBox (&scope);
addAndMakeVisible (effects);
setupCallbacks();
}
void Editor::setupCallbacks()
{
// LFO mod items
for (int i = 0; i < Cfg::numLFOs; i++)
{
modItems[i].onClick = [this, i]
{
modItems[0].setSelected (i == 0);
modItems[1].setSelected (i == 1);
modItems[2].setSelected (i == 2);
lfoBox.setPage (i);
};
}
modItems[0].onClick();
}
void Editor::resized()
{
#if JUCE_DEBUG
auto f = juce::File (__FILE__).getChildFile ("../../Resources/layout.json");
layout.setLayout ("layout.json", f);
#else
layout.setLayout ("layout.json");
#endif
}

60
plugin/Source/Editor.h Normal file
View file

@ -0,0 +1,60 @@
#pragma once
#include <JuceHeader.h>
#include "PluginProcessor.h"
#include "Panels.h"
//==============================================================================
class Editor : public juce::Component
{
public:
Editor (WavetableAudioProcessor& proc_);
void setupCallbacks();
void resized() override;
private:
WavetableAudioProcessor& proc;
OscillatorBox oscillators[Cfg::numOSCs] { { "oscillator 1", proc, 0 }, { "oscillator 2", proc, 1 } };
FilterBox filter { "filter 1", proc };
FilterADSRArea fltADSR { proc };
LFOBox lfos[Cfg::numLFOs] { { "LFO 1", proc, 0 }, { "LFO 2", proc, 1 }, { "LFO 3", proc, 2 } };
LFOArea lfoGraphs[Cfg::numLFOs] { { proc, 0 }, { proc, 1 }, { proc, 2 } };
gin::HeaderItem modItems[8] { { "LFO 1", proc.lfoParams[0].enable, proc.modMatrix, proc.modSrcMonoLFO[0], proc.modSrcLFO[0] },
{ "LFO 2", proc.lfoParams[1].enable, proc.modMatrix, proc.modSrcMonoLFO[1], proc.modSrcLFO[1] },
{ "LFO 3", proc.lfoParams[2].enable, proc.modMatrix, proc.modSrcMonoLFO[2], proc.modSrcLFO[2] },
{ "ENV 1", proc.envParams[0].enable, proc.modMatrix, {}, proc.modSrcEnv[0] },
{ "ENV 2", proc.envParams[1].enable, proc.modMatrix, {}, proc.modSrcEnv[1] },
{ "ENV 3", proc.envParams[2].enable, proc.modMatrix, {}, proc.modSrcEnv[2] },
{ "STEP", proc.stepLfoParams.enable, proc.modMatrix, proc.modSrcMonoStep, proc.modSrcStep },
{ "MIDI", nullptr } };
gin::HeaderRow modHeader;
gin::HeaderItem fxItems[5] { { "GATE", proc.gateParams.enable },
{ "CHORUS", proc.chorusParams.enable },
{ "DISTORT", proc.distortionParams.enable },
{ "DELAY", proc.delayParams.enable },
{ "REVERB", proc.reverbParams.enable } };
gin::HeaderRow fxHeader;
GateBox gate { proc };
GateArea pattern { proc };
ChorusBox chorus { proc };
DistortBox distort { proc };
DelayBox delay { proc };
ReverbBox reverb { proc };
ScopeArea scope { proc };
gin::BoxArea lfoBox;
gin::BoxArea effects;
gin::Layout layout { *this };
};

View file

@ -11,21 +11,21 @@ public:
OscillatorBox (const juce::String& name, WavetableAudioProcessor& proc_, int idx_)
: gin::ParamBox (name), proc (proc_), idx (idx_)
{
setName ( "osc" + juce::String ( idx + 1 ) );
auto& osc = proc.oscParams[idx];
addEnable (osc.enable);
addControl (new gin::Select (osc.wave), 0, 0);
addControl (new gin::Knob (osc.tune, true), 1, 0);
addControl (new gin::Select (osc.voices), 2, 0);
addControl (detune = new gin::Knob (osc.detune), 3, 0);
addControl (pw = new gin::Knob (osc.pulsewidth), 0, 1);
addControl (new gin::Knob (osc.pos), 0, 1);
addControl (new gin::Knob (osc.finetune, true), 1, 1);
addControl (spread = new gin::Knob (osc.spread), 2, 1);
addControl (trans = new gin::Knob (osc.voicesTrns, true), 3, 1);
watchParam (osc.wave);
watchParam (osc.voices);
}
@ -34,7 +34,6 @@ public:
gin::ParamBox::paramChanged();
auto& osc = proc.oscParams[idx];
pw->setEnabled ((gin::Wave) int (osc.wave->getProcValue()) == gin::Wave::pulse);
trans->setEnabled (osc.voices->getProcValue() > 1);
detune->setEnabled (osc.voices->getProcValue() > 1);
@ -43,7 +42,7 @@ public:
WavetableAudioProcessor& proc;
int idx = 0;
gin::ParamComponent::Ptr pw, trans, detune, spread;
gin::ParamComponent::Ptr trans, detune, spread;
};
//==============================================================================
@ -53,6 +52,8 @@ public:
FilterBox (const juce::String& name, WavetableAudioProcessor& proc_)
: gin::ParamBox (name), proc (proc_)
{
setName ( "flt" );
auto& flt = proc.filterParams;
addEnable (flt.enable);
@ -95,6 +96,8 @@ public:
FilterADSRArea (WavetableAudioProcessor& proc_)
: proc (proc_)
{
setName ( "fltAdsr" );
auto& flt = proc.filterParams;
adsr = new gin::ADSRComponent ();
@ -126,22 +129,6 @@ public:
gin::ADSRComponent* adsr;
};
//==============================================================================
class MixBox : public gin::ParamBox
{
public:
MixBox (const juce::String& name, WavetableAudioProcessor& proc_)
: gin::ParamBox (name), proc (proc_)
{
}
void paramChanged () override
{
}
WavetableAudioProcessor& proc;
};
//==============================================================================
class LFOBox : public gin::ParamBox
{
@ -149,6 +136,8 @@ public:
LFOBox (const juce::String& name, WavetableAudioProcessor& proc_, int idx_)
: gin::ParamBox (name), proc (proc_), idx (idx_)
{
setName ( "lfo" + juce::String ( idx + 1 ) );
auto& lfo = proc.lfoParams[idx];
addEnable (lfo.enable);
@ -185,6 +174,8 @@ public:
LFOArea (WavetableAudioProcessor& proc_, int idx_)
: proc (proc_), idx (idx_)
{
setName ( "lfoArea" + juce::String ( idx + 1 ) );
auto& lfo = proc.lfoParams[idx];
addControl (new gin::Select (lfo.wave));
@ -215,6 +206,8 @@ public:
GateBox (WavetableAudioProcessor& proc_)
: gin::ParamBox ("Gate"), proc (proc_)
{
setName ( "gate" );
addControl (new gin::Select (proc.gateParams.beat), 0, 0);
addControl (new gin::Knob (proc.gateParams.length), 1, 0);
addControl (new gin::Knob (proc.gateParams.attack), 0, 1);
@ -233,6 +226,8 @@ public:
GateArea (WavetableAudioProcessor& proc_)
: gin::ParamArea ("Pattern"), proc (proc_)
{
setName ( "gatePattern" );
g = new gin::GateEffectComponent();
g->setParams (proc.gateParams.length, proc.gateParams.l, proc.gateParams.r, proc.gateParams.enable);
addControl (g);
@ -261,6 +256,8 @@ public:
ChorusBox (WavetableAudioProcessor& proc_)
: gin::ParamBox ("Chorus"), proc (proc_)
{
setName ( "chorus" );
addControl (new gin::Knob (proc.chorusParams.delay), 0, 0);
addControl (new gin::Knob (proc.chorusParams.rate), 1, 0);
addControl (new gin::Knob (proc.chorusParams.mix), 2, 0);
@ -281,6 +278,8 @@ public:
DistortBox (WavetableAudioProcessor& proc_)
: gin::ParamBox ("Distort"), proc (proc_)
{
setName ( "distort" );
addControl (new gin::Knob (proc.distortionParams.amount), 0, 0);
addControl (new gin::Knob (proc.distortionParams.highpass), 1, 0);
addControl (new gin::Knob (proc.distortionParams.output), 0, 1);
@ -299,6 +298,8 @@ public:
DelayBox (WavetableAudioProcessor& proc_)
: gin::ParamBox ("Delay"), proc (proc_)
{
setName ( "delay" );
addControl (t = new gin::Knob (proc.delayParams.time), 0, 0);
addControl (b = new gin::Select (proc.delayParams.beat), 0, 0);
addControl (new gin::Knob (proc.delayParams.fb), 1, 0);
@ -331,6 +332,8 @@ public:
ReverbBox (WavetableAudioProcessor& proc_)
: gin::ParamBox ("Reverb"), proc (proc_)
{
setName ( "reverb" );
addControl (new gin::Knob (proc.reverbParams.size), 0, 0);
addControl (new gin::Knob (proc.reverbParams.decay), 1, 0);
addControl (new gin::Knob (proc.reverbParams.lowpass), 2, 0);
@ -351,6 +354,8 @@ public:
ScopeArea (WavetableAudioProcessor& proc_)
: gin::ParamArea ("Scope"), proc (proc_)
{
setName ( "scope" );
scope = new gin::TriggeredScope (proc.fifo);
scope->setNumChannels (2);
scope->setTriggerMode (gin::TriggeredScope::TriggerMode::Up);

View file

@ -3,140 +3,7 @@
#include <JuceHeader.h>
#include "PluginProcessor.h"
#include "Panels.h"
//==============================================================================
class Editor : public juce::Component
{
public:
Editor (WavetableAudioProcessor& proc_)
: proc ( proc_ )
{
for (auto& o : oscillators) addAndMakeVisible (o);
for (auto& l : lfos) addAndMakeVisible (l);
for (auto& l : lfoGraphs) addAndMakeVisible (l);
addAndMakeVisible (filter);
addAndMakeVisible (fltADSR);
addAndMakeVisible (mix);
for (auto& i : modItems)
modHeader.addItem (i);
addAndMakeVisible (modHeader);
for (int i = 0; i < Cfg::numLFOs; i++)
{
lfoBox.addBox (i, &lfos[i]);
lfoBox.addBox (i, &lfoGraphs[i]);
}
addAndMakeVisible (lfoBox);
lfoBox.setPage (0);
for (auto& i : fxItems)
fxHeader.addItem (i);
addAndMakeVisible (fxHeader);
effects.addBox (&gate);
effects.addBox (&pattern);
effects.addBox (&chorus);
effects.addBox (&distort);
effects.addBox (&delay);
effects.addBox (&reverb);
effects.addBox (&scope);
addAndMakeVisible (effects);
setupCallbacks();
}
void setupCallbacks()
{
// LFO mod items
for (int i = 0; i < Cfg::numLFOs; i++)
{
modItems[i].onClick = [this, i]
{
modItems[0].setSelected (i == 0);
modItems[1].setSelected (i == 1);
modItems[2].setSelected (i == 2);
lfoBox.setPage (i);
};
}
modItems[0].onClick();
}
void resized() override
{
auto rc = getLocalBounds();
auto rcOsc = rc.removeFromTop (163);
for (auto& o : oscillators) { o.setBounds (rcOsc.removeFromLeft (224)); rcOsc.removeFromLeft (1); };
rc.removeFromTop (1);
auto rcFlt = rc.removeFromTop (163);
filter.setBounds (rcFlt.removeFromLeft (168)); rcFlt.removeFromLeft (1);
fltADSR.setBounds (rcFlt.removeFromLeft (186)); rcFlt.removeFromLeft (1);
mix.setBounds (rcFlt.removeFromLeft (187)); rcFlt.removeFromLeft (1);
auto rcB1 = rc.removeFromTop (26);
modHeader.setBounds (rcB1);
auto rcMod = rc.removeFromTop (163);
lfoBox.setBounds (rcMod);
auto rcB2 = rc.removeFromTop (26);
fxHeader.setBounds (rcB2);
auto rcFX = rc.removeFromTop (163);
effects.setBounds (rcFX);
}
WavetableAudioProcessor& proc;
OscillatorBox oscillators[Cfg::numOSCs] { { "oscillator 1", proc, 0 }, { "oscillator 2", proc, 1 } };
FilterBox filter { "filter 1", proc };
FilterADSRArea fltADSR { proc };
MixBox mix { "osc mix", proc };
LFOBox lfos[Cfg::numLFOs] { { "LFO 1", proc, 0 }, { "LFO 2", proc, 1 }, { "LFO 3", proc, 2 } };
LFOArea lfoGraphs[Cfg::numLFOs] { { proc, 0 }, { proc, 1 }, { proc, 2 } };
gin::HeaderItem modItems[8] { { "LFO 1", proc.lfoParams[0].enable, proc.modMatrix, proc.modSrcMonoLFO[0], proc.modSrcLFO[0] },
{ "LFO 2", proc.lfoParams[1].enable, proc.modMatrix, proc.modSrcMonoLFO[1], proc.modSrcLFO[1] },
{ "LFO 3", proc.lfoParams[2].enable, proc.modMatrix, proc.modSrcMonoLFO[2], proc.modSrcLFO[2] },
{ "ENV 1", proc.envParams[0].enable, proc.modMatrix, {}, proc.modSrcEnv[0] },
{ "ENV 2", proc.envParams[1].enable, proc.modMatrix, {}, proc.modSrcEnv[1] },
{ "ENV 3", proc.envParams[2].enable, proc.modMatrix, {}, proc.modSrcEnv[2] },
{ "STEP", proc.stepLfoParams.enable, proc.modMatrix, proc.modSrcMonoStep, proc.modSrcStep },
{ "MIDI", nullptr } };
gin::HeaderRow modHeader;
gin::HeaderItem fxItems[5] { { "GATE", proc.gateParams.enable },
{ "CHORUS", proc.chorusParams.enable },
{ "DISTORT", proc.distortionParams.enable },
{ "DELAY", proc.delayParams.enable },
{ "REVERB", proc.reverbParams.enable } };
gin::HeaderRow fxHeader;
GateBox gate { proc };
GateArea pattern { proc };
ChorusBox chorus { proc };
DistortBox distort { proc };
DelayBox delay { proc };
ReverbBox reverb { proc };
ScopeArea scope { proc };
gin::BoxArea lfoBox;
gin::BoxArea effects;
};
#include "Editor.h"
//==============================================================================
class WavetableAudioProcessorEditor : public gin::ProcessorEditor

View file

@ -107,13 +107,12 @@ void WavetableAudioProcessor::OSCParams::setup (WavetableAudioProcessor& p, int
juce::String nm = "OSC" + juce::String (idx + 1) + " ";
enable = p.addIntParam (id + "enable", nm + "Enable", "Enable", "", { 0.0, 1.0, 1.0, 1.0 }, idx == 0 ? 1.0f : 0.0f, 0.0f);
wave = p.addIntParam (id + "wave", nm + "Wave", "Wave", "", { 1.0, 7.0, 1.0, 1.0 }, 1.0, 0.0f, waveTextFunction);
voices = p.addIntParam (id + "unison", nm + "Unison", "Unison", "", { 1.0, 8.0, 1.0, 1.0 }, 1.0, 0.0f);
voicesTrns = p.addExtParam (id + "unisontrns", nm + "Unison Trns", "LTrans", "st", { -36.0, 36.0, 1.0, 1.0 }, 0.0, 0.0f);
tune = p.addExtParam (id + "tune", nm + "Tune", "Tune", "st", { -36.0, 36.0, 1.0, 1.0 }, 0.0, 0.0f);
finetune = p.addExtParam (id + "finetune", nm + "Fine Tune", "Fine", "ct", { -100.0, 100.0, 0.0, 1.0 }, 0.0, 0.0f);
level = p.addExtParam (id + "level", nm + "Level", "Level", "db", { -100.0, 0.0, 1.0, 4.0 }, 0.0, 0.0f);
pulsewidth = p.addExtParam (id + "pulsewidth", nm + "Pulse Width", "PW", "%", { 1.0, 99.0, 0.0, 1.0 }, 50.0, 0.0f);
pos = p.addExtParam (id + "pos", nm + "Pos", "Pos", "%", { 0.0, 100.0, 0.0, 1.0 }, 00.0, 0.0f);
detune = p.addExtParam (id + "detune", nm + "Detune", "Detune", "", { 0.0, 0.5, 0.0, 1.0 }, 0.0, 0.0f);
spread = p.addExtParam (id + "spread", nm + "Spread", "Spread", "%", { -100.0, 100.0, 0.0, 1.0 }, 0.0, 0.0f);
pan = p.addExtParam (id + "pan", nm + "Pan", "Pan", "", { -1.0, 1.0, 0.0, 1.0 }, 0.0, 0.0f);
@ -121,6 +120,34 @@ void WavetableAudioProcessor::OSCParams::setup (WavetableAudioProcessor& p, int
level->conversionFunction = [] (float in) { return juce::Decibels::decibelsToGain (in); };
}
//==============================================================================
void WavetableAudioProcessor::SubParams::setup (WavetableAudioProcessor& p)
{
juce::String id = "sub";
juce::String nm = "SUB ";
enable = p.addIntParam (id + "enable", nm + "Enable", "Enable", "", { 0.0, 1.0, 1.0, 1.0 }, 0.0f, 0.0f);
wave = p.addIntParam (id + "wave", nm + "Wave", "Wave", "", { 1.0, 7.0, 1.0, 1.0 }, 1.0, 0.0f, waveTextFunction);
tune = p.addExtParam (id + "tune", nm + "Tune", "Tune", "st", { -36.0, 36.0, 1.0, 1.0 }, 0.0, 0.0f);
level = p.addExtParam (id + "level", nm + "Level", "Level", "db", { -100.0, 0.0, 1.0, 4.0 }, 0.0, 0.0f);
pan = p.addExtParam (id + "pan", nm + "Pan", "Pan", "", { -1.0, 1.0, 0.0, 1.0 }, 0.0, 0.0f);
level->conversionFunction = [] (float in) { return juce::Decibels::decibelsToGain (in); };
}
//==============================================================================
void WavetableAudioProcessor::NoiseParams::setup (WavetableAudioProcessor& p)
{
juce::String id = "noise";
juce::String nm = "Noise ";
enable = p.addIntParam (id + "enable", nm + "Enable", "Enable", "", { 0.0, 1.0, 1.0, 1.0 }, 0.0f, 0.0f);
level = p.addExtParam (id + "level", nm + "Level", "Level", "db", { -100.0, 0.0, 1.0, 4.0 }, 0.0, 0.0f);
pan = p.addExtParam (id + "pan", nm + "Pan", "Pan", "", { -1.0, 1.0, 0.0, 1.0 }, 0.0, 0.0f);
level->conversionFunction = [] (float in) { return juce::Decibels::decibelsToGain (in); };
}
//==============================================================================
void WavetableAudioProcessor::FilterParams::setup (WavetableAudioProcessor& p)
{
@ -318,6 +345,8 @@ WavetableAudioProcessor::WavetableAudioProcessor()
for (int i = 0; i < juce::numElementsInArray (oscParams); i++)
oscParams[i].setup (*this, i);
subParams.setup (*this);
noiseParams.setup (*this);
filterParams.setup (*this);
for (int i = 0; i < juce::numElementsInArray (envParams); i++)

View file

@ -43,14 +43,36 @@ public:
{
OSCParams() = default;
gin::Parameter::Ptr enable , wave, voices, voicesTrns, tune, finetune,
level, pulsewidth, detune, spread, pan;
gin::Parameter::Ptr enable, voices, voicesTrns, tune, finetune,
level, pos, detune, spread, pan;
void setup (WavetableAudioProcessor& p, int idx);
JUCE_DECLARE_NON_COPYABLE (OSCParams)
};
struct SubParams
{
SubParams() = default;
gin::Parameter::Ptr enable, wave, tune, level, pan;
void setup (WavetableAudioProcessor& p);
JUCE_DECLARE_NON_COPYABLE (SubParams)
};
struct NoiseParams
{
NoiseParams() = default;
gin::Parameter::Ptr enable, level, pan;
void setup (WavetableAudioProcessor& p);
JUCE_DECLARE_NON_COPYABLE (NoiseParams)
};
struct FilterParams
{
FilterParams() = default;
@ -187,6 +209,8 @@ public:
//==============================================================================
OSCParams oscParams[Cfg::numOSCs];
SubParams subParams;
NoiseParams noiseParams;
FilterParams filterParams;
EnvParams envParams[Cfg::numENVs];
LFOParams lfoParams[Cfg::numLFOs];

View file

@ -191,10 +191,10 @@ void WavetableVoice::updateParams (int blockSize)
currentMidiNotes[i] += float (note.totalPitchbendInSemitones);
currentMidiNotes[i] += getValue (proc.oscParams[i].tune) + getValue (proc.oscParams[i].finetune) / 100.0f;
oscParams[i].wave = (gin::Wave) int (proc.oscParams[i].wave->getProcValue());
oscParams[i].wave = gin::Wave::silence;
oscParams[i].voices = int (proc.oscParams[i].voices->getProcValue());
oscParams[i].vcTrns = int (proc.oscParams[i].voicesTrns->getProcValue());
oscParams[i].pw = getValue (proc.oscParams[i].pulsewidth) / 100.0f;
oscParams[i].pw = getValue (proc.oscParams[i].pos) / 100.0f;
oscParams[i].pan = getValue (proc.oscParams[i].pan);
oscParams[i].spread = getValue (proc.oscParams[i].spread) / 100.0f;
oscParams[i].detune = getValue (proc.oscParams[i].detune);