Proteus

Guitar amp and pedal capture plugin using neural networks
Log | Files | Refs | Submodules | README

commit dd0606e1f41a292b60a453250db332f0a66fe05d
parent 87c2c552c3afc13288a6ba01753673b80ea4e8d2
Author: Keith Bloemer <32459398+GuitarML@users.noreply.github.com>
Date:   Tue, 18 Oct 2022 13:49:01 -0500

Merge pull request #1 from GuitarML/updates-v1-1

Updates v1 1
Diffstat:
MCMakeLists.txt | 11++++++++---
Minstallers/linux/build_deb.sh | 2+-
Msrc/PluginEditor.cpp | 30+++++++++++++++++++++++-------
Msrc/PluginEditor.h | 2+-
Msrc/PluginProcessor.cpp | 40++++++++++++++++++++++++++++++----------
Msrc/PluginProcessor.h | 4++++
6 files changed, 67 insertions(+), 22 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -1,15 +1,15 @@ cmake_minimum_required(VERSION 3.15) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.12" CACHE STRING "Minimum OS X deployment target") -project(Proteus VERSION 1.0.0) +project(Proteus VERSION 1.1.0) set(CMAKE_CXX_STANDARD 17) add_subdirectory(modules) include_directories(modules) -#juce_set_aax_sdk_path(C:/SDKs/AAX_SDK/) +juce_set_aax_sdk_path(C:/SDKs/AAX_SDK/) -set(JUCE_FORMATS AU VST3 Standalone) +set(JUCE_FORMATS AU VST3) # Build LV2 only on Linux if(UNIX AND NOT APPLE) @@ -31,6 +31,11 @@ juce_add_plugin(Proteus ProductName "Proteus" LV2URI https://github.com/GuitarML/Proteus ICON_BIG resources/logo.png + + VST3_CATEGORIES Fx Distortion + AU_MAIN_TYPE kAudioUnitType_Effect + AAX_CATEGORY AAX_ePlugInCategory_Harmonic + MICROPHONE_PERMISSION_ENABLED TRUE ) diff --git a/installers/linux/build_deb.sh b/installers/linux/build_deb.sh @@ -3,7 +3,7 @@ # Set the app name and version here app_name=Proteus -version=1.0 +version=1.1 # 1. Create the package directory structure and control file diff --git a/src/PluginEditor.cpp b/src/PluginEditor.cpp @@ -81,7 +81,7 @@ ProteusAudioProcessorEditor::ProteusAudioProcessorEditor (ProteusAudioProcessor& odLevelKnob.setDoubleClickReturnValue(true, 0.5); addAndMakeVisible(versionLabel); - versionLabel.setText("v1.0", juce::NotificationType::dontSendNotification); + versionLabel.setText("v1.1", juce::NotificationType::dontSendNotification); versionLabel.setJustificationType(juce::Justification::left); versionLabel.setColour(juce::Label::textColourId, juce::Colours::white); //auto font = versionLabel.getFont(); @@ -176,7 +176,7 @@ bool ProteusAudioProcessorEditor::isValidFormat(File configFile) } void ProteusAudioProcessorEditor::loadButtonClicked() -{ +{ myChooser = std::make_unique<FileChooser> ("Select a folder to load models from", processor.folder, "*.json"); @@ -188,6 +188,7 @@ void ProteusAudioProcessorEditor::loadButtonClicked() if (!chooser.getResult().exists()) { return; } + processor.model_loaded = false; Array<File> files; if (chooser.getResult().existsAsFile()) { // If a file is selected @@ -229,6 +230,8 @@ void ProteusAudioProcessorEditor::loadButtonClicked() modelSelectChanged(); } } + } else { + processor.saved_model = ""; // Clear the saved model since there's nothing in the dropdown } }); @@ -236,7 +239,7 @@ void ProteusAudioProcessorEditor::loadButtonClicked() void ProteusAudioProcessorEditor::loadFromFolder() { - + processor.model_loaded = false; Array<File> files; files = processor.folder.findChildFiles(2, false, "*.json"); @@ -252,9 +255,19 @@ void ProteusAudioProcessorEditor::loadFromFolder() processor.num_models += 1; } } + // Try to load model from saved_model, if it doesnt exist and jsonFiles is not empty, load the first model (if it exists and is valid format) if (!processor.jsonFiles.empty()) { - processor.loadConfig(processor.jsonFiles[processor.current_model_index]); - modelSelect.setText(processor.jsonFiles[processor.current_model_index].getFileNameWithoutExtension(), juce::NotificationType::dontSendNotification); + if (processor.saved_model.existsAsFile() && isValidFormat(processor.saved_model)) { + processor.loadConfig(processor.saved_model); + modelSelect.setText(processor.saved_model.getFileNameWithoutExtension(), juce::NotificationType::dontSendNotification); + } else { + if (processor.jsonFiles[0].existsAsFile() && isValidFormat(processor.jsonFiles[0])) { + processor.loadConfig(processor.jsonFiles[0]); + modelSelect.setText(processor.jsonFiles[0].getFileNameWithoutExtension(), juce::NotificationType::dontSendNotification); + } + } + //processor.loadConfig(processor.jsonFiles[processor.current_model_index]); + //modelSelect.setText(processor.jsonFiles[processor.current_model_index].getFileNameWithoutExtension(), juce::NotificationType::dontSendNotification); } } } @@ -286,8 +299,11 @@ void ProteusAudioProcessorEditor::modelSelectChanged() { const int selectedFileIndex = modelSelect.getSelectedItemIndex(); if (selectedFileIndex >= 0 && selectedFileIndex < processor.jsonFiles.size() && processor.jsonFiles.empty() == false) { //check if correct - processor.loadConfig(processor.jsonFiles[selectedFileIndex]); - processor.current_model_index = selectedFileIndex; + if (processor.jsonFiles[selectedFileIndex].existsAsFile() && isValidFormat(processor.jsonFiles[selectedFileIndex])) { + processor.loadConfig(processor.jsonFiles[selectedFileIndex]); + processor.current_model_index = selectedFileIndex; + processor.saved_model = processor.jsonFiles[selectedFileIndex]; + } } repaint(); } diff --git a/src/PluginEditor.h b/src/PluginEditor.h @@ -74,7 +74,7 @@ private: void odFootSwClicked(); void modelSelectChanged(); - + bool model_loaded = false; public: std::unique_ptr <AudioProcessorValueTreeState::SliderAttachment> driveSliderAttach; diff --git a/src/PluginProcessor.cpp b/src/PluginProcessor.cpp @@ -31,6 +31,12 @@ ProteusAudioProcessor::ProteusAudioProcessor() { driveParam = treeState.getRawParameterValue (GAIN_ID); masterParam = treeState.getRawParameterValue (MASTER_ID); + + pauseVolume = 3; + + // Check if this works to load without GUI -> This doesnt work + //if (auto* editor = dynamic_cast<ProteusAudioProcessorEditor*> (getActiveEditor())) + // editor->loadFromFolder(); } ProteusAudioProcessor::~ProteusAudioProcessor() @@ -105,6 +111,8 @@ void ProteusAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBloc // Use this method as the place to do any pre-playback // initialisation that you need.. + *dcBlocker.state = *dsp::IIR::Coefficients<float>::makeHighPass (sampleRate, 35.0f); + // prepare resampler for target sample rate: 44.1 kHz constexpr double targetSampleRate = 44100.0; //resampler.prepareWithTargetSampleRate ({ sampleRate, (uint32) samplesPerBlock, 1 }, targetSampleRate); @@ -114,6 +122,8 @@ void ProteusAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBloc dsp::ProcessSpec specMono { sampleRate, static_cast<uint32> (samplesPerBlock), 1 }; dsp::ProcessSpec spec{ sampleRate, static_cast<uint32> (samplesPerBlock), 2 }; + dcBlocker.prepare (spec); + LSTM.reset(); LSTM2.reset(); @@ -162,11 +172,11 @@ void ProteusAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer const int numInputChannels = getTotalNumInputChannels(); dsp::AudioBlock<float> block(buffer); + dsp::ProcessContextReplacing<float> context(block); // Overdrive Pedal ================================================================== - if (fw_state == 1) { + if (fw_state == 1 && model_loaded == true) { - if (conditioned == false) { // Apply ramped changes for gain smoothing if (driveValue == previousDriveValue) @@ -207,16 +217,16 @@ void ProteusAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer resampler.processOut(block44k, block); } - + dcBlocker.process(context); // Master Volume // Apply ramped changes for gain smoothing if (masterValue == previousMasterValue) { - buffer.applyGain(masterValue*1.2); + buffer.applyGain(masterValue); } else { - buffer.applyGainRamp(0, (int) buffer.getNumSamples(), previousMasterValue * 1.2, masterValue * 1.2); + buffer.applyGainRamp(0, (int) buffer.getNumSamples(), previousMasterValue, masterValue); previousMasterValue = masterValue; } @@ -225,9 +235,9 @@ void ProteusAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer if (pauseVolume > 2) buffer.applyGain(0.0); else if (pauseVolume == 2) - buffer.applyGainRamp(0, (int)buffer.getNumSamples(), 0, masterValue * 1.2 / 2); + buffer.applyGainRamp(0, (int)buffer.getNumSamples(), 0, masterValue / 2); else - buffer.applyGainRamp(0, (int)buffer.getNumSamples(), masterValue * 1.2 / 2, masterValue * 1.2); + buffer.applyGainRamp(0, (int)buffer.getNumSamples(), masterValue / 2, masterValue); pauseVolume -= 1; } } @@ -274,14 +284,22 @@ void ProteusAudioProcessor::setStateInformation (const void* data, int sizeInByt { treeState.replaceState (juce::ValueTree::fromXml (*xmlState)); fw_state = xmlState->getBoolAttribute ("fw_state"); - saved_model = xmlState->getStringAttribute("saved_model"); + File temp_saved_model = xmlState->getStringAttribute("saved_model"); + saved_model = temp_saved_model; + //saved_model = xmlState->getStringAttribute("saved_model"); + current_model_index = xmlState->getIntAttribute("current_model_index"); File temp = xmlState->getStringAttribute("folder"); folder = temp; if (auto* editor = dynamic_cast<ProteusAudioProcessorEditor*> (getActiveEditor())) editor->resetImages(); - if (auto* editor = dynamic_cast<ProteusAudioProcessorEditor*> (getActiveEditor())) - editor->loadFromFolder(); + //if (auto* editor = dynamic_cast<ProteusAudioProcessorEditor*> (getActiveEditor())) + // editor->loadFromFolder(); + + //if (isValidFormat(saved_model)) { + if (saved_model.existsAsFile()) { + loadConfig(saved_model); + } } } @@ -307,6 +325,8 @@ void ProteusAudioProcessor::loadConfig(File configFile) conditioned = true; } + //saved_model = configFile; + model_loaded = true; this->suspendProcessing(false); } diff --git a/src/PluginProcessor.h b/src/PluginProcessor.h @@ -87,6 +87,8 @@ public: int pauseVolume = 3; + bool model_loaded = false; + private: std::atomic<float>* driveParam = nullptr; @@ -99,6 +101,8 @@ private: RT_LSTM LSTM; RT_LSTM LSTM2; + dsp::ProcessorDuplicator<dsp::IIR::Filter<float>, dsp::IIR::Coefficients<float>> dcBlocker; + chowdsp::ResampledProcess<chowdsp::ResamplingTypes::SRCResampler<>> resampler; //==============================================================================