/* ============================================================================== This file contains the basic framework code for a JUCE plugin processor. ============================================================================== */ #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); //sp.waveform = parameters.getRawParameterValue("waveform"); // === 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"); // === 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"); // === Flanger === parameters.addParameterListener("flanger_rate", this); parameters.addParameterListener("flanger_depth", this); parameters.addParameterListener("flanger_feedback", this); parameters.addParameterListener("flanger_dryMix", this); parameters.addParameterListener("flanger_phase", this); parameters.addParameterListener("flanger_delay", this); sp.flangerRate = parameters.getRawParameterValue("flanger_rate"); sp.flangerDepth = parameters.getRawParameterValue("flanger_depth"); sp.flangerFeedback = parameters.getRawParameterValue("flanger_feedback"); sp.flangerDryMix = parameters.getRawParameterValue("flanger_dryMix"); sp.flangerPhase = parameters.getRawParameterValue("flanger_phase"); sp.flangerDelay = parameters.getRawParameterValue("flanger_delay"); // === Filter === 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"); 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() { } //============================================================================== 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; // NB: some hosts don't cope very well if you tell them there are 0 programs, // so this should be at least 1, even if you're not really implementing programs. } int NeuralSynthAudioProcessor::getCurrentProgram() { return 0; } void NeuralSynthAudioProcessor::setCurrentProgram (int index) { } const juce::String NeuralSynthAudioProcessor::getProgramName (int index) { return {}; } void NeuralSynthAudioProcessor::changeProgramName (int index, const juce::String& newName) { } //============================================================================== void NeuralSynthAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) { audioEngine.prepare({ sampleRate, (juce::uint32)samplesPerBlock, 2 }); midiMessageCollector.reset(sampleRate); } void NeuralSynthAudioProcessor::releaseResources() { // When playback stops, you can use this as an opportunity to free up any // spare memory, etc. } bool NeuralSynthAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const { // This is the place where you check if the layout is supported. // In this template code we only support mono or stereo. 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; // (change this to false if you choose to not supply an editor) } juce::AudioProcessorEditor* NeuralSynthAudioProcessor::createEditor() { return new NeuralSynthAudioProcessorEditor (*this); } //============================================================================== void NeuralSynthAudioProcessor::getStateInformation (juce::MemoryBlock& destData) { // You should use this method to store your parameters in the memory block. // You could do that either as raw data, or use the XML or ValueTree classes // as intermediaries to make it easy to save and load complex data. } void NeuralSynthAudioProcessor::setStateInformation (const void* data, int sizeInBytes) { // You should use this method to restore your parameters from this memory block, // whose contents will have been created by the getStateInformation() call. } void NeuralSynthAudioProcessor::parameterChanged(const juce::String& id, float 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> ¶ms, const std::string& paramGroup) { const auto& paramGroupSettings = PARAM_SETTINGS.at(paramGroup); for (const auto& [name, paramSettings] : paramGroupSettings) { params.push_back(std::make_unique(paramGroup + "_" + name, paramSettings.label, juce::NormalisableRange(paramSettings.min, paramSettings.max, paramSettings.interval), paramSettings.defValue)); } } juce::AudioProcessorValueTreeState::ParameterLayout NeuralSynthAudioProcessor::createParameterLayout() { std::vector> params; params.push_back(std::make_unique( "waveform", "Waveform", juce::StringArray{ "Sine", "Saw", "Square", "Triangle" }, 0)); buildParams(params, "adsr"); 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() }; }