diff --git a/modules/gin b/modules/gin index 3c168aa..11ccb71 160000 --- a/modules/gin +++ b/modules/gin @@ -1 +1 @@ -Subproject commit 3c168aa48ef18b5fe7f4a671a91e299f9ec1e32c +Subproject commit 11ccb71b61b735fa2071330df9a349679cd3e01e diff --git a/plugin/Resources/layout.json b/plugin/Resources/layout.json index b0930ca..a02493f 100644 --- a/plugin/Resources/layout.json +++ b/plugin/Resources/layout.json @@ -4,6 +4,8 @@ { "id": "osc[1..2]", "x": "0,prevR()+1", "y": 0, "w": "parW()/2", "h": 163 }, { "id": "flt", "x": "0", "y": "prevB()+1", "w": 175, "h": 163 }, { "id": "fltAdsr", "x": "prevR()+1", "y": "prevY()", "w": 175, "h": 163 }, + { "id": "noise", "x": "prevR()+1", "y": "prevY()", "w": 60, "h": 163 }, + { "id": "sub", "x": "prevR()+1", "y": "prevY()", "w": 120, "h": 163 }, { "id": "lfo[1..3]", "x": "0,prevR()+1", "y": "prevB()+1,prevY()", "w": 175, "h": 163 }, { "id": "gate", "x": "prevR()+1", "y": "prevY()", "w": 175, "h": 163 }, { "id": "gatePattern", "x": "prevR()+1", "y": "prevY()", "w": 175, "h": 163 }, diff --git a/plugin/Source/Editor.cpp b/plugin/Source/Editor.cpp index 31a51c9..6383408 100644 --- a/plugin/Source/Editor.cpp +++ b/plugin/Source/Editor.cpp @@ -7,6 +7,8 @@ Editor::Editor (WavetableAudioProcessor& proc_) for (auto& l : lfos) addAndMakeVisible (l); for (auto& l : lfoGraphs) addAndMakeVisible (l); + addAndMakeVisible (sub); + addAndMakeVisible (noise); addAndMakeVisible (filter); addAndMakeVisible (fltADSR); diff --git a/plugin/Source/Editor.h b/plugin/Source/Editor.h index 4c47ad2..5afaa05 100644 --- a/plugin/Source/Editor.h +++ b/plugin/Source/Editor.h @@ -18,6 +18,8 @@ private: WavetableAudioProcessor& proc; OscillatorBox oscillators[Cfg::numOSCs] { { "oscillator 1", proc, 0 }, { "oscillator 2", proc, 1 } }; + NoiseBox noise { "noise", proc }; + SubBox sub { "sub", proc }; FilterBox filter { "filter", proc }; diff --git a/plugin/Source/Panels.h b/plugin/Source/Panels.h index 2038257..9b461c5 100644 --- a/plugin/Source/Panels.h +++ b/plugin/Source/Panels.h @@ -33,7 +33,6 @@ public: addControl (new gin::Select (osc.voices), 0, 1); addControl (detune = new gin::Knob (osc.detune), 1, 1); addControl (spread = new gin::Knob (osc.spread), 2, 1); - addControl (trans = new gin::Knob (osc.voicesTrns, true), 3, 1); watchParam (osc.voices); @@ -67,7 +66,7 @@ public: void mouseUp (const juce::MouseEvent& e) override { auto& h = getHeader(); - if (e.originalComponent == &h && e.mouseWasClicked()) + if (e.originalComponent == &h && e.mouseWasClicked() && e.x >= prevButton.getRight() && e.x <= nextButton.getX()) { juce::StringArray tables; for (auto i = 0; i < BinaryData::namedResourceListSize; i++) @@ -123,14 +122,13 @@ public: auto& osc = proc.oscParams[idx]; - trans->setEnabled (osc.voices->getProcValue() > 1); detune->setEnabled (osc.voices->getProcValue() > 1); spread->setEnabled (osc.voices->getProcValue() > 1); } WavetableAudioProcessor& proc; int idx = 0; - gin::ParamComponent::Ptr trans, detune, spread; + gin::ParamComponent::Ptr detune, spread; gin::WavetableComponent* wt; gin::CoalescedTimer timer; @@ -139,6 +137,48 @@ public: gin::SVGButton prevButton {"prev", "M238.475 475.535l7.071-7.07c4.686-4.686 4.686-12.284 0-16.971L50.053 256 245.546 60.506c4.686-4.686 4.686-12.284 0-16.971l-7.071-7.07c-4.686-4.686-12.284-4.686-16.97 0L10.454 247.515c-4.686 4.686-4.686 12.284 0 16.971l211.051 211.05c4.686 4.686 12.284 4.686 16.97-.001z"}; }; +//============================================================================== +class SubBox : public gin::ParamBox +{ +public: + SubBox (const juce::String& name, WavetableAudioProcessor& proc_) + : gin::ParamBox (name), proc (proc_) + { + setName ("sub"); + + auto& sub = proc.subParams; + + addEnable (sub.enable); + + addControl (new gin::Knob (sub.tune, true), 0, 0); + addControl (new gin::Knob (sub.level, true), 1, 0); + addControl (new gin::Knob (sub.pan, true), 0, 1); + addControl (new gin::Select (sub.wave), 1, 1); + } + + WavetableAudioProcessor& proc; +}; + +//============================================================================== +class NoiseBox : public gin::ParamBox +{ +public: + NoiseBox (const juce::String& name, WavetableAudioProcessor& proc_) + : gin::ParamBox (name), proc (proc_) + { + setName ("noise"); + + auto& noise = proc.noiseParams; + + addEnable (noise.enable); + + addControl (new gin::Knob (noise.level, true), 0, 0); + addControl (new gin::Knob (noise.pan, true), 0, 1); + } + + WavetableAudioProcessor& proc; +}; + //============================================================================== class FilterBox : public gin::ParamBox { @@ -381,9 +421,6 @@ public: addEnable (proc.distortionParams.enable); 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); - addControl (new gin::Knob (proc.distortionParams.mix), 1, 1); setSize (112, 163); } diff --git a/plugin/Source/PluginProcessor.cpp b/plugin/Source/PluginProcessor.cpp index 6aaef44..1e36509 100644 --- a/plugin/Source/PluginProcessor.cpp +++ b/plugin/Source/PluginProcessor.cpp @@ -2,19 +2,14 @@ #include "PluginEditor.h" #include "WavetableVoice.h" -static juce::String waveTextFunction (const gin::Parameter&, float v) +static juce::String subTextFunction (const gin::Parameter&, float v) { - switch ((gin::Wave)int (v)) + switch (int (v)) { - case gin::Wave::silence: return "Off"; - case gin::Wave::sine: return "Sine"; - case gin::Wave::triangle: return "Triangle"; - case gin::Wave::sawUp: return "Saw (Up)"; - case gin::Wave::sawDown: return "Saw (Down)"; - case gin::Wave::pulse: return "Pulse"; - case gin::Wave::square: return "Square"; - case gin::Wave::noise: return "Noise"; - case gin::Wave::wavetable: + case 0: return "Sine"; + case 1: return "Triangle"; + case 2: return "Saw"; + case 3: return "Pulse"; default: jassertfalse; return {}; @@ -108,7 +103,6 @@ void WavetableAudioProcessor::OSCParams::setup (WavetableAudioProcessor& p, int enable = p.addIntParam (id + "enable", nm + "Enable", "Enable", "", { 0.0, 1.0, 1.0, 1.0 }, idx == 0 ? 1.0f : 0.0f, 0.0f); 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); @@ -127,7 +121,7 @@ void WavetableAudioProcessor::SubParams::setup (WavetableAudioProcessor& p) 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); + wave = p.addIntParam (id + "wave", nm + "Wave", "Wave", "", { 0.0, 3.0, 1.0, 1.0 }, 1.0, 0.0f, subTextFunction); 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); @@ -295,9 +289,6 @@ void WavetableAudioProcessor::DistortionParams::setup (WavetableAudioProcessor& { enable = p.addIntParam ("dsEnable", "Enable", "", "", { 0.0, 1.0, 1.0, 1.0 }, 0.0f, 0.0f, enableTextFunction); amount = p.addExtParam ("dsAmount", "Amount", "", "", { 0.0, 1.0, 0.0, 1.0 }, 0.2f, 0.0f, distortionAmountTextFunction); - highpass = p.addExtParam ("dsHighpass", "Highpass", "", "", { 0.0, 1.0, 0.0, 1.0 }, 0.0, 0.0f); - output = p.addExtParam ("dsOutput", "Output", "", "", { 0.0, 1.0, 0.0, 1.0 }, 1.0, 0.0f); - mix = p.addExtParam ("dsMix", "Mix", "", "", { 0.0, 1.0, 0.0, 1.0 }, 1.0, 0.0f); } //============================================================================== @@ -532,7 +523,6 @@ void WavetableAudioProcessor::reset() gate.reset(); chorus.reset(); - distortion.reset(); stereoDelay.reset(); reverb.reset(); @@ -555,7 +545,6 @@ void WavetableAudioProcessor::prepareToPlay (double newSampleRate, int newSample gate.setSampleRate (newSampleRate); chorus.setSampleRate (newSampleRate); - distortion.setSampleRate (newSampleRate); stereoDelay.setSampleRate (newSampleRate); reverb.setSampleRate (float (newSampleRate)); @@ -565,6 +554,7 @@ void WavetableAudioProcessor::prepareToPlay (double newSampleRate, int newSample modStepLFO.setSampleRate (newSampleRate); reloadWavetables(); + analogTables.setSampleRate (newSampleRate); } void WavetableAudioProcessor::releaseResources() @@ -656,7 +646,10 @@ void WavetableAudioProcessor::applyEffects (juce::AudioSampleBuffer& buffer) // Apply Distortion if (distortionParams.enable->isOn()) - distortion.process (buffer); + { + auto clip = 1.0f / (2.0f * distortionVal); + gin::Distortion::processBlock (buffer, distortionVal, -clip, clip); + } // Apply Delay if (delayParams.enable->isOn()) @@ -754,12 +747,7 @@ void WavetableAudioProcessor::updateParams (int newBlockSize) // Update Distortion if (distortionParams.enable->isOn()) - { - distortion.setParams (modMatrix.getValue (distortionParams.amount), - modMatrix.getValue (distortionParams.highpass), - modMatrix.getValue (distortionParams.output), - modMatrix.getValue (distortionParams.mix)); - } + distortionVal = modMatrix.getValue (distortionParams.amount); // Update Delay if (delayParams.enable->isOn()) diff --git a/plugin/Source/PluginProcessor.h b/plugin/Source/PluginProcessor.h index cd08a4b..90423ba 100644 --- a/plugin/Source/PluginProcessor.h +++ b/plugin/Source/PluginProcessor.h @@ -47,8 +47,7 @@ public: { OSCParams() = default; - gin::Parameter::Ptr enable, voices, voicesTrns, tune, finetune, - level, pos, detune, spread, pan; + gin::Parameter::Ptr enable, voices, tune, finetune, level, pos, detune, spread, pan; void setup (WavetableAudioProcessor& p, int idx); @@ -175,7 +174,7 @@ public: { DistortionParams() = default; - gin::Parameter::Ptr enable, amount, highpass, output, mix; + gin::Parameter::Ptr enable, amount; void setup (WavetableAudioProcessor& p); @@ -232,15 +231,17 @@ public: //============================================================================== gin::GateEffect gate; gin::Modulation chorus { 0.5f }; - gin::Distortion distortion; gin::StereoDelay stereoDelay { 120.1 }; gin::PlateReverb reverb; gin::GainProcessor outputGain; gin::AudioFifo scopeFifo { 2, 44100 }; + float distortionVal = 0.0f; juce::OwnedArray osc1Tables; juce::OwnedArray osc2Tables; + gin::BandLimitedLookupTables analogTables; + juce::Value osc1Table, osc2Table; //============================================================================== diff --git a/plugin/Source/WavetableVoice.cpp b/plugin/Source/WavetableVoice.cpp index e15c5ed..ae0327a 100644 --- a/plugin/Source/WavetableVoice.cpp +++ b/plugin/Source/WavetableVoice.cpp @@ -4,6 +4,8 @@ //============================================================================== WavetableVoice::WavetableVoice (WavetableAudioProcessor& p) : proc (p) + , noise (proc.analogTables) + , sub (proc.analogTables) { filter.setNumChannels (2); } @@ -155,6 +157,12 @@ void WavetableVoice::renderNextBlock (juce::AudioBuffer& outputBuffer, in if (proc.oscParams[i].enable->isOn()) oscillators[i].processAdding (currentMidiNotes[i], oscParams[i], buffer); + if (proc.subParams.enable->isOn()) + sub.processAdding (subNote, subParams, buffer); + + if (proc.noiseParams.enable->isOn()) + noise.processAdding (60.0f, noiseParams, buffer); + // Apply velocity float velocity = currentlyPlayingNote.noteOnVelocity.asUnsignedFloat(); buffer.applyGain (gin::velocityToGain (velocity, ampKeyTrack)); @@ -196,13 +204,40 @@ void WavetableVoice::updateParams (int blockSize) oscParams[i].wave = gin::Wave::wavetable; oscParams[i].voices = int (proc.oscParams[i].voices->getProcValue()); - oscParams[i].vcTrns = int (proc.oscParams[i].voicesTrns->getProcValue()); + oscParams[i].vcTrns = 0; 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); oscParams[i].gain = getValue (proc.oscParams[i].level); } + + if (proc.subParams.enable->isOn()) + { + subNote = noteSmoother.getCurrentValue() * 127.0f; + if (glideInfo.glissando) subNote = (float) juce::roundToInt (subNote); + subNote += float (note.totalPitchbendInSemitones); + subNote += getValue (proc.subParams.tune); + + switch (proc.subParams.wave->getUserValueInt()) + { + case 0: subParams.wave = gin::Wave::sine; break; + case 1: subParams.wave = gin::Wave::triangle; break; + case 2: subParams.wave = gin::Wave::sawUp; break; + case 3: subParams.wave = gin::Wave::pulse; break;; + } + + subParams.leftGain = getValue (proc.subParams.level) * (1.0f - getValue (proc.subParams.pan)); + subParams.rightGain = getValue (proc.subParams.level) * (1.0f + getValue (proc.subParams.pan)); + } + + if (proc.noiseParams.enable->isOn()) + { + noiseParams.wave = gin::Wave::noise; + + noiseParams.leftGain = getValue (proc.noiseParams.level) * (1.0f - getValue (proc.noiseParams.pan)); + noiseParams.rightGain = getValue (proc.noiseParams.level) * (1.0f + getValue (proc.noiseParams.pan)); + } ampKeyTrack = getValue (proc.adsrParams.velocityTracking); diff --git a/plugin/Source/WavetableVoice.h b/plugin/Source/WavetableVoice.h index ba9e02b..201def8 100644 --- a/plugin/Source/WavetableVoice.h +++ b/plugin/Source/WavetableVoice.h @@ -36,6 +36,8 @@ private: WavetableAudioProcessor& proc; gin::WTVoicedStereoOscillator oscillators[Cfg::numOSCs]; + gin::StereoOscillator noise; + gin::StereoOscillator sub; gin::Filter filter; gin::ADSR filterADSR; @@ -48,6 +50,10 @@ private: float currentMidiNotes[Cfg::numOSCs]; gin::WTVoicedStereoOscillator::Params oscParams[Cfg::numOSCs]; + + float subNote = 0.0f; + gin::StereoOscillator::Params subParams; + gin::StereoOscillator::Params noiseParams; gin::EasedValueSmoother noteSmoother;