diff --git a/modules/gin b/modules/gin index 2aa9e9f..d8ead26 160000 --- a/modules/gin +++ b/modules/gin @@ -1 +1 @@ -Subproject commit 2aa9e9fb9208a7e49eef07fe9a65365351b8481a +Subproject commit d8ead26e5775c0b11bd5067399d3a38beb7602b2 diff --git a/plugin/Resources/Wavetables/WINDOW_S.WAV b/plugin/Resources/Wavetables/WINDOW_S.WAV new file mode 100644 index 0000000..e6f7134 Binary files /dev/null and b/plugin/Resources/Wavetables/WINDOW_S.WAV differ diff --git a/plugin/Source/Boxes.h b/plugin/Source/Boxes.h index c701fb5..ec7bf19 100644 --- a/plugin/Source/Boxes.h +++ b/plugin/Source/Boxes.h @@ -59,6 +59,7 @@ public: addPage ("WT " + String (i + 1), 3, 4); addPageEnable (i * 2, wt.enable); + addControl (i * 2, new gin::Knob (wt.table), 0, 0); addControl (i * 2, new gin::Knob (wt.tune, true), 1, 0); addControl (i * 2, new gin::Knob (wt.finetune, true), 2, 0); addControl (i * 2, new gin::Knob (wt.pan, true), 0, 1); @@ -78,7 +79,7 @@ public: auto& osc = proc.oscParams[i]; addPage ("OSC " + String (i + 1), 3, 4); - addPageEnable (i * 2, osc.enable); + addPageEnable (Cfg::numWTs * 2 + i * 2, osc.enable); addControl (Cfg::numWTs * 2 + i * 2, new gin::Select (osc.wave), 0, 0); addControl (Cfg::numWTs * 2 + i * 2, new gin::Knob (osc.tune, true), 1, 0); diff --git a/plugin/Source/PluginProcessor.cpp b/plugin/Source/PluginProcessor.cpp index 1ae0f15..fc01145 100644 --- a/plugin/Source/PluginProcessor.cpp +++ b/plugin/Source/PluginProcessor.cpp @@ -107,6 +107,7 @@ void WavetableAudioProcessor::WTParams::setup (WavetableAudioProcessor& p, int i String nm = "WT" + 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); + table = p.addExtParam (id + "table", nm + "Table", "Table", "", { 0.0, 1.0, 0.0, 1.0 }, 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); @@ -125,7 +126,7 @@ void WavetableAudioProcessor::OSCParams::setup (WavetableAudioProcessor& p, int String id = "osc" + String (idx + 1); String nm = "OSC" + 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); + 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); 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); @@ -397,6 +398,8 @@ void WavetableAudioProcessor::LimiterParams::setup (WavetableAudioProcessor& p) //============================================================================== WavetableAudioProcessor::WavetableAudioProcessor() { + formatManager->registerBasicFormats(); + enableLegacyMode(); setVoiceStealingEnabled (true); @@ -440,6 +443,9 @@ WavetableAudioProcessor::WavetableAudioProcessor() } setupModMatrix(); + + MemoryBlock mb (BinaryData::WINDOW_S_WAV, BinaryData::WINDOW_S_WAVSize); + updateWavetable (0, mb, 256); } WavetableAudioProcessor::~WavetableAudioProcessor() @@ -850,6 +856,22 @@ void WavetableAudioProcessor::handleController ([[maybe_unused]] int ch, int num modMatrix.setMonoValue (modSrcCC[num], val / 127.0f); } +void WavetableAudioProcessor::updateWavetable (int idx, MemoryBlock& src, int tableSize) +{ + if (auto reader = std::unique_ptr (formatManager->createReaderFor (std::make_unique (src, false)))) + { + AudioSampleBuffer buffer; + buffer.setSize (1, int (reader->lengthInSamples)); + reader->read (&buffer, 0, int (reader->lengthInSamples), 0, true, false); + + loadWavetables (waveTables[idx], buffer, reader->sampleRate, tableSize); + + for (auto v : voices) + if (auto wtv = dynamic_cast(v)) + wtv->setWavetable (idx, waveTables[idx]); + } +} + //============================================================================== bool WavetableAudioProcessor::hasEditor() const { diff --git a/plugin/Source/PluginProcessor.h b/plugin/Source/PluginProcessor.h index 47b5ed0..c2b5778 100644 --- a/plugin/Source/PluginProcessor.h +++ b/plugin/Source/PluginProcessor.h @@ -45,7 +45,7 @@ public: { WTParams() = default; - gin::Parameter::Ptr enable, voices, voicesTrns, tune, finetune, + gin::Parameter::Ptr enable, table, voices, voicesTrns, tune, finetune, level, detune, spread, pan; void setup (WavetableAudioProcessor& p, int idx); @@ -230,6 +230,9 @@ public: JUCE_DECLARE_NON_COPYABLE (LimiterParams) }; + //============================================================================== + void updateWavetable (int idx, MemoryBlock& src, int tableSize); + //============================================================================== gin::ModSrcId modSrcPressure, modSrcTimbre, modScrPitchBend, modSrcNote, modSrcVelocity, modSrcStep, modSrcMonoStep; @@ -237,6 +240,7 @@ public: Array modSrcCC, modSrcMonoLFO, modSrcLFO, modSrcFilter, modSrcEnv; //============================================================================== + SharedResourcePointer formatManager; WTParams wtParams[Cfg::numWTs]; OSCParams oscParams[Cfg::numOSCs]; @@ -277,6 +281,8 @@ public: AudioPlayHead* playhead = nullptr; + OwnedArray waveTables[Cfg::numWTs]; + //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WavetableAudioProcessor) }; diff --git a/plugin/Source/WavetableVoice.cpp b/plugin/Source/WavetableVoice.cpp index ed5cb65..4509358 100644 --- a/plugin/Source/WavetableVoice.cpp +++ b/plugin/Source/WavetableVoice.cpp @@ -12,6 +12,11 @@ WavetableVoice::WavetableVoice (WavetableAudioProcessor& p, BandLimitedLookupTab f.setNumChannels (2); } +void WavetableVoice::setWavetable (int idx, OwnedArray& table) +{ + wtOscillators[idx].setWavetable (table); +} + void WavetableVoice::noteStarted() { fastKill = false; @@ -51,7 +56,10 @@ void WavetableVoice::noteStarted() snapParams(); updateParams (0); snapParams(); - + + for (auto& osc : wtOscillators) + osc.noteOn(); + for (auto& osc : oscillators) osc.noteOn(); @@ -91,6 +99,9 @@ void WavetableVoice::noteRetriggered() updateParams (0); + for (auto& osc : wtOscillators) + osc.noteOn(); + for (auto& osc : oscillators) osc.noteOn(); @@ -137,6 +148,9 @@ void WavetableVoice::setCurrentSampleRate (double newRate) { MPESynthesiserVoice::setCurrentSampleRate (newRate); + for (auto& osc : wtOscillators) + osc.setSampleRate (newRate); + for (auto& osc : oscillators) osc.setSampleRate (newRate); @@ -161,9 +175,13 @@ void WavetableVoice::renderNextBlock (AudioBuffer& outputBuffer, int star // Run OSC ScratchBuffer buffer (2, numSamples); + for (int i = 0; i < Cfg::numWTs; i++) + if (proc.wtParams[i].enable->isOn()) + wtOscillators[i].processAdding (currentMidiNotes[i], wtParams[i], buffer); + for (int i = 0; i < Cfg::numOSCs; i++) if (proc.oscParams[i].enable->isOn()) - oscillators[i].processAdding (currentMidiNotes[i], oscParams[i], buffer); + oscillators[i].processAdding (currentMidiNotes[Cfg::numWTs + i], oscParams[i], buffer); // Apply velocity float velocity = currentlyPlayingNote.noteOnVelocity.asUnsignedFloat(); @@ -196,14 +214,32 @@ void WavetableVoice::updateParams (int blockSize) proc.modMatrix.setPolyValue (*this, proc.modSrcNote, note.initialNote / 127.0f); + for (int i = 0; i < Cfg::numWTs; i++) + { + if (! proc.wtParams[i].enable->isOn()) continue; + + currentMidiNotes[i] = noteSmoother.getCurrentValue() * 127.0f; + if (glideInfo.glissando) currentMidiNotes[i] = roundToInt (currentMidiNotes[i]); + currentMidiNotes[i] += float (note.totalPitchbendInSemitones); + currentMidiNotes[i] += getValue (proc.wtParams[i].tune) + getValue (proc.wtParams[i].finetune) / 100.0f; + + wtParams[i].voices = int (proc.wtParams[i].voices->getProcValue()); + wtParams[i].vcTrns = int (proc.wtParams[i].voicesTrns->getProcValue()); + wtParams[i].pw = getValue (proc.wtParams[i].table); + wtParams[i].pan = getValue (proc.wtParams[i].pan); + wtParams[i].spread = getValue (proc.wtParams[i].spread) / 100.0f; + wtParams[i].detune = getValue (proc.wtParams[i].detune); + wtParams[i].gain = getValue (proc.wtParams[i].level); + } + for (int i = 0; i < Cfg::numOSCs; i++) { if (! proc.oscParams[i].enable->isOn()) continue; - currentMidiNotes[i] = noteSmoother.getCurrentValue() * 127.0f; - if (glideInfo.glissando) currentMidiNotes[i] = roundToInt (currentMidiNotes[i]); - currentMidiNotes[i] += float (note.totalPitchbendInSemitones); - currentMidiNotes[i] += getValue (proc.oscParams[i].tune) + getValue (proc.oscParams[i].finetune) / 100.0f; + currentMidiNotes[Cfg::numWTs + i] = noteSmoother.getCurrentValue() * 127.0f; + if (glideInfo.glissando) currentMidiNotes[Cfg::numWTs + i] = roundToInt (currentMidiNotes[Cfg::numWTs + i]); + currentMidiNotes[Cfg::numWTs + i] += float (note.totalPitchbendInSemitones); + currentMidiNotes[Cfg::numWTs + i] += getValue (proc.oscParams[i].tune) + getValue (proc.oscParams[i].finetune) / 100.0f; oscParams[i].wave = (Wave) int (proc.oscParams[i].wave->getProcValue()); oscParams[i].voices = int (proc.oscParams[i].voices->getProcValue()); diff --git a/plugin/Source/WavetableVoice.h b/plugin/Source/WavetableVoice.h index 1b6a13b..ae73949 100644 --- a/plugin/Source/WavetableVoice.h +++ b/plugin/Source/WavetableVoice.h @@ -11,7 +11,9 @@ class WavetableVoice : public gin::SynthesiserVoice, { public: WavetableVoice (WavetableAudioProcessor& p, gin::BandLimitedLookupTables& bandLimitedLookupTables); - + + void setWavetable (int idx, OwnedArray& table); + void noteStarted() override; void noteRetriggered() override; void noteStopped (bool allowTailOff) override; @@ -35,7 +37,8 @@ private: WavetableAudioProcessor& proc; gin::BandLimitedLookupTables& bandLimitedLookupTables; - gin::VoicedStereoOscillator oscillators[Cfg::numOSCs] = + gin::WTVoicedStereoOscillator wtOscillators[Cfg::numWTs]; + gin::BLLTVoicedStereoOscillator oscillators[Cfg::numOSCs] = { bandLimitedLookupTables, }; @@ -49,8 +52,10 @@ private: gin::AnalogADSR adsr; - float currentMidiNotes[Cfg::numOSCs]; - gin::VoicedStereoOscillator::Params oscParams[Cfg::numOSCs]; + float currentMidiNotes[Cfg::numWTs + Cfg::numOSCs]; + + gin::WTVoicedStereoOscillator::Params wtParams[Cfg::numWTs]; + gin::BLLTVoicedStereoOscillator::Params oscParams[Cfg::numOSCs]; gin::EasedValueSmoother noteSmoother; diff --git a/plugin/Wavetable.jucer b/plugin/Wavetable.jucer index 5de073b..7e2b7c7 100644 --- a/plugin/Wavetable.jucer +++ b/plugin/Wavetable.jucer @@ -6,6 +6,11 @@ pluginManufacturerCode="Soca" pluginCode="SLwt" pluginAUMainType="'aumu'" cppLanguageStandard="latest" pluginChannelConfigs="{0,2}" version="0.0.2"> + + + + +