Upload files to "Source"
This commit is contained in:
@@ -1,13 +1,54 @@
|
||||
#include "PluginProcessor.h"
|
||||
#include "PluginEditor.h"
|
||||
#include "WavetableOsc.h"
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
//==============================================================================
|
||||
NeuralSynthAudioProcessor::NeuralSynthAudioProcessor()
|
||||
: parameters(*this, nullptr, "PARAMETERS", createParameterLayout())
|
||||
, AudioProcessor(BusesProperties().withOutput("Output", juce::AudioChannelSet::stereo(), true))
|
||||
, audioEngine(sp)
|
||||
, factoryPresets(makeFactoryPresets())
|
||||
{
|
||||
parameters.addParameterListener("waveform", this);
|
||||
parameters.addParameterListener("wt_phase", this);
|
||||
parameters.addParameterListener("wt_on", this);
|
||||
parameters.addParameterListener("wt_morph", this);
|
||||
parameters.addParameterListener("wt_bank", this);
|
||||
parameters.addParameterListener("wt_lfoRate", this);
|
||||
parameters.addParameterListener("wt_lfoDepth", this);
|
||||
parameters.addParameterListener("wt_lfoShape", this);
|
||||
parameters.addParameterListener("wt_level", this);
|
||||
|
||||
parameters.addParameterListener("wt2_phase", this);
|
||||
parameters.addParameterListener("wt2_on", this);
|
||||
parameters.addParameterListener("wt2_morph", this);
|
||||
parameters.addParameterListener("wt2_bank", this);
|
||||
parameters.addParameterListener("wt2_lfoRate", this);
|
||||
parameters.addParameterListener("wt2_lfoDepth", this);
|
||||
parameters.addParameterListener("wt2_lfoShape", this);
|
||||
parameters.addParameterListener("wt2_level", this);
|
||||
|
||||
sp.wtPhase = parameters.getRawParameterValue("wt_phase");
|
||||
sp.wtOn = parameters.getRawParameterValue("wt_on");
|
||||
sp.wtMorph = parameters.getRawParameterValue("wt_morph");
|
||||
sp.wtBank = parameters.getRawParameterValue("wt_bank");
|
||||
sp.wtLfoRate = parameters.getRawParameterValue("wt_lfoRate");
|
||||
sp.wtLfoDepth= parameters.getRawParameterValue("wt_lfoDepth");
|
||||
sp.wtLfoShape= parameters.getRawParameterValue("wt_lfoShape");
|
||||
sp.wtLevel = parameters.getRawParameterValue("wt_level");
|
||||
|
||||
sp.wt2Phase = parameters.getRawParameterValue("wt2_phase");
|
||||
sp.wt2On = parameters.getRawParameterValue("wt2_on");
|
||||
sp.wt2Morph = parameters.getRawParameterValue("wt2_morph");
|
||||
sp.wt2Bank = parameters.getRawParameterValue("wt2_bank");
|
||||
sp.wt2LfoRate= parameters.getRawParameterValue("wt2_lfoRate");
|
||||
sp.wt2LfoDepth= parameters.getRawParameterValue("wt2_lfoDepth");
|
||||
sp.wt2LfoShape= parameters.getRawParameterValue("wt2_lfoShape");
|
||||
sp.wt2Level = parameters.getRawParameterValue("wt2_level");
|
||||
|
||||
if (! factoryPresets.empty())
|
||||
applyPreset(0);
|
||||
|
||||
// === Per-panel bypass (default OFF) ===
|
||||
sp.chorusOn = parameters.getRawParameterValue("chorus_on");
|
||||
@@ -158,6 +199,12 @@ void NeuralSynthAudioProcessor::changeProgramName (int, const juce::String&) {}
|
||||
void NeuralSynthAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
|
||||
{
|
||||
audioEngine.prepare({ sampleRate, (juce::uint32)samplesPerBlock, 2 });
|
||||
const auto numChannels = (juce::uint32) juce::jmax (1, getTotalNumOutputChannels());
|
||||
juce::dsp::ProcessSpec limiterSpec { sampleRate, (juce::uint32) samplesPerBlock, numChannels };
|
||||
outputLimiter.reset();
|
||||
outputLimiter.prepare (limiterSpec);
|
||||
outputLimiter.setThreshold (-0.8f);
|
||||
outputLimiter.setRelease (0.05f);
|
||||
midiMessageCollector.reset(sampleRate);
|
||||
}
|
||||
|
||||
@@ -174,15 +221,6 @@ bool NeuralSynthAudioProcessor::isBusesLayoutSupported (const BusesLayout& layou
|
||||
|
||||
void NeuralSynthAudioProcessor::processBlock(juce::AudioSampleBuffer& buffer, juce::MidiBuffer& midiMessages)
|
||||
{
|
||||
const int newWaveform = sp.waveform.exchange(-1);
|
||||
|
||||
if (newWaveform != -1) {
|
||||
audioEngine.applyToVoices([newWaveform](NeuralSynthVoice* v)
|
||||
{
|
||||
v->changeWaveform(newWaveform);
|
||||
});
|
||||
}
|
||||
|
||||
juce::ScopedNoDenormals noDenormals;
|
||||
auto totalNumInputChannels = getTotalNumInputChannels();
|
||||
auto totalNumOutputChannels = getTotalNumOutputChannels();
|
||||
@@ -193,6 +231,8 @@ void NeuralSynthAudioProcessor::processBlock(juce::AudioSampleBuffer& buffer, ju
|
||||
buffer.clear(i, 0, buffer.getNumSamples());
|
||||
|
||||
audioEngine.renderNextBlock(buffer, midiMessages, 0, buffer.getNumSamples());
|
||||
juce::dsp::AudioBlock<float> outputBlock (buffer);
|
||||
outputLimiter.process (juce::dsp::ProcessContextReplacing<float> (outputBlock));
|
||||
scopeDataCollector.process(buffer.getReadPointer(0), (size_t)buffer.getNumSamples());
|
||||
}
|
||||
|
||||
@@ -210,9 +250,26 @@ void NeuralSynthAudioProcessor::setStateInformation (const void* data, int sizeI
|
||||
|
||||
void NeuralSynthAudioProcessor::parameterChanged(const juce::String& id, float newValue)
|
||||
{
|
||||
juce::ignoreUnused(newValue);
|
||||
if (id == "waveform")
|
||||
sp.waveform.store((int)newValue, std::memory_order_release);
|
||||
if (id == "wt_bank" && ! presetChangeInProgress)
|
||||
{
|
||||
const int targetBank = juce::jlimit(0, (int)WT::FactoryLibrary::get().size() - 1,
|
||||
(int) std::lround(newValue));
|
||||
int matched = -1;
|
||||
for (int i = 0; i < (int) factoryPresets.size(); ++i)
|
||||
{
|
||||
if (factoryPresets[(size_t)i].wtBankIndex == targetBank)
|
||||
{
|
||||
matched = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
currentPresetIndex = matched;
|
||||
}
|
||||
else if (id == "wt2_bank" && ! presetChangeInProgress)
|
||||
{
|
||||
juce::ignoreUnused(newValue);
|
||||
currentPresetIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
@@ -230,13 +287,610 @@ void NeuralSynthAudioProcessor::buildParams(std::vector<std::unique_ptr<juce::Ra
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<NeuralSynthAudioProcessor::PresetDefinition> NeuralSynthAudioProcessor::makeFactoryPresets()
|
||||
{
|
||||
std::vector<PresetDefinition> presets;
|
||||
const auto& wtLibrary = WT::FactoryLibrary::get();
|
||||
if (wtLibrary.empty())
|
||||
return presets;
|
||||
|
||||
presets.reserve(220);
|
||||
|
||||
std::map<juce::String, std::vector<int>> categoryToIndices;
|
||||
for (int i = 0; i < (int) wtLibrary.size(); ++i)
|
||||
categoryToIndices[wtLibrary[(size_t) i].category].push_back(i);
|
||||
|
||||
const std::array<juce::String, 12> requestedCategories = {
|
||||
"Electric Piano", "Organ", "Bass", "Drums", "Strings",
|
||||
"Brass", "Choir", "Pad", "SFX", "Lead", "Pluck", "Misc"
|
||||
};
|
||||
|
||||
static const std::array<std::pair<int, const char*>, 20> gmDrumInfo = {{
|
||||
{35, "Acoustic Bass Drum"},
|
||||
{36, "Bass Drum 1"},
|
||||
{37, "Side Stick"},
|
||||
{38, "Acoustic Snare"},
|
||||
{39, "Hand Clap"},
|
||||
{40, "Electric Snare"},
|
||||
{41, "Low Floor Tom"},
|
||||
{42, "Closed Hi-Hat"},
|
||||
{43, "High Floor Tom"},
|
||||
{44, "Pedal Hi-Hat"},
|
||||
{45, "Low Tom"},
|
||||
{46, "Open Hi-Hat"},
|
||||
{47, "Low-Mid Tom"},
|
||||
{48, "Hi-Mid Tom"},
|
||||
{49, "Crash Cymbal 1"},
|
||||
{50, "High Tom"},
|
||||
{51, "Ride Cymbal 1"},
|
||||
{52, "Chinese Cymbal"},
|
||||
{53, "Ride Bell"},
|
||||
{54, "Tambourine"}
|
||||
}};
|
||||
|
||||
auto clampMorph = [](float v) { return juce::jlimit(0.0f, 15.0f, v); };
|
||||
auto clampUnit = [](float v) { return juce::jlimit(0.0f, 1.0f, v); };
|
||||
auto clampLfoDepth = [](float v) { return juce::jlimit(0.0f, 8.0f, v); };
|
||||
auto clampLfoRate = [](float v) { return juce::jlimit(0.01f, 10.0f, v); };
|
||||
auto clampCutoff = [](float v) { return juce::jlimit(20.0f, 20000.0f, v); };
|
||||
auto clampRes = [](float v) { return juce::jlimit(0.1f, 10.0f, v); };
|
||||
auto clampDb = [](float v) { return juce::jlimit(-24.0f, 24.0f, v); };
|
||||
|
||||
for (const auto& category : requestedCategories)
|
||||
{
|
||||
auto mapIt = categoryToIndices.find(category);
|
||||
if (mapIt == categoryToIndices.end())
|
||||
continue;
|
||||
|
||||
const auto& indices = mapIt->second;
|
||||
if (indices.size() < 20)
|
||||
continue;
|
||||
|
||||
for (int variant = 0; variant < 20; ++variant)
|
||||
{
|
||||
const bool layered = variant >= 10;
|
||||
const int primaryIndex = indices[(size_t) (variant % indices.size())];
|
||||
const int secondaryIndex = layered ? indices[(size_t) ((variant + 5) % indices.size())]
|
||||
: primaryIndex;
|
||||
|
||||
const float t = (float) variant / 19.0f;
|
||||
const float subT = (float) (variant % 10) / 9.0f;
|
||||
|
||||
const bool isDrumCategory = (category == "Drums");
|
||||
std::pair<int, const char*> gmInfo { 0, "" };
|
||||
if (isDrumCategory)
|
||||
gmInfo = gmDrumInfo[(size_t) variant];
|
||||
|
||||
std::map<juce::String, float> values;
|
||||
auto set = [&](const juce::String& param, float value)
|
||||
{
|
||||
values[param] = value;
|
||||
};
|
||||
|
||||
set("wt_on", 1.0f);
|
||||
set("wt_bank", (float) primaryIndex);
|
||||
set("wt_morph", clampMorph(2.0f + 8.0f * t));
|
||||
set("wt_phase", 0.0f);
|
||||
set("wt_lfoRate", clampLfoRate(0.25f + 0.8f * t));
|
||||
set("wt_lfoDepth", clampLfoDepth(0.6f + 2.0f * t));
|
||||
set("wt_lfoShape", (float) (variant % 4));
|
||||
set("wt_level", clampUnit(layered ? 0.72f : 0.85f));
|
||||
|
||||
set("wt2_on", layered ? 1.0f : 0.0f);
|
||||
set("wt2_bank", (float) secondaryIndex);
|
||||
set("wt2_morph", layered ? clampMorph(4.0f + 6.0f * (1.0f - t)) : 0.0f);
|
||||
set("wt2_phase", layered ? 0.25f : 0.0f);
|
||||
set("wt2_lfoRate", clampLfoRate(layered ? (0.4f + 1.3f * (1.0f - t)) : 0.3f));
|
||||
set("wt2_lfoDepth", clampLfoDepth(layered ? (1.0f + 2.0f * subT) : 0.0f));
|
||||
set("wt2_lfoShape", layered ? (float) ((variant + 1) % 4) : 0.0f);
|
||||
set("wt2_level", layered ? clampUnit(0.5f + 0.3f * t) : 0.0f);
|
||||
|
||||
set("chorus_on", 0.0f);
|
||||
set("chorus_rate", clampUnit(0.3f));
|
||||
set("chorus_depth", clampUnit(0.3f));
|
||||
set("chorus_centre", clampUnit(0.5f));
|
||||
set("chorus_feedback", clampUnit(0.12f));
|
||||
set("chorus_mix", clampUnit(0.2f));
|
||||
|
||||
set("delay_on", 0.0f);
|
||||
set("delay_delay", clampUnit(0.2f));
|
||||
|
||||
set("reverb_on", 0.0f);
|
||||
set("reverb_roomSize", clampUnit(0.3f));
|
||||
set("reverb_damping", clampUnit(0.5f));
|
||||
set("reverb_wetLevel", clampUnit(0.18f));
|
||||
set("reverb_dryLevel", clampUnit(0.85f));
|
||||
set("reverb_width", clampUnit(0.9f));
|
||||
set("reverb_freezeMode", 0.0f);
|
||||
|
||||
set("flanger_on", 0.0f);
|
||||
set("flanger_rate", clampUnit(0.35f));
|
||||
set("flanger_depth", 2.5f);
|
||||
set("flanger_feedback", clampUnit(0.15f));
|
||||
set("flanger_dryMix", clampUnit(0.25f));
|
||||
set("flanger_phase", clampUnit(0.2f));
|
||||
set("flanger_delay", 0.2f);
|
||||
|
||||
set("distortion_on", 0.0f);
|
||||
set("distortion_drive", 10.0f);
|
||||
set("distortion_mix", clampUnit(0.2f));
|
||||
set("distortion_bias", 0.0f);
|
||||
set("distortion_tone", juce::jlimit(100.0f, 8000.0f, 2400.0f));
|
||||
set("distortion_shape", 0.0f);
|
||||
|
||||
set("filter_on", 0.0f);
|
||||
set("filter_cutoff", clampCutoff(2000.0f));
|
||||
set("filter_resonance", clampRes(0.7f));
|
||||
set("filter_type", 0.0f);
|
||||
set("filter_drive", 0.0f);
|
||||
set("filter_mod", 0.0f);
|
||||
set("filter_key", 0.0f);
|
||||
|
||||
set("adsr_attack", clampUnit(0.02f));
|
||||
set("adsr_decay", clampUnit(0.3f));
|
||||
set("adsr_sustain", clampUnit(0.7f));
|
||||
set("adsr_release", clampUnit(0.4f));
|
||||
|
||||
set("fenv_attack", juce::jlimit(0.0f, 2.0f, 0.03f));
|
||||
set("fenv_decay", juce::jlimit(0.0f, 2.0f, 0.3f));
|
||||
set("fenv_sustain", clampUnit(0.5f));
|
||||
set("fenv_release", juce::jlimit(0.0f, 4.0f, 0.4f));
|
||||
set("fenv_amount", juce::jlimit(-1.0f, 1.0f, 0.2f));
|
||||
|
||||
set("eq_on", 1.0f);
|
||||
set("lowEQ", clampDb(0.0f));
|
||||
set("midEQ", clampDb(0.0f));
|
||||
set("highEQ", clampDb(0.0f));
|
||||
|
||||
set("master", layered ? -8.0f : -6.0f);
|
||||
|
||||
if (category == "Electric Piano")
|
||||
{
|
||||
set("chorus_on", 1.0f);
|
||||
set("chorus_rate", clampUnit(0.18f + 0.25f * t));
|
||||
set("chorus_depth", clampUnit(0.35f + 0.2f * t));
|
||||
set("chorus_mix", clampUnit(0.2f + 0.15f * t));
|
||||
set("chorus_feedback", clampUnit(0.18f + 0.1f * t));
|
||||
set("reverb_on", 1.0f);
|
||||
set("reverb_roomSize", clampUnit(0.35f + 0.25f * t));
|
||||
set("reverb_wetLevel", clampUnit(0.2f + 0.12f * t));
|
||||
set("reverb_damping", clampUnit(0.45f + 0.1f * t));
|
||||
set("filter_on", 1.0f);
|
||||
set("filter_cutoff", clampCutoff(1500.0f + 700.0f * t));
|
||||
set("filter_resonance", clampRes(0.8f + 0.3f * t));
|
||||
set("fenv_amount", juce::jlimit(-1.0f, 1.0f, 0.35f + 0.15f * t));
|
||||
set("adsr_attack", clampUnit(0.02f + 0.03f * t));
|
||||
set("adsr_decay", clampUnit(0.25f + 0.1f * t));
|
||||
set("adsr_sustain", clampUnit(0.65f + 0.1f * t));
|
||||
set("adsr_release", clampUnit(0.45f + 0.18f * t));
|
||||
set("wt_level", clampUnit(layered ? 0.7f : 0.83f));
|
||||
if (layered)
|
||||
{
|
||||
set("wt2_level", clampUnit(0.55f + 0.2f * t));
|
||||
set("wt2_lfoRate", clampLfoRate(0.35f + 0.9f * (1.0f - t)));
|
||||
set("wt2_lfoDepth", clampLfoDepth(1.1f + 1.4f * t));
|
||||
}
|
||||
set("lowEQ", clampDb(1.5f));
|
||||
set("midEQ", clampDb(-1.0f + 2.5f * t));
|
||||
set("highEQ", clampDb(2.0f + 3.0f * t));
|
||||
}
|
||||
else if (category == "Organ")
|
||||
{
|
||||
set("chorus_on", 1.0f);
|
||||
set("chorus_rate", clampUnit(0.45f + 0.15f * t));
|
||||
set("chorus_depth", clampUnit(0.3f + 0.1f * t));
|
||||
set("chorus_mix", clampUnit(0.33f + 0.08f * t));
|
||||
set("chorus_feedback", clampUnit(0.15f + 0.05f * t));
|
||||
set("reverb_on", 1.0f);
|
||||
set("reverb_roomSize", clampUnit(0.25f + 0.2f * t));
|
||||
set("reverb_wetLevel", clampUnit(0.16f + 0.1f * t));
|
||||
set("reverb_damping", clampUnit(0.4f + 0.15f * t));
|
||||
set("filter_on", 0.0f);
|
||||
set("adsr_attack", clampUnit(0.01f));
|
||||
set("adsr_decay", clampUnit(0.3f));
|
||||
set("adsr_sustain", clampUnit(1.0f));
|
||||
set("adsr_release", clampUnit(0.3f + 0.2f * t));
|
||||
set("fenv_amount", 0.0f);
|
||||
set("wt_morph", clampMorph(3.0f + 5.0f * t));
|
||||
set("wt_lfoRate", clampLfoRate(0.4f + 0.45f * t));
|
||||
set("wt_lfoDepth", clampLfoDepth(0.25f + 0.35f * t));
|
||||
if (layered)
|
||||
{
|
||||
set("wt2_level", clampUnit(0.5f + 0.2f * t));
|
||||
set("wt2_lfoDepth", clampLfoDepth(0.4f + 0.5f * t));
|
||||
set("distortion_on", variant >= 15 ? 1.0f : 0.0f);
|
||||
if (variant >= 15)
|
||||
{
|
||||
set("distortion_drive", 9.0f + 5.0f * t);
|
||||
set("distortion_mix", clampUnit(0.18f + 0.12f * t));
|
||||
set("distortion_shape", 1.0f);
|
||||
}
|
||||
}
|
||||
set("midEQ", clampDb(1.5f + 1.0f * t));
|
||||
set("highEQ", clampDb(2.0f + 1.5f * t));
|
||||
set("master", layered ? -8.0f : -5.0f);
|
||||
}
|
||||
else if (category == "Bass")
|
||||
{
|
||||
set("wt_morph", clampMorph(1.5f + 5.5f * t));
|
||||
set("wt_lfoRate", clampLfoRate(0.2f + 0.6f * t));
|
||||
set("wt_lfoDepth", clampLfoDepth(0.5f + 1.3f * t));
|
||||
set("wt_level", clampUnit(0.92f));
|
||||
set("adsr_attack", clampUnit(0.005f));
|
||||
set("adsr_decay", clampUnit(0.18f + 0.08f * t));
|
||||
set("adsr_sustain", clampUnit(0.45f - 0.15f * t));
|
||||
set("adsr_release", clampUnit(0.22f + 0.12f * t));
|
||||
set("filter_on", 1.0f);
|
||||
set("filter_cutoff", clampCutoff(180.0f + 720.0f * t));
|
||||
set("filter_resonance", clampRes(0.85f + 0.35f * t));
|
||||
set("fenv_amount", juce::jlimit(-1.0f, 1.0f, 0.6f + 0.25f * t));
|
||||
set("distortion_on", (layered || variant >= 6) ? 1.0f : 0.0f);
|
||||
if (values["distortion_on"] > 0.5f)
|
||||
{
|
||||
set("distortion_drive", 14.0f + 8.0f * t);
|
||||
set("distortion_mix", clampUnit(0.25f + 0.25f * t));
|
||||
set("distortion_shape", 2.0f);
|
||||
}
|
||||
set("lowEQ", clampDb(3.5f + 2.0f * t));
|
||||
set("midEQ", clampDb(-2.5f + 1.8f * t));
|
||||
set("highEQ", clampDb(-5.0f + 2.0f * t));
|
||||
if (layered)
|
||||
{
|
||||
set("wt2_level", clampUnit(0.6f + 0.2f * t));
|
||||
set("wt2_lfoDepth", clampLfoDepth(0.8f + 1.6f * t));
|
||||
set("wt2_lfoRate", clampLfoRate(0.3f + 0.7f * t));
|
||||
}
|
||||
set("master", layered ? -7.5f : -5.0f);
|
||||
}
|
||||
else if (category == "Drums")
|
||||
{
|
||||
set("wt_morph", clampMorph(1.0f + 9.0f * t));
|
||||
set("wt_lfoRate", clampLfoRate(1.2f + 2.5f * t));
|
||||
set("wt_lfoDepth", clampLfoDepth(0.3f + 2.8f * t));
|
||||
set("wt_level", clampUnit(0.88f));
|
||||
set("adsr_attack", clampUnit(0.001f));
|
||||
set("adsr_decay", clampUnit(0.12f + 0.08f * t));
|
||||
set("adsr_sustain", clampUnit(0.05f));
|
||||
set("adsr_release", clampUnit(0.18f + 0.12f * t));
|
||||
set("fenv_amount", juce::jlimit(-1.0f, 1.0f, -0.2f + 0.4f * t));
|
||||
set("distortion_on", 1.0f);
|
||||
set("distortion_drive", 16.0f + 10.0f * t);
|
||||
set("distortion_mix", clampUnit(0.35f + 0.2f * t));
|
||||
set("distortion_shape", (float) (variant % 3));
|
||||
set("distortion_bias", juce::jlimit(-1.0f, 1.0f, 0.05f * (variant % 5)));
|
||||
set("reverb_on", layered ? 1.0f : (variant >= 8 ? 1.0f : 0.0f));
|
||||
if (values["reverb_on"] > 0.5f)
|
||||
{
|
||||
set("reverb_roomSize", clampUnit(layered ? (0.45f + 0.3f * t) : 0.35f + 0.15f * t));
|
||||
set("reverb_wetLevel", clampUnit(layered ? (0.3f + 0.18f * t) : 0.18f + 0.1f * t));
|
||||
set("reverb_damping", clampUnit(0.45f + 0.25f * t));
|
||||
}
|
||||
set("filter_on", layered ? 1.0f : 0.0f);
|
||||
if (values["filter_on"] > 0.5f)
|
||||
{
|
||||
set("filter_cutoff", clampCutoff(800.0f + 1200.0f * t));
|
||||
set("filter_resonance", clampRes(1.0f + 0.6f * t));
|
||||
set("fenv_amount", juce::jlimit(-1.0f, 1.0f, 0.1f + 0.35f * t));
|
||||
}
|
||||
if (layered)
|
||||
{
|
||||
set("wt2_level", clampUnit(0.6f + 0.25f * t));
|
||||
set("wt2_lfoRate", clampLfoRate(0.9f + 1.6f * (1.0f - t)));
|
||||
set("wt2_lfoDepth", clampLfoDepth(1.3f + 1.7f * t));
|
||||
}
|
||||
set("lowEQ", clampDb(4.0f + 2.0f * t));
|
||||
set("midEQ", clampDb(-4.0f + 3.0f * t));
|
||||
set("highEQ", clampDb(3.0f + 4.0f * t));
|
||||
set("master", layered ? -8.5f : -6.5f);
|
||||
}
|
||||
else if (category == "Strings")
|
||||
{
|
||||
set("wt_morph", clampMorph(3.0f + 9.0f * t));
|
||||
set("wt_lfoRate", clampLfoRate(0.18f + 0.4f * t));
|
||||
set("wt_lfoDepth", clampLfoDepth(0.8f + 1.8f * t));
|
||||
set("adsr_attack", clampUnit(0.22f + 0.18f * t));
|
||||
set("adsr_decay", clampUnit(0.3f + 0.12f * t));
|
||||
set("adsr_sustain", clampUnit(0.85f));
|
||||
set("adsr_release", clampUnit(0.6f + 0.25f * t));
|
||||
set("chorus_on", 1.0f);
|
||||
set("chorus_rate", clampUnit(0.25f + 0.1f * t));
|
||||
set("chorus_depth", clampUnit(0.45f + 0.15f * t));
|
||||
set("chorus_mix", clampUnit(0.3f + 0.1f * t));
|
||||
set("reverb_on", 1.0f);
|
||||
set("reverb_roomSize", clampUnit(0.55f + 0.2f * t));
|
||||
set("reverb_wetLevel", clampUnit(0.35f + 0.15f * t));
|
||||
set("filter_on", 1.0f);
|
||||
set("filter_cutoff", clampCutoff(2600.0f + 1500.0f * t));
|
||||
set("filter_resonance", clampRes(0.85f + 0.25f * t));
|
||||
set("fenv_amount", juce::jlimit(-1.0f, 1.0f, 0.25f + 0.1f * t));
|
||||
if (layered)
|
||||
{
|
||||
set("wt2_level", clampUnit(0.5f + 0.25f * t));
|
||||
set("wt2_lfoDepth", clampLfoDepth(1.0f + 1.5f * t));
|
||||
}
|
||||
set("midEQ", clampDb(-1.0f + 2.0f * t));
|
||||
set("highEQ", clampDb(2.5f + 2.5f * t));
|
||||
set("master", -7.5f);
|
||||
}
|
||||
else if (category == "Brass")
|
||||
{
|
||||
set("adsr_attack", clampUnit(0.05f + 0.05f * t));
|
||||
set("adsr_decay", clampUnit(0.25f + 0.1f * t));
|
||||
set("adsr_sustain", clampUnit(0.75f));
|
||||
set("adsr_release", clampUnit(0.35f + 0.15f * t));
|
||||
set("filter_on", 1.0f);
|
||||
set("filter_cutoff", clampCutoff(2200.0f + 1800.0f * t));
|
||||
set("filter_resonance", clampRes(1.0f + 0.3f * t));
|
||||
set("fenv_amount", juce::jlimit(-1.0f, 1.0f, 0.55f + 0.25f * t));
|
||||
set("reverb_on", 1.0f);
|
||||
set("reverb_roomSize", clampUnit(0.4f + 0.25f * t));
|
||||
set("reverb_wetLevel", clampUnit(0.3f + 0.1f * t));
|
||||
set("distortion_on", (layered || variant >= 8) ? 1.0f : 0.0f);
|
||||
if (values["distortion_on"] > 0.5f)
|
||||
{
|
||||
set("distortion_drive", 10.0f + 6.0f * t);
|
||||
set("distortion_mix", clampUnit(0.18f + 0.18f * t));
|
||||
set("distortion_shape", 1.0f);
|
||||
}
|
||||
set("flanger_on", layered ? 1.0f : 0.0f);
|
||||
if (values["flanger_on"] > 0.5f)
|
||||
{
|
||||
set("flanger_rate", clampUnit(0.35f + 0.25f * t));
|
||||
set("flanger_depth", 4.0f + 3.0f * t);
|
||||
set("flanger_dryMix", clampUnit(0.5f));
|
||||
}
|
||||
if (layered)
|
||||
{
|
||||
set("wt2_level", clampUnit(0.52f + 0.22f * t));
|
||||
set("wt2_lfoDepth", clampLfoDepth(0.8f + 1.4f * t));
|
||||
}
|
||||
set("lowEQ", clampDb(2.0f + 1.0f * t));
|
||||
set("midEQ", clampDb(1.0f + 1.5f * t));
|
||||
set("highEQ", clampDb(1.0f + 2.5f * t));
|
||||
}
|
||||
else if (category == "Choir")
|
||||
{
|
||||
set("adsr_attack", clampUnit(0.3f + 0.2f * t));
|
||||
set("adsr_decay", clampUnit(0.4f + 0.1f * t));
|
||||
set("adsr_sustain", clampUnit(0.9f));
|
||||
set("adsr_release", clampUnit(0.55f + 0.3f * t));
|
||||
set("chorus_on", 1.0f);
|
||||
set("chorus_rate", clampUnit(0.2f + 0.15f * t));
|
||||
set("chorus_depth", clampUnit(0.5f + 0.2f * t));
|
||||
set("chorus_mix", clampUnit(0.35f + 0.15f * t));
|
||||
set("reverb_on", 1.0f);
|
||||
set("reverb_roomSize", clampUnit(0.6f + 0.25f * t));
|
||||
set("reverb_wetLevel", clampUnit(0.4f + 0.15f * t));
|
||||
set("filter_on", 1.0f);
|
||||
set("filter_cutoff", clampCutoff(1800.0f + 800.0f * t));
|
||||
set("filter_resonance", clampRes(0.7f + 0.2f * t));
|
||||
set("fenv_amount", juce::jlimit(-1.0f, 1.0f, 0.15f + 0.08f * t));
|
||||
set("wt_lfoDepth", clampLfoDepth(1.0f + 2.0f * t));
|
||||
if (layered)
|
||||
{
|
||||
set("wt2_level", clampUnit(0.48f + 0.2f * t));
|
||||
set("wt2_lfoDepth", clampLfoDepth(1.2f + 1.5f * t));
|
||||
}
|
||||
set("midEQ", clampDb(-1.5f + 1.5f * t));
|
||||
set("highEQ", clampDb(3.0f + 2.0f * t));
|
||||
set("master", -7.5f);
|
||||
}
|
||||
else if (category == "Pad")
|
||||
{
|
||||
set("adsr_attack", clampUnit(0.35f + 0.25f * t));
|
||||
set("adsr_decay", clampUnit(0.35f + 0.15f * t));
|
||||
set("adsr_sustain", clampUnit(0.85f));
|
||||
set("adsr_release", clampUnit(0.7f + 0.35f * t));
|
||||
set("chorus_on", 1.0f);
|
||||
set("chorus_rate", clampUnit(0.18f + 0.12f * t));
|
||||
set("chorus_depth", clampUnit(0.55f + 0.2f * t));
|
||||
set("chorus_mix", clampUnit(0.35f + 0.15f * t));
|
||||
set("reverb_on", 1.0f);
|
||||
set("reverb_roomSize", clampUnit(0.65f + 0.25f * t));
|
||||
set("reverb_wetLevel", clampUnit(0.4f + 0.2f * t));
|
||||
set("filter_on", 1.0f);
|
||||
set("filter_cutoff", clampCutoff(1500.0f + 900.0f * t));
|
||||
set("filter_resonance", clampRes(0.8f + 0.25f * t));
|
||||
set("fenv_amount", juce::jlimit(-1.0f, 1.0f, 0.2f + 0.12f * t));
|
||||
set("flanger_on", (layered || variant % 3 == 0) ? 1.0f : 0.0f);
|
||||
if (values["flanger_on"] > 0.5f)
|
||||
{
|
||||
set("flanger_rate", clampUnit(0.25f + 0.15f * t));
|
||||
set("flanger_depth", 5.0f + 3.0f * t);
|
||||
set("flanger_dryMix", clampUnit(0.4f));
|
||||
}
|
||||
set("wt_lfoRate", clampLfoRate(0.15f + 0.35f * t));
|
||||
set("wt_lfoDepth", clampLfoDepth(1.5f + 2.5f * t));
|
||||
if (layered)
|
||||
{
|
||||
set("wt2_level", clampUnit(0.5f + 0.3f * t));
|
||||
set("wt2_lfoDepth", clampLfoDepth(1.3f + 2.0f * t));
|
||||
}
|
||||
set("master", -8.5f);
|
||||
}
|
||||
else if (category == "SFX")
|
||||
{
|
||||
set("wt_morph", clampMorph(4.0f + 10.0f * t));
|
||||
set("wt_lfoRate", clampLfoRate(1.2f + 3.5f * t));
|
||||
set("wt_lfoDepth", clampLfoDepth(2.5f + 5.0f * t));
|
||||
set("wt_lfoShape", (float) (variant % 4));
|
||||
set("wt_phase", (variant % 2 == 0) ? 0.0f : 0.5f);
|
||||
set("chorus_on", 1.0f);
|
||||
set("chorus_rate", clampUnit(0.35f + 0.3f * t));
|
||||
set("chorus_depth", clampUnit(0.45f + 0.25f * t));
|
||||
set("chorus_mix", clampUnit(0.3f + 0.2f * t));
|
||||
set("flanger_on", 1.0f);
|
||||
set("flanger_rate", clampUnit(0.45f + 0.4f * t));
|
||||
set("flanger_depth", 6.0f + 4.0f * t);
|
||||
set("flanger_phase", clampUnit(0.2f + 0.5f * t));
|
||||
set("flanger_dryMix", clampUnit(0.5f));
|
||||
set("distortion_on", 1.0f);
|
||||
set("distortion_drive", 18.0f + 7.0f * t);
|
||||
set("distortion_mix", clampUnit(0.35f + 0.2f * t));
|
||||
set("distortion_shape", (float) ((variant + 1) % 3));
|
||||
set("distortion_bias", juce::jlimit(-1.0f, 1.0f, -0.2f + 0.4f * t));
|
||||
set("reverb_on", 1.0f);
|
||||
set("reverb_roomSize", clampUnit(0.7f + 0.2f * t));
|
||||
set("reverb_wetLevel", clampUnit(0.45f + 0.2f * t));
|
||||
if (layered)
|
||||
{
|
||||
set("wt2_level", clampUnit(0.6f + 0.25f * t));
|
||||
set("wt2_morph", clampMorph(6.0f + 7.0f * (1.0f - t)));
|
||||
set("wt2_lfoRate", clampLfoRate(0.8f + 4.0f * (1.0f - t)));
|
||||
set("wt2_lfoDepth", clampLfoDepth(2.0f + 4.0f * t));
|
||||
set("wt2_lfoShape", (float) ((variant + 2) % 4));
|
||||
}
|
||||
set("lowEQ", clampDb(-4.0f + 4.0f * t));
|
||||
set("midEQ", clampDb(3.0f - 4.0f * t));
|
||||
set("highEQ", clampDb(6.0f + 4.0f * t));
|
||||
set("master", -12.0f);
|
||||
}
|
||||
else if (category == "Lead")
|
||||
{
|
||||
set("wt_morph", clampMorph(3.0f + 8.0f * t));
|
||||
set("wt_lfoRate", clampLfoRate(0.4f + 1.2f * t));
|
||||
set("wt_lfoDepth", clampLfoDepth(1.0f + 2.0f * t));
|
||||
set("adsr_attack", clampUnit(0.01f + 0.02f * t));
|
||||
set("adsr_decay", clampUnit(0.18f + 0.08f * t));
|
||||
set("adsr_sustain", clampUnit(0.85f));
|
||||
set("adsr_release", clampUnit(0.25f + 0.1f * t));
|
||||
set("filter_on", 1.0f);
|
||||
set("filter_cutoff", clampCutoff(2300.0f + 3200.0f * t));
|
||||
set("filter_resonance", clampRes(0.9f + 0.25f * t));
|
||||
set("fenv_amount", juce::jlimit(-1.0f, 1.0f, 0.45f + 0.25f * t));
|
||||
set("distortion_on", 1.0f);
|
||||
set("distortion_drive", 12.0f + 10.0f * t);
|
||||
set("distortion_mix", clampUnit(0.25f + 0.25f * t));
|
||||
set("distortion_shape", (float) ((variant % 2) + 1));
|
||||
set("chorus_on", (layered || variant % 3 == 0) ? 1.0f : 0.0f);
|
||||
if (values["chorus_on"] > 0.5f)
|
||||
{
|
||||
set("chorus_rate", clampUnit(0.3f + 0.2f * t));
|
||||
set("chorus_depth", clampUnit(0.4f + 0.2f * t));
|
||||
set("chorus_mix", clampUnit(0.25f + 0.15f * t));
|
||||
}
|
||||
set("reverb_on", 1.0f);
|
||||
set("reverb_roomSize", clampUnit(0.35f + 0.25f * t));
|
||||
set("reverb_wetLevel", clampUnit(0.22f + 0.15f * t));
|
||||
if (layered)
|
||||
{
|
||||
set("wt2_level", clampUnit(0.52f + 0.22f * t));
|
||||
set("wt2_lfoDepth", clampLfoDepth(1.1f + 1.6f * t));
|
||||
}
|
||||
set("lowEQ", clampDb(-1.5f + 1.5f * t));
|
||||
set("midEQ", clampDb(2.0f + 1.5f * t));
|
||||
set("highEQ", clampDb(4.0f + 3.0f * t));
|
||||
set("master", layered ? -7.5f : -6.0f);
|
||||
}
|
||||
else if (category == "Pluck")
|
||||
{
|
||||
set("wt_morph", clampMorph(2.5f + 7.0f * t));
|
||||
set("wt_lfoRate", clampLfoRate(0.25f + 0.7f * t));
|
||||
set("wt_lfoDepth", clampLfoDepth(0.6f + 1.8f * t));
|
||||
set("adsr_attack", clampUnit(0.005f));
|
||||
set("adsr_decay", clampUnit(0.22f + 0.15f * t));
|
||||
set("adsr_sustain", clampUnit(0.2f + 0.1f * t));
|
||||
set("adsr_release", clampUnit(0.25f + 0.1f * t));
|
||||
set("fenv_amount", juce::jlimit(-1.0f, 1.0f, 0.4f + 0.2f * t));
|
||||
set("filter_on", 1.0f);
|
||||
set("filter_cutoff", clampCutoff(1800.0f + 2000.0f * t));
|
||||
set("filter_resonance", clampRes(1.1f + 0.3f * t));
|
||||
set("delay_on", 1.0f);
|
||||
set("delay_delay", clampUnit(0.25f + 0.25f * t));
|
||||
set("reverb_on", 1.0f);
|
||||
set("reverb_roomSize", clampUnit(0.45f + 0.25f * t));
|
||||
set("reverb_wetLevel", clampUnit(0.25f + 0.15f * t));
|
||||
set("chorus_on", 0.0f);
|
||||
set("distortion_on", variant >= 12 ? 1.0f : 0.0f);
|
||||
if (values["distortion_on"] > 0.5f)
|
||||
{
|
||||
set("distortion_drive", 10.0f + 8.0f * t);
|
||||
set("distortion_mix", clampUnit(0.2f + 0.2f * t));
|
||||
set("distortion_shape", 2.0f);
|
||||
}
|
||||
if (layered)
|
||||
{
|
||||
set("wt2_level", clampUnit(0.48f + 0.25f * t));
|
||||
set("wt2_lfoDepth", clampLfoDepth(0.9f + 1.5f * t));
|
||||
}
|
||||
set("lowEQ", clampDb(-1.0f + 2.0f * t));
|
||||
set("midEQ", clampDb(-2.0f + 3.0f * t));
|
||||
set("highEQ", clampDb(3.0f + 2.5f * t));
|
||||
}
|
||||
|
||||
juce::String presetName;
|
||||
if (isDrumCategory)
|
||||
{
|
||||
presetName = juce::String::formatted("GM %d %s%s",
|
||||
gmInfo.first,
|
||||
gmInfo.second,
|
||||
layered ? " Stack" : "");
|
||||
}
|
||||
else
|
||||
{
|
||||
presetName = category + (layered ? " Duo " : " Solo ")
|
||||
+ juce::String(variant + 1).paddedLeft('0', 2);
|
||||
}
|
||||
|
||||
auto scaleLevel = [&](const juce::String& paramId, float factor)
|
||||
{
|
||||
auto it = values.find(paramId);
|
||||
if (it != values.end())
|
||||
it->second = juce::jlimit(0.0f, 1.0f, it->second * factor);
|
||||
};
|
||||
|
||||
scaleLevel("wt_level", 0.75f);
|
||||
scaleLevel("wt2_level", 0.75f);
|
||||
|
||||
if (auto it = values.find("master"); it != values.end())
|
||||
it->second = juce::jlimit(-24.0f, 24.0f, it->second - 4.0f);
|
||||
|
||||
PresetDefinition def;
|
||||
def.category = category;
|
||||
def.name = presetName.trim();
|
||||
def.wtBankIndex = primaryIndex;
|
||||
def.wt2BankIndex = layered ? secondaryIndex : -1;
|
||||
def.parameterValues.reserve(values.size());
|
||||
for (const auto& entry : values)
|
||||
def.parameterValues.emplace_back(entry.first, entry.second);
|
||||
|
||||
presets.push_back(std::move(def));
|
||||
}
|
||||
}
|
||||
|
||||
return presets;
|
||||
}
|
||||
|
||||
void NeuralSynthAudioProcessor::setParameterValue(const juce::String& paramID, float value)
|
||||
{
|
||||
if (parameters.getParameter(paramID) != nullptr)
|
||||
parameters.getParameterAsValue(paramID) = value;
|
||||
}
|
||||
|
||||
void NeuralSynthAudioProcessor::applyPreset(int index)
|
||||
{
|
||||
if (factoryPresets.empty())
|
||||
return;
|
||||
|
||||
index = juce::jlimit(0, (int) factoryPresets.size() - 1, index);
|
||||
const auto& preset = factoryPresets[(size_t) index];
|
||||
|
||||
juce::ScopedValueSetter<bool> guard(presetChangeInProgress, true, false);
|
||||
|
||||
for (const auto& entry : preset.parameterValues)
|
||||
setParameterValue(entry.first, entry.second);
|
||||
|
||||
currentPresetIndex = index;
|
||||
}
|
||||
|
||||
juce::AudioProcessorValueTreeState::ParameterLayout NeuralSynthAudioProcessor::createParameterLayout()
|
||||
{
|
||||
std::vector<std::unique_ptr<juce::RangedAudioParameter>> params;
|
||||
|
||||
params.push_back(std::make_unique<juce::AudioParameterChoice>(
|
||||
"waveform", "Waveform",
|
||||
juce::StringArray{ "Sine", "Saw", "Square", "Triangle" }, 0));
|
||||
params.push_back(std::make_unique<juce::AudioParameterBool>(
|
||||
"wt_on", "Layer A On", true));
|
||||
params.push_back(std::make_unique<juce::AudioParameterBool>(
|
||||
"wt2_on", "Layer B On", false));
|
||||
|
||||
// Per-panel bypass toggles (default OFF)
|
||||
params.push_back(std::make_unique<juce::AudioParameterBool>("chorus_on", "Chorus On", false));
|
||||
@@ -255,9 +909,11 @@ juce::AudioProcessorValueTreeState::ParameterLayout NeuralSynthAudioProcessor::c
|
||||
buildParams(params, "flanger");
|
||||
buildParams(params, "distortion");
|
||||
buildParams(params, "filter");
|
||||
buildParams(params, "wt");
|
||||
buildParams(params, "wt2");
|
||||
|
||||
params.push_back(std::make_unique<juce::AudioParameterFloat>("master", "Master",
|
||||
juce::NormalisableRange<float>(-24.0f, 24.0f, 0.1f), 0.1f));
|
||||
juce::NormalisableRange<float>(-24.0f, 24.0f, 0.1f), -6.0f));
|
||||
|
||||
params.push_back(std::make_unique<juce::AudioParameterFloat>("lowEQ", "Low Gain",
|
||||
juce::NormalisableRange<float>(-24.0f, 24.0f, 0.1f), 0.5f));
|
||||
|
||||
@@ -12,6 +12,15 @@ class NeuralSynthAudioProcessor : public juce::AudioProcessor,
|
||||
private juce::AudioProcessorValueTreeState::Listener
|
||||
{
|
||||
public:
|
||||
struct PresetDefinition
|
||||
{
|
||||
juce::String category;
|
||||
juce::String name;
|
||||
int wtBankIndex;
|
||||
int wt2BankIndex { -1 };
|
||||
std::vector<std::pair<juce::String, float>> parameterValues;
|
||||
};
|
||||
|
||||
NeuralSynthAudioProcessor();
|
||||
~NeuralSynthAudioProcessor() override;
|
||||
|
||||
@@ -53,6 +62,10 @@ public:
|
||||
const std::string& paramGroup);
|
||||
juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout();
|
||||
|
||||
void applyPreset(int index);
|
||||
const std::vector<PresetDefinition>& getFactoryPresets() const noexcept { return factoryPresets; }
|
||||
int getCurrentPresetIndex() const noexcept { return currentPresetIndex; }
|
||||
|
||||
// Utilities
|
||||
juce::MidiMessageCollector& getMidiMessageCollector() noexcept { return midiMessageCollector; }
|
||||
AudioBufferQueue<float>& getAudioBufferQueue() noexcept { return audioBufferQueue; }
|
||||
@@ -87,4 +100,13 @@ private:
|
||||
|
||||
// Scope collector (uses audioBufferQueue, so declare after it)
|
||||
ScopeDataCollector<float> scopeDataCollector { audioBufferQueue };
|
||||
|
||||
std::vector<PresetDefinition> factoryPresets;
|
||||
int currentPresetIndex { -1 };
|
||||
bool presetChangeInProgress { false };
|
||||
|
||||
static std::vector<PresetDefinition> makeFactoryPresets();
|
||||
void setParameterValue(const juce::String& paramID, float value);
|
||||
|
||||
juce::dsp::Limiter<float> outputLimiter;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user