#include "PluginProcessor.h" #include "PluginEditor.h" //============================================================================== NeuralSynthAudioProcessor::NeuralSynthAudioProcessor() : parameters(*this, nullptr, "PARAMETERS", createParameterLayout()) , AudioProcessor(BusesProperties().withOutput("Output", juce::AudioChannelSet::stereo(), true)) , audioEngine(sp) { parameters.addParameterListener("waveform", this); // === Per-panel bypass (default OFF) === sp.chorusOn = parameters.getRawParameterValue("chorus_on"); sp.delayOn = parameters.getRawParameterValue("delay_on"); sp.reverbOn = parameters.getRawParameterValue("reverb_on"); sp.flangerOn = parameters.getRawParameterValue("flanger_on"); sp.distortionOn = parameters.getRawParameterValue("distortion_on"); sp.filterOn = parameters.getRawParameterValue("filter_on"); sp.eqOn = parameters.getRawParameterValue("eq_on"); // === Chorus === parameters.addParameterListener("chorus_rate", this); parameters.addParameterListener("chorus_depth", this); parameters.addParameterListener("chorus_centre", this); parameters.addParameterListener("chorus_feedback", this); parameters.addParameterListener("chorus_mix", this); sp.chorusRate = parameters.getRawParameterValue("chorus_rate"); sp.chorusDepth = parameters.getRawParameterValue("chorus_depth"); sp.chorusCentre = parameters.getRawParameterValue("chorus_centre"); sp.chorusFeedback = parameters.getRawParameterValue("chorus_feedback"); sp.chorusMix = parameters.getRawParameterValue("chorus_mix"); // === Delay === parameters.addParameterListener("delay_delay", this); sp.delayTime = parameters.getRawParameterValue("delay_delay"); // === Reverb === parameters.addParameterListener("reverb_roomSize", this); parameters.addParameterListener("reverb_damping", this); parameters.addParameterListener("reverb_wetLevel", this); parameters.addParameterListener("reverb_dryLevel", this); parameters.addParameterListener("reverb_width", this); parameters.addParameterListener("reverb_freezeMode", this); sp.reverbRoomSize = parameters.getRawParameterValue("reverb_roomSize"); sp.reverbDamping = parameters.getRawParameterValue("reverb_damping"); sp.reverbWetLevel = parameters.getRawParameterValue("reverb_wetLevel"); sp.reverbDryLevel = parameters.getRawParameterValue("reverb_dryLevel"); sp.reverbWidth = parameters.getRawParameterValue("reverb_width"); sp.reverbFreezeMode= parameters.getRawParameterValue("reverb_freezeMode"); // === Amp ADSR === parameters.addParameterListener("adsr_attack", this); parameters.addParameterListener("adsr_decay", this); parameters.addParameterListener("adsr_sustain", this); parameters.addParameterListener("adsr_release", this); sp.adsrAttack = parameters.getRawParameterValue("adsr_attack"); sp.adsrDecay = parameters.getRawParameterValue("adsr_decay"); sp.adsrSustain = parameters.getRawParameterValue("adsr_sustain"); sp.adsrRelease = parameters.getRawParameterValue("adsr_release"); // === Filter Env === parameters.addParameterListener("fenv_attack", this); parameters.addParameterListener("fenv_decay", this); parameters.addParameterListener("fenv_sustain", this); parameters.addParameterListener("fenv_release", this); parameters.addParameterListener("fenv_amount", this); sp.fenvAttack = parameters.getRawParameterValue("fenv_attack"); sp.fenvDecay = parameters.getRawParameterValue("fenv_decay"); sp.fenvSustain = parameters.getRawParameterValue("fenv_sustain"); sp.fenvRelease = parameters.getRawParameterValue("fenv_release"); sp.fenvAmount = parameters.getRawParameterValue("fenv_amount"); // === Filter base === parameters.addParameterListener("filter_cutoff", this); parameters.addParameterListener("filter_resonance", this); parameters.addParameterListener("filter_type", this); parameters.addParameterListener("filter_drive", this); parameters.addParameterListener("filter_mod", this); parameters.addParameterListener("filter_key", this); sp.filterCutoff = parameters.getRawParameterValue("filter_cutoff"); sp.filterResonance = parameters.getRawParameterValue("filter_resonance"); sp.filterType = parameters.getRawParameterValue("filter_type"); sp.filterDrive = parameters.getRawParameterValue("filter_drive"); sp.filterMod = parameters.getRawParameterValue("filter_mod"); sp.filterKey = parameters.getRawParameterValue("filter_key"); // === Distortion === parameters.addParameterListener("distortion_drive", this); parameters.addParameterListener("distortion_mix", this); parameters.addParameterListener("distortion_bias", this); parameters.addParameterListener("distortion_tone", this); parameters.addParameterListener("distortion_shape", this); sp.distortionDrive = parameters.getRawParameterValue("distortion_drive"); sp.distortionMix = parameters.getRawParameterValue("distortion_mix"); sp.distortionBias = parameters.getRawParameterValue("distortion_bias"); sp.distortionTone = parameters.getRawParameterValue("distortion_tone"); sp.distortionShape = parameters.getRawParameterValue("distortion_shape"); // === Master / EQ === parameters.addParameterListener("master", this); parameters.addParameterListener("lowEQ", this); parameters.addParameterListener("midEQ", this); parameters.addParameterListener("highEQ", this); sp.masterDbls = parameters.getRawParameterValue("master"); sp.lowGainDbls = parameters.getRawParameterValue("lowEQ"); sp.midGainDbls = parameters.getRawParameterValue("midEQ"); sp.highGainDbls = parameters.getRawParameterValue("highEQ"); } NeuralSynthAudioProcessor::~NeuralSynthAudioProcessor() = default; //============================================================================== const juce::String NeuralSynthAudioProcessor::getName() const { return JucePlugin_Name; } bool NeuralSynthAudioProcessor::acceptsMidi() const { #if JucePlugin_WantsMidiInput return true; #else return false; #endif } bool NeuralSynthAudioProcessor::producesMidi() const { #if JucePlugin_ProducesMidiOutput return true; #else return false; #endif } bool NeuralSynthAudioProcessor::isMidiEffect() const { #if JucePlugin_IsMidiEffect return true; #else return false; #endif } double NeuralSynthAudioProcessor::getTailLengthSeconds() const { return 0.0; } int NeuralSynthAudioProcessor::getNumPrograms() { return 1; } int NeuralSynthAudioProcessor::getCurrentProgram() { return 0; } void NeuralSynthAudioProcessor::setCurrentProgram (int) {} const juce::String NeuralSynthAudioProcessor::getProgramName (int) { return {}; } void NeuralSynthAudioProcessor::changeProgramName (int, const juce::String&) {} //============================================================================== void NeuralSynthAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) { audioEngine.prepare({ sampleRate, (juce::uint32)samplesPerBlock, 2 }); midiMessageCollector.reset(sampleRate); } void NeuralSynthAudioProcessor::releaseResources() {} bool NeuralSynthAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const { if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::mono() && layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo()) return false; return true; } 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(); midiMessageCollector.removeNextBlockOfMessages(midiMessages, buffer.getNumSamples()); for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i) buffer.clear(i, 0, buffer.getNumSamples()); audioEngine.renderNextBlock(buffer, midiMessages, 0, buffer.getNumSamples()); scopeDataCollector.process(buffer.getReadPointer(0), (size_t)buffer.getNumSamples()); } //============================================================================== bool NeuralSynthAudioProcessor::hasEditor() const { return true; } juce::AudioProcessorEditor* NeuralSynthAudioProcessor::createEditor() { return new NeuralSynthAudioProcessorEditor (*this); } //============================================================================== void NeuralSynthAudioProcessor::getStateInformation (juce::MemoryBlock& destData) { juce::ignoreUnused(destData); } void NeuralSynthAudioProcessor::setStateInformation (const void* data, int sizeInBytes) { juce::ignoreUnused(data, sizeInBytes); } void NeuralSynthAudioProcessor::parameterChanged(const juce::String& id, float newValue) { juce::ignoreUnused(newValue); if (id == "waveform") sp.waveform.store((int)newValue, std::memory_order_release); } //============================================================================== // This creates new instances of the plugin.. juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter() { return new NeuralSynthAudioProcessor(); } void NeuralSynthAudioProcessor::buildParams(std::vector>& params, const std::string& paramGroup) { const auto& paramGroupSettings = PARAM_SETTINGS.at(paramGroup); for (const auto& [name, s] : paramGroupSettings) { params.push_back(std::make_unique( paramGroup + "_" + name, s.label, juce::NormalisableRange(s.min, s.max, s.interval), s.defValue)); } } juce::AudioProcessorValueTreeState::ParameterLayout NeuralSynthAudioProcessor::createParameterLayout() { std::vector> params; params.push_back(std::make_unique( "waveform", "Waveform", juce::StringArray{ "Sine", "Saw", "Square", "Triangle" }, 0)); // Per-panel bypass toggles (default OFF) params.push_back(std::make_unique("chorus_on", "Chorus On", false)); params.push_back(std::make_unique("delay_on", "Delay On", false)); params.push_back(std::make_unique("reverb_on", "Reverb On", false)); params.push_back(std::make_unique("flanger_on", "Flanger On", false)); params.push_back(std::make_unique("distortion_on", "Distortion On", false)); params.push_back(std::make_unique("filter_on", "Filter On", false)); params.push_back(std::make_unique("eq_on", "EQ On", false)); buildParams(params, "adsr"); buildParams(params, "fenv"); buildParams(params, "chorus"); buildParams(params, "delay"); buildParams(params, "reverb"); buildParams(params, "flanger"); buildParams(params, "distortion"); buildParams(params, "filter"); params.push_back(std::make_unique("master", "Master", juce::NormalisableRange(-24.0f, 24.0f, 0.1f), 0.1f)); params.push_back(std::make_unique("lowEQ", "Low Gain", juce::NormalisableRange(-24.0f, 24.0f, 0.1f), 0.5f)); params.push_back(std::make_unique("midEQ", "Mid EQ", juce::NormalisableRange(-24.0f, 24.0f, 0.1f), 0.8f)); params.push_back(std::make_unique("highEQ", "High EQ", juce::NormalisableRange(-24.0f, 24.0f, 0.1f), 1.0f)); return { params.begin(), params.end() }; }