commit 01d446af2d465e348136fe60b60ce7d7aef3f265 Author: Timothy Scully Date: Mon Jun 23 00:16:47 2025 +0100 Initial plugin version diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ed2aabc --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Builds +NeuralSynth Installer.exe diff --git a/JuceLibraryCode/JuceHeader.h b/JuceLibraryCode/JuceHeader.h new file mode 100644 index 0000000..bfa7f03 --- /dev/null +++ b/JuceLibraryCode/JuceHeader.h @@ -0,0 +1,49 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + + This is the header file that your files should include in order to get all the + JUCE library headers. You should avoid including the JUCE headers directly in + your own source files, because that wouldn't pick up the correct configuration + options for your app. + +*/ + +#pragma once + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#if defined (JUCE_PROJUCER_VERSION) && JUCE_PROJUCER_VERSION < JUCE_VERSION + /** If you've hit this error then the version of the Projucer that was used to generate this project is + older than the version of the JUCE modules being included. To fix this error, re-save your project + using the latest version of the Projucer or, if you aren't using the Projucer to manage your project, + remove the JUCE_PROJUCER_VERSION define. + */ + #error "This project was last saved using an outdated version of the Projucer! Re-save this project with the latest version to fix this error." +#endif + + +#if ! JUCE_DONT_DECLARE_PROJECTINFO +namespace ProjectInfo +{ + const char* const projectName = "NeuralSynth"; + const char* const companyName = ""; + const char* const versionString = "1.0.0"; + const int versionNumber = 0x10000; +} +#endif diff --git a/JuceLibraryCode/JucePluginDefines.h b/JuceLibraryCode/JucePluginDefines.h new file mode 100644 index 0000000..f47135b --- /dev/null +++ b/JuceLibraryCode/JucePluginDefines.h @@ -0,0 +1,162 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#pragma once + +//============================================================================== +// Audio plugin settings.. + +#ifndef JucePlugin_Build_VST + #define JucePlugin_Build_VST 0 +#endif +#ifndef JucePlugin_Build_VST3 + #define JucePlugin_Build_VST3 1 +#endif +#ifndef JucePlugin_Build_AU + #define JucePlugin_Build_AU 1 +#endif +#ifndef JucePlugin_Build_AUv3 + #define JucePlugin_Build_AUv3 0 +#endif +#ifndef JucePlugin_Build_AAX + #define JucePlugin_Build_AAX 0 +#endif +#ifndef JucePlugin_Build_Standalone + #define JucePlugin_Build_Standalone 1 +#endif +#ifndef JucePlugin_Build_Unity + #define JucePlugin_Build_Unity 0 +#endif +#ifndef JucePlugin_Build_LV2 + #define JucePlugin_Build_LV2 0 +#endif +#ifndef JucePlugin_Enable_IAA + #define JucePlugin_Enable_IAA 0 +#endif +#ifndef JucePlugin_Enable_ARA + #define JucePlugin_Enable_ARA 0 +#endif +#ifndef JucePlugin_Name + #define JucePlugin_Name "NeuralSynth" +#endif +#ifndef JucePlugin_Desc + #define JucePlugin_Desc "NeuralSynth" +#endif +#ifndef JucePlugin_Manufacturer + #define JucePlugin_Manufacturer "yourcompany" +#endif +#ifndef JucePlugin_ManufacturerWebsite + #define JucePlugin_ManufacturerWebsite "www.yourcompany.com" +#endif +#ifndef JucePlugin_ManufacturerEmail + #define JucePlugin_ManufacturerEmail "" +#endif +#ifndef JucePlugin_ManufacturerCode + #define JucePlugin_ManufacturerCode 0x4d616e75 +#endif +#ifndef JucePlugin_PluginCode + #define JucePlugin_PluginCode 0x4d73347a +#endif +#ifndef JucePlugin_IsSynth + #define JucePlugin_IsSynth 0 +#endif +#ifndef JucePlugin_WantsMidiInput + #define JucePlugin_WantsMidiInput 0 +#endif +#ifndef JucePlugin_ProducesMidiOutput + #define JucePlugin_ProducesMidiOutput 0 +#endif +#ifndef JucePlugin_IsMidiEffect + #define JucePlugin_IsMidiEffect 0 +#endif +#ifndef JucePlugin_EditorRequiresKeyboardFocus + #define JucePlugin_EditorRequiresKeyboardFocus 0 +#endif +#ifndef JucePlugin_Version + #define JucePlugin_Version 1.0.0 +#endif +#ifndef JucePlugin_VersionCode + #define JucePlugin_VersionCode 0x10000 +#endif +#ifndef JucePlugin_VersionString + #define JucePlugin_VersionString "1.0.0" +#endif +#ifndef JucePlugin_VSTUniqueID + #define JucePlugin_VSTUniqueID JucePlugin_PluginCode +#endif +#ifndef JucePlugin_VSTCategory + #define JucePlugin_VSTCategory kPlugCategEffect +#endif +#ifndef JucePlugin_Vst3Category + #define JucePlugin_Vst3Category "Fx" +#endif +#ifndef JucePlugin_AUMainType + #define JucePlugin_AUMainType 'aufx' +#endif +#ifndef JucePlugin_AUSubType + #define JucePlugin_AUSubType JucePlugin_PluginCode +#endif +#ifndef JucePlugin_AUExportPrefix + #define JucePlugin_AUExportPrefix NeuralSynthAU +#endif +#ifndef JucePlugin_AUExportPrefixQuoted + #define JucePlugin_AUExportPrefixQuoted "NeuralSynthAU" +#endif +#ifndef JucePlugin_AUManufacturerCode + #define JucePlugin_AUManufacturerCode JucePlugin_ManufacturerCode +#endif +#ifndef JucePlugin_CFBundleIdentifier + #define JucePlugin_CFBundleIdentifier com.yourcompany.NeuralSynth +#endif +#ifndef JucePlugin_AAXIdentifier + #define JucePlugin_AAXIdentifier com.yourcompany.NeuralSynth +#endif +#ifndef JucePlugin_AAXManufacturerCode + #define JucePlugin_AAXManufacturerCode JucePlugin_ManufacturerCode +#endif +#ifndef JucePlugin_AAXProductId + #define JucePlugin_AAXProductId JucePlugin_PluginCode +#endif +#ifndef JucePlugin_AAXCategory + #define JucePlugin_AAXCategory 0 +#endif +#ifndef JucePlugin_AAXDisableBypass + #define JucePlugin_AAXDisableBypass 0 +#endif +#ifndef JucePlugin_AAXDisableMultiMono + #define JucePlugin_AAXDisableMultiMono 0 +#endif +#ifndef JucePlugin_IAAType + #define JucePlugin_IAAType 0x61757278 +#endif +#ifndef JucePlugin_IAASubType + #define JucePlugin_IAASubType JucePlugin_PluginCode +#endif +#ifndef JucePlugin_IAAName + #define JucePlugin_IAAName "yourcompany: NeuralSynth" +#endif +#ifndef JucePlugin_VSTNumMidiInputs + #define JucePlugin_VSTNumMidiInputs 16 +#endif +#ifndef JucePlugin_VSTNumMidiOutputs + #define JucePlugin_VSTNumMidiOutputs 16 +#endif +#ifndef JucePlugin_ARAContentTypes + #define JucePlugin_ARAContentTypes 0 +#endif +#ifndef JucePlugin_ARATransformationFlags + #define JucePlugin_ARATransformationFlags 0 +#endif +#ifndef JucePlugin_ARAFactoryID + #define JucePlugin_ARAFactoryID "com.yourcompany.NeuralSynth.factory" +#endif +#ifndef JucePlugin_ARADocumentArchiveID + #define JucePlugin_ARADocumentArchiveID "com.yourcompany.NeuralSynth.aradocumentarchive.1.0.0" +#endif +#ifndef JucePlugin_ARACompatibleArchiveIDs + #define JucePlugin_ARACompatibleArchiveIDs "" +#endif diff --git a/JuceLibraryCode/ReadMe.txt b/JuceLibraryCode/ReadMe.txt new file mode 100644 index 0000000..1e6784f --- /dev/null +++ b/JuceLibraryCode/ReadMe.txt @@ -0,0 +1,12 @@ + + Important Note!! + ================ + +The purpose of this folder is to contain files that are auto-generated by the Projucer, +and ALL files in this folder will be mercilessly DELETED and completely re-written whenever +the Projucer saves your project. + +Therefore, it's a bad idea to make any manual changes to the files in here, or to +put any of your own files in here if you don't want to lose them. (Of course you may choose +to add the folder's contents to your version-control system so that you can re-merge your own +modifications after the Projucer has saved its changes). diff --git a/JuceLibraryCode/include_juce_audio_basics.cpp b/JuceLibraryCode/include_juce_audio_basics.cpp new file mode 100644 index 0000000..4070844 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_basics.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_basics.mm b/JuceLibraryCode/include_juce_audio_basics.mm new file mode 100644 index 0000000..0c09914 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_basics.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_devices.cpp b/JuceLibraryCode/include_juce_audio_devices.cpp new file mode 100644 index 0000000..c9c2d11 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_devices.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_devices.mm b/JuceLibraryCode/include_juce_audio_devices.mm new file mode 100644 index 0000000..77e69b1 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_devices.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_formats.cpp b/JuceLibraryCode/include_juce_audio_formats.cpp new file mode 100644 index 0000000..78e74f7 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_formats.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_formats.mm b/JuceLibraryCode/include_juce_audio_formats.mm new file mode 100644 index 0000000..0adf319 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_formats.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_plugin_client_AAX.cpp b/JuceLibraryCode/include_juce_audio_plugin_client_AAX.cpp new file mode 100644 index 0000000..a20d1e3 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_plugin_client_AAX.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_plugin_client_AAX.mm b/JuceLibraryCode/include_juce_audio_plugin_client_AAX.mm new file mode 100644 index 0000000..0d740d8 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_plugin_client_AAX.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_plugin_client_AAX_utils.cpp b/JuceLibraryCode/include_juce_audio_plugin_client_AAX_utils.cpp new file mode 100644 index 0000000..5463093 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_plugin_client_AAX_utils.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_plugin_client_ARA.cpp b/JuceLibraryCode/include_juce_audio_plugin_client_ARA.cpp new file mode 100644 index 0000000..d64efb0 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_plugin_client_ARA.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_plugin_client_AU_1.mm b/JuceLibraryCode/include_juce_audio_plugin_client_AU_1.mm new file mode 100644 index 0000000..0924b03 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_plugin_client_AU_1.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_plugin_client_AU_2.mm b/JuceLibraryCode/include_juce_audio_plugin_client_AU_2.mm new file mode 100644 index 0000000..402f054 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_plugin_client_AU_2.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_plugin_client_AUv3.mm b/JuceLibraryCode/include_juce_audio_plugin_client_AUv3.mm new file mode 100644 index 0000000..5c705a2 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_plugin_client_AUv3.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_plugin_client_LV2.cpp b/JuceLibraryCode/include_juce_audio_plugin_client_LV2.cpp new file mode 100644 index 0000000..dd2858f --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_plugin_client_LV2.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_plugin_client_LV2.mm b/JuceLibraryCode/include_juce_audio_plugin_client_LV2.mm new file mode 100644 index 0000000..ef6fab7 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_plugin_client_LV2.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_plugin_client_Standalone.cpp b/JuceLibraryCode/include_juce_audio_plugin_client_Standalone.cpp new file mode 100644 index 0000000..198ae8c --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_plugin_client_Standalone.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_plugin_client_Unity.cpp b/JuceLibraryCode/include_juce_audio_plugin_client_Unity.cpp new file mode 100644 index 0000000..acf6830 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_plugin_client_Unity.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_plugin_client_VST2.cpp b/JuceLibraryCode/include_juce_audio_plugin_client_VST2.cpp new file mode 100644 index 0000000..b019de9 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_plugin_client_VST2.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_plugin_client_VST2.mm b/JuceLibraryCode/include_juce_audio_plugin_client_VST2.mm new file mode 100644 index 0000000..5923412 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_plugin_client_VST2.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_plugin_client_VST3.cpp b/JuceLibraryCode/include_juce_audio_plugin_client_VST3.cpp new file mode 100644 index 0000000..ac79442 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_plugin_client_VST3.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_plugin_client_VST3.mm b/JuceLibraryCode/include_juce_audio_plugin_client_VST3.mm new file mode 100644 index 0000000..f6f7943 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_plugin_client_VST3.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_processors.cpp b/JuceLibraryCode/include_juce_audio_processors.cpp new file mode 100644 index 0000000..0dbc0b6 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_processors.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_processors.mm b/JuceLibraryCode/include_juce_audio_processors.mm new file mode 100644 index 0000000..dac7f37 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_processors.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_processors_ara.cpp b/JuceLibraryCode/include_juce_audio_processors_ara.cpp new file mode 100644 index 0000000..1651fc5 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_processors_ara.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_processors_lv2_libs.cpp b/JuceLibraryCode/include_juce_audio_processors_lv2_libs.cpp new file mode 100644 index 0000000..1151b5a --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_processors_lv2_libs.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_utils.cpp b/JuceLibraryCode/include_juce_audio_utils.cpp new file mode 100644 index 0000000..f31e8b6 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_utils.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_audio_utils.mm b/JuceLibraryCode/include_juce_audio_utils.mm new file mode 100644 index 0000000..4dfd5b4 --- /dev/null +++ b/JuceLibraryCode/include_juce_audio_utils.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_core.cpp b/JuceLibraryCode/include_juce_core.cpp new file mode 100644 index 0000000..6f55178 --- /dev/null +++ b/JuceLibraryCode/include_juce_core.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_core.mm b/JuceLibraryCode/include_juce_core.mm new file mode 100644 index 0000000..db83b69 --- /dev/null +++ b/JuceLibraryCode/include_juce_core.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_core_CompilationTime.cpp b/JuceLibraryCode/include_juce_core_CompilationTime.cpp new file mode 100644 index 0000000..789042d --- /dev/null +++ b/JuceLibraryCode/include_juce_core_CompilationTime.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_data_structures.cpp b/JuceLibraryCode/include_juce_data_structures.cpp new file mode 100644 index 0000000..f53f241 --- /dev/null +++ b/JuceLibraryCode/include_juce_data_structures.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_data_structures.mm b/JuceLibraryCode/include_juce_data_structures.mm new file mode 100644 index 0000000..db212c9 --- /dev/null +++ b/JuceLibraryCode/include_juce_data_structures.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_dsp.cpp b/JuceLibraryCode/include_juce_dsp.cpp new file mode 100644 index 0000000..ec2c898 --- /dev/null +++ b/JuceLibraryCode/include_juce_dsp.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_dsp.mm b/JuceLibraryCode/include_juce_dsp.mm new file mode 100644 index 0000000..e641589 --- /dev/null +++ b/JuceLibraryCode/include_juce_dsp.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_events.cpp b/JuceLibraryCode/include_juce_events.cpp new file mode 100644 index 0000000..33a3a69 --- /dev/null +++ b/JuceLibraryCode/include_juce_events.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_events.mm b/JuceLibraryCode/include_juce_events.mm new file mode 100644 index 0000000..6ad0eda --- /dev/null +++ b/JuceLibraryCode/include_juce_events.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_graphics.cpp b/JuceLibraryCode/include_juce_graphics.cpp new file mode 100644 index 0000000..12f6750 --- /dev/null +++ b/JuceLibraryCode/include_juce_graphics.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_graphics.mm b/JuceLibraryCode/include_juce_graphics.mm new file mode 100644 index 0000000..ab22eb4 --- /dev/null +++ b/JuceLibraryCode/include_juce_graphics.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_graphics_Harfbuzz.cpp b/JuceLibraryCode/include_juce_graphics_Harfbuzz.cpp new file mode 100644 index 0000000..419cf23 --- /dev/null +++ b/JuceLibraryCode/include_juce_graphics_Harfbuzz.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_graphics_Sheenbidi.c b/JuceLibraryCode/include_juce_graphics_Sheenbidi.c new file mode 100644 index 0000000..df5eb4b --- /dev/null +++ b/JuceLibraryCode/include_juce_graphics_Sheenbidi.c @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_gui_basics.cpp b/JuceLibraryCode/include_juce_gui_basics.cpp new file mode 100644 index 0000000..80a5878 --- /dev/null +++ b/JuceLibraryCode/include_juce_gui_basics.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_gui_basics.mm b/JuceLibraryCode/include_juce_gui_basics.mm new file mode 100644 index 0000000..708837c --- /dev/null +++ b/JuceLibraryCode/include_juce_gui_basics.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_gui_extra.cpp b/JuceLibraryCode/include_juce_gui_extra.cpp new file mode 100644 index 0000000..ea050e5 --- /dev/null +++ b/JuceLibraryCode/include_juce_gui_extra.cpp @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/JuceLibraryCode/include_juce_gui_extra.mm b/JuceLibraryCode/include_juce_gui_extra.mm new file mode 100644 index 0000000..9bb3fea --- /dev/null +++ b/JuceLibraryCode/include_juce_gui_extra.mm @@ -0,0 +1,8 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + +*/ + +#include diff --git a/NeuralSynth.iss b/NeuralSynth.iss new file mode 100644 index 0000000..8606a46 --- /dev/null +++ b/NeuralSynth.iss @@ -0,0 +1,98 @@ +[Setup] +AppName=NeuralSynth +AppVersion=1.0.0 +DefaultDirName={pf}\NeuralSynth +DefaultGroupName=NeuralSynth +Compression=lzma2 +SolidCompression=yes +OutputDir=.\ +ArchitecturesInstallIn64BitMode=x64 +OutputBaseFilename=NeuralSynth Installer +;LicenseFile=license.rtf +SetupLogging=yes + +[Types] +Name: "full"; Description: "Full installation" +Name: "custom"; Description: "Custom installation"; Flags: iscustom + +[Components] +Name: "app"; Description: "Standalone application (.exe)"; Types: full custom; +;Name: "vst2_32"; Description: "32-bit VST2 Plugin (.dll)"; Types: full custom; +;Name: "vst2_64"; Description: "64-bit VST2 Plugin (.dll)"; Types: full custom; Check: Is64BitInstallMode; +;Name: "vst3_32"; Description: "32-bit VST3 Plugin (.vst3)"; Types: full custom; +Name: "vst3_64"; Description: "64-bit VST3 Plugin (.vst3)"; Types: full custom; Check: Is64BitInstallMode; +;Name: "rtas_32"; Description: "32-bit RTAS Plugin (.dpm)"; Types: full custom; +;Name: "aax_32"; Description: "32-bit AAX Plugin (.aaxplugin)"; Types: full custom; +;Name: "aax_64"; Description: "64-bit AAX Plugin (.aaxplugin)"; Types: full custom; Check: Is64BitInstallMode; +;Name: "manual"; Description: "User guide"; Types: full custom; Flags: fixed + +[Files] +;Source: "..\build-win\app\Win32\bin\NeuralSynth.exe"; DestDir: "{app}"; Check: not Is64BitInstallMode; Components:app; Flags: ignoreversion; +Source: "Builds\VisualStudio2022\x64\Release\Standalone Plugin\NeuralSynth.exe"; DestDir: "{app}"; Check: Is64BitInstallMode; Components:app; Flags: ignoreversion; + +;Source: "..\build-win\vst2\Win32\bin\NeuralSynth.dll"; DestDir: {code:GetVST2Dir_32}; Check: not Is64BitInstallMode; Components:vst2_32; Flags: ignoreversion; +;Source: "..\build-win\vst2\Win32\bin\NeuralSynth.dll"; DestDir: {code:GetVST2Dir_32}; Check: Is64BitInstallMode; Components:vst2_32; Flags: ignoreversion; +;Source: "..\build-win\vst2\x64\bin\NeuralSynth.dll"; DestDir: {code:GetVST2Dir_64}; Check: Is64BitInstallMode; Components:vst2_64; Flags: ignoreversion; + +;Source: "..\build-win\vst3\Win32\bin\NeuralSynth.vst3"; DestDir: "{cf}\VST3\"; Check: not Is64BitInstallMode; Components:vst3_32; Flags: ignoreversion; +;Source: "..\build-win\vst3\Win32\bin\NeuralSynth.vst3"; DestDir: "{cf32}\VST3\"; Check: Is64BitInstallMode; Components:vst3_32; Flags: ignoreversion; +Source: "Builds\VisualStudio2022\x64\Release\VST3\NeuralSynth.vst3\Contents\x86_64-win\NeuralSynth.vst3"; DestDir: "{cf64}\VST3\"; Check: Is64BitInstallMode; Components:vst3_64; Flags: ignoreversion; + +;Source: "..\build-win\rtas\bin\NeuralSynth.dpm"; DestDir: "{cf32}\Digidesign\DAE\Plug-Ins\"; Components:rtas_32; Flags: ignoreversion; +;Source: "..\build-win\rtas\bin\NeuralSynth.dpm.rsr"; DestDir: "{cf32}\Digidesign\DAE\Plug-Ins\"; Components:rtas_32; Flags: ignoreversion; + +;Source: "..\build-win\aax\bin\NeuralSynth.aaxplugin\*.*"; DestDir: "{cf32}\Avid\Audio\Plug-Ins\NeuralSynth.aaxplugin\"; Components:aax_32; Flags: ignoreversion recursesubdirs; +;Source: "..\build-win\aax\bin\NeuralSynth.aaxplugin\*.*"; DestDir: "{cf}\Avid\Audio\Plug-Ins\NeuralSynth.aaxplugin\"; Components:aax_64; Flags: ignoreversion recursesubdirs; + +;Source: "..\manual\NeuralSynth_manual.pdf"; DestDir: "{app}" +;Source: "changelog.txt"; DestDir: "{app}" +;Source: "readmewin.rtf"; DestDir: "{app}"; DestName: "readme.rtf"; Flags: isreadme + +[Icons] +Name: "{group}\NeuralSynth"; Filename: "{app}\NeuralSynth.exe" +;Name: "{group}\User guide"; Filename: "{app}\NeuralSynth_manual.pdf" +;Name: "{group}\Changelog"; Filename: "{app}\changelog.txt" +;Name: "{group}\readme"; Filename: "{app}\readme.rtf" +Name: "{group}\Uninstall NeuralSynth"; Filename: "{app}\unins000.exe" + +;[Dirs] +;Name: {cf}\Digidesign\DAE\Plugins\ + +[Code] +var + OkToCopyLog : Boolean; + VST3DirPage_32: TInputDirWizardPage; + VST3DirPage_64: TInputDirWizardPage; + +procedure InitializeWizard; +begin + if IsWin64 then begin + VST3DirPage_64 := CreateInputDirPage(wpSelectDir, + 'Confirm 64-Bit VST3 Plugin Directory', '', + 'Select the folder in which setup should install the 64-bit VST3 Plugin, then click Next.', + False, ''); + VST3DirPage_64.Add(''); + VST3DirPage_64.Values[0] := ExpandConstant('{reg:HKLM\SOFTWARE\VST,VSTPluginsPath|{pf}\Common Files\VST3}\'); + end; +end; + +function GetVST3Dir_64(Param: String): String; +begin + Result := VST3DirPage_64.Values[0] +end; + +procedure CurStepChanged(CurStep: TSetupStep); +begin + if CurStep = ssDone then + OkToCopyLog := True; +end; + +procedure DeinitializeSetup(); +begin + if OkToCopyLog then + FileCopy (ExpandConstant ('{log}'), ExpandConstant ('{app}\InstallationLogFile.log'), FALSE); + RestartReplace (ExpandConstant ('{log}'), ''); +end; + +[UninstallDelete] +Type: files; Name: "{app}\InstallationLogFile.log" \ No newline at end of file diff --git a/NeuralSynth.jucer b/NeuralSynth.jucer new file mode 100644 index 0000000..3c21fa2 --- /dev/null +++ b/NeuralSynth.jucer @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/AudioBufferQueue.h b/Source/AudioBufferQueue.h new file mode 100644 index 0000000..30bb6f7 --- /dev/null +++ b/Source/AudioBufferQueue.h @@ -0,0 +1,49 @@ +#pragma once + +//============================================================================== +template +class AudioBufferQueue +{ +public: + //============================================================================== + static constexpr size_t order = 9; + static constexpr size_t bufferSize = 1U << order; + static constexpr size_t numBuffers = 5; + + //============================================================================== + void push(const SampleType* dataToPush, size_t numSamples) + { + jassert(numSamples <= bufferSize); + + int start1, size1, start2, size2; + abstractFifo.prepareToWrite(1, start1, size1, start2, size2); + + jassert(size1 <= 1); + jassert(size2 == 0); + + if (size1 > 0) + juce::FloatVectorOperations::copy(buffers[(size_t)start1].data(), dataToPush, (int)juce::jmin(bufferSize, numSamples)); + + abstractFifo.finishedWrite(size1); + } + + //============================================================================== + void pop(SampleType* outputBuffer) + { + int start1, size1, start2, size2; + abstractFifo.prepareToRead(1, start1, size1, start2, size2); + + jassert(size1 <= 1); + jassert(size2 == 0); + + if (size1 > 0) + juce::FloatVectorOperations::copy(outputBuffer, buffers[(size_t)start1].data(), (int)bufferSize); + + abstractFifo.finishedRead(size1); + } + +private: + //============================================================================== + juce::AbstractFifo abstractFifo{ numBuffers }; + std::array, numBuffers> buffers; +}; \ No newline at end of file diff --git a/Source/AudioEngine.h b/Source/AudioEngine.h new file mode 100644 index 0000000..ce59eb6 --- /dev/null +++ b/Source/AudioEngine.h @@ -0,0 +1,43 @@ +#pragma once + +#include "SynthVoice.h" +#include + +class NeuralAudioEngine : public juce::MPESynthesiser +{ +public: + static constexpr auto maxNumVoices = 4; + + //============================================================================== + NeuralAudioEngine(NeuralSharedParams &sp) + { + for (auto i = 0; i < maxNumVoices; ++i) + addVoice(new NeuralSynthVoice(sp)); + + setVoiceStealingEnabled(true); + } + + //============================================================================== + void prepare(const juce::dsp::ProcessSpec& spec) noexcept + { + setCurrentPlaybackSampleRate(spec.sampleRate); + + for (auto* v : voices) + dynamic_cast (v)->prepare(spec); + } + + //============================================================================== + template + void applyToVoices(VoiceFunc&& fn) noexcept + { + for (auto* v : voices) + fn(dynamic_cast (v)); + } + +private: + //============================================================================== + void renderNextSubBlock(juce::AudioBuffer& outputAudio, int startSample, int numSamples) override + { + MPESynthesiser::renderNextSubBlock(outputAudio, startSample, numSamples); + } +}; \ No newline at end of file diff --git a/Source/NeuralSharedParams.h b/Source/NeuralSharedParams.h new file mode 100644 index 0000000..709d70e --- /dev/null +++ b/Source/NeuralSharedParams.h @@ -0,0 +1,23 @@ +/* + ============================================================================== + + NeuralSharedParams.h + Created: 21 Jun 2025 7:53:02am + Author: timot + + ============================================================================== +*/ + +#pragma once + +#include + +struct NeuralSharedParams +{ + std::atomic waveform{ -1 }; + + std::atomic* attack; + std::atomic* decay; + std::atomic* sustain; + std::atomic* release; +}; \ No newline at end of file diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp new file mode 100644 index 0000000..fa44511 --- /dev/null +++ b/Source/PluginEditor.cpp @@ -0,0 +1,101 @@ +/* + ============================================================================== + + This file contains the basic framework code for a JUCE plugin editor. + + ============================================================================== +*/ + +#include "PluginProcessor.h" +#include "PluginEditor.h" +#include "ScopeComponent.h" + +//============================================================================== +NeuralSynthAudioProcessorEditor::NeuralSynthAudioProcessorEditor (NeuralSynthAudioProcessor& p) + : AudioProcessorEditor (&p), audioProcessor (p), scopeComponent(audioProcessor.getAudioBufferQueue()) +{ + // Make sure that before the constructor has finished, you've set the + // editor's size to whatever you need it to be. + setSize(400, 500); + + auto& tree = audioProcessor.parameters; + + auto area = getLocalBounds(); + scopeComponent.setTopLeftPosition(0, 0); + scopeComponent.setSize(400, 200); + + addAndMakeVisible(scopeComponent); + + attackAttachment = std::make_unique(tree, "attack", attackSlider); + decayAttachment = std::make_unique(tree, "decay", decaySlider); + sustainAttachment = std::make_unique(tree, "sustain", sustainSlider); + releaseAttachment = std::make_unique(tree, "release", releaseSlider); + + addAndMakeVisible(waveformSelector); + + waveformSelector.setTopLeftPosition(15, 225); + + int leftPosition = 15; + const int sliderWidth = 60; + for (auto* slider : { &attackSlider, &decaySlider, &sustainSlider, &releaseSlider }) + { + slider->setSliderStyle(juce::Slider::Rotary); + slider->setTextBoxStyle(juce::Slider::TextBoxBelow, false, sliderWidth, 20); + addAndMakeVisible(*slider); + slider->setTopLeftPosition(leftPosition, 250); + leftPosition += (sliderWidth + 40); + } + + waveformSelector.addItem("Sine", 1); + waveformSelector.addItem("Saw", 2); + waveformSelector.addItem("Square", 3); + waveformSelector.addItem("Triangle", 4); + + + // Attach to parameter + waveformAttachment = std::make_unique( + audioProcessor.parameters, "waveform", waveformSelector); + + addAndMakeVisible(midiKeyboardComponent); + + + //scopeComponent.setSize(area.getWidth(), area.getHeight()); + + midiKeyboardComponent.setMidiChannel(2); + midiKeyboardState.addListener(&audioProcessor.getMidiMessageCollector()); + + midiKeyboardComponent.setBounds(area.removeFromTop(80).reduced(8)); + midiKeyboardComponent.setTopLeftPosition(8, 420); +} + +NeuralSynthAudioProcessorEditor::~NeuralSynthAudioProcessorEditor() +{ +} + +//============================================================================== +void NeuralSynthAudioProcessorEditor::paint (juce::Graphics& g) +{ + // (Our component is opaque, so we must completely fill the background with a solid colour) + g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId)); + + //g.setColour (juce::Colours::white); + //g.setFont (juce::FontOptions (15.0f)); + //g.drawFittedText ("Hello World!", getLocalBounds(), juce::Justification::centred, 1); +} + +void NeuralSynthAudioProcessorEditor::resized() +{ + // This is generally where you'll want to lay out the positions of any + // subcomponents in your editor.. + auto bounds = getLocalBounds().reduced(20); + auto row = bounds.removeFromTop(150); + + int knobWidth = row.getWidth() / 4; + + attackSlider.setBounds(row.removeFromLeft(knobWidth).reduced(10)); + decaySlider.setBounds(row.removeFromLeft(knobWidth).reduced(10)); + sustainSlider.setBounds(row.removeFromLeft(knobWidth).reduced(10)); + releaseSlider.setBounds(row.removeFromLeft(knobWidth).reduced(10)); + + waveformSelector.setBounds(20, 20, 120, 30); +} diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h new file mode 100644 index 0000000..b0a1353 --- /dev/null +++ b/Source/PluginEditor.h @@ -0,0 +1,48 @@ +/* + ============================================================================== + + This file contains the basic framework code for a JUCE plugin editor. + + ============================================================================== +*/ + +#pragma once + +#include +#include "PluginProcessor.h" +#include "ScopeComponent.h" + +//============================================================================== +/** +*/ +class NeuralSynthAudioProcessorEditor : public juce::AudioProcessorEditor +{ +public: + NeuralSynthAudioProcessorEditor (NeuralSynthAudioProcessor&); + ~NeuralSynthAudioProcessorEditor() override; + + //============================================================================== + void paint (juce::Graphics&) override; + void resized() override; + +private: + // This reference is provided as a quick way for your editor to + // access the processor object that created it. + NeuralSynthAudioProcessor& audioProcessor; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NeuralSynthAudioProcessorEditor) + + juce::ComboBox waveformSelector; + std::unique_ptr waveformAttachment; + + juce::Slider attackSlider, decaySlider, sustainSlider, releaseSlider; + + std::unique_ptr attackAttachment; + std::unique_ptr decayAttachment; + std::unique_ptr sustainAttachment; + std::unique_ptr releaseAttachment; + + juce::MidiKeyboardState midiKeyboardState; + juce::MidiKeyboardComponent midiKeyboardComponent{ midiKeyboardState, juce::MidiKeyboardComponent::horizontalKeyboard }; + ScopeComponent scopeComponent; +}; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp new file mode 100644 index 0000000..b0d4558 --- /dev/null +++ b/Source/PluginProcessor.cpp @@ -0,0 +1,201 @@ +/* + ============================================================================== + + 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); + + parameters.addParameterListener("attack", this); + parameters.addParameterListener("decay", this); + parameters.addParameterListener("sustain", this); + parameters.addParameterListener("release", this); + + sp.attack = parameters.getRawParameterValue("attack"); + sp.decay = parameters.getRawParameterValue("decay"); + sp.sustain = parameters.getRawParameterValue("sustain"); + sp.release = parameters.getRawParameterValue("release"); +} + +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(); +} + +juce::AudioProcessorValueTreeState::ParameterLayout NeuralSynthAudioProcessor::createParameterLayout() +{ + std::vector> params; + + params.push_back(std::make_unique( + "waveform", "Waveform", + juce::StringArray{ "Sine", "Saw", "Square", "Triangle" }, 0)); + + // Start/end/interval + params.push_back(std::make_unique("attack", "Attack", + juce::NormalisableRange(0.0f, 1.0f, 0.01f), 0.1f)); + params.push_back(std::make_unique("decay", "Decay", + juce::NormalisableRange(0.0f, 1.0f, 0.01f), 0.5f)); + params.push_back(std::make_unique("sustain", "Sustain", + juce::NormalisableRange(0.0f, 1.0f, 0.01f), 0.8f)); + params.push_back(std::make_unique("release", "Release", + juce::NormalisableRange(0.01f, 1.0f, 0.01f), 1.0f)); + + return { params.begin(), params.end() }; +} \ No newline at end of file diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h new file mode 100644 index 0000000..af14600 --- /dev/null +++ b/Source/PluginProcessor.h @@ -0,0 +1,80 @@ +/* + ============================================================================== + + This file contains the basic framework code for a JUCE plugin processor. + + ============================================================================== +*/ + +#pragma once + +#include +#include "AudioBufferQueue.h" +#include "AudioEngine.h" +#include "ScopeDataCollector.h" +#include "NeuralSharedParams.h" + +//============================================================================== +/** +*/ +class NeuralSynthAudioProcessor : public juce::AudioProcessor, + private juce::AudioProcessorValueTreeState::Listener +{ +public: + //============================================================================== + NeuralSynthAudioProcessor(); + ~NeuralSynthAudioProcessor() override; + + //============================================================================== + void prepareToPlay(double sampleRate, int samplesPerBlock) override; + void releaseResources() override; + +#ifndef JucePlugin_PreferredChannelConfigurations + bool isBusesLayoutSupported(const BusesLayout& layouts) const override; +#endif + + void processBlock(juce::AudioBuffer&, juce::MidiBuffer&) override; + + //============================================================================== + juce::AudioProcessorEditor* createEditor() override; + bool hasEditor() const override; + + //============================================================================== + const juce::String getName() const override; + + bool acceptsMidi() const override; + bool producesMidi() const override; + bool isMidiEffect() const override; + double getTailLengthSeconds() const override; + + //============================================================================== + int getNumPrograms() override; + int getCurrentProgram() override; + void setCurrentProgram(int index) override; + const juce::String getProgramName(int index) override; + void changeProgramName(int index, const juce::String& newName) override; + + //============================================================================== + void getStateInformation(juce::MemoryBlock& destData) override; + void setStateInformation(const void* data, int sizeInBytes) override; + + //============================================================================== + void parameterChanged(const juce::String& id, float newValue) override; + + juce::MidiMessageCollector& getMidiMessageCollector() noexcept { return midiMessageCollector; } + + juce::MidiMessageCollector midiMessageCollector; + juce::AudioProcessorValueTreeState parameters; + juce::AudioProcessorValueTreeState::ParameterLayout createParameterLayout(); + + AudioBufferQueue& getAudioBufferQueue() noexcept { return audioBufferQueue; } +private: + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NeuralSynthAudioProcessor) + + NeuralAudioEngine audioEngine; + AudioBufferQueue audioBufferQueue; + ScopeDataCollector scopeDataCollector{ audioBufferQueue }; + + NeuralSharedParams sp; +}; diff --git a/Source/ScopeComponent.h b/Source/ScopeComponent.h new file mode 100644 index 0000000..5d4ec4d --- /dev/null +++ b/Source/ScopeComponent.h @@ -0,0 +1,102 @@ +#pragma once + +#include "AudioBufferQueue.h" + +//============================================================================== +template +class ScopeComponent : public juce::Component, + private juce::Timer +{ +public: + using Queue = AudioBufferQueue; + + //============================================================================== + ScopeComponent(Queue& queueToUse) + : audioBufferQueue(queueToUse) + { + sampleData.fill(SampleType(0)); + setFramesPerSecond(30); + } + + //============================================================================== + void setFramesPerSecond(int framesPerSecond) + { + jassert(framesPerSecond > 0 && framesPerSecond < 1000); + startTimerHz(framesPerSecond); + } + + //============================================================================== + void paint(juce::Graphics& g) override + { + g.fillAll(juce::Colours::black); + g.setColour(juce::Colours::white); + + auto area = getLocalBounds(); + auto h = (SampleType)area.getHeight(); + auto w = (SampleType)area.getWidth(); + + // Oscilloscope + auto scopeRect = juce::Rectangle{ SampleType(0), SampleType(0), w, h / 2 }; + plot(sampleData.data(), sampleData.size(), g, scopeRect, SampleType(1), h / 4); + + // Spectrum + auto spectrumRect = juce::Rectangle{ SampleType(0), h / 2, w, h / 2 }; + plot(spectrumData.data(), spectrumData.size() / 4, g, spectrumRect); + } + + //============================================================================== + void resized() override {} + +private: + //============================================================================== + Queue& audioBufferQueue; + std::array sampleData; + + juce::dsp::FFT fft{ Queue::order }; + using WindowFun = juce::dsp::WindowingFunction; + WindowFun windowFun{ (size_t)fft.getSize(), WindowFun::hann }; + std::array spectrumData; + + //============================================================================== + void timerCallback() override + { + audioBufferQueue.pop(sampleData.data()); + juce::FloatVectorOperations::copy(spectrumData.data(), sampleData.data(), (int)sampleData.size()); + + auto fftSize = (size_t)fft.getSize(); + + jassert(spectrumData.size() == 2 * fftSize); + windowFun.multiplyWithWindowingTable(spectrumData.data(), fftSize); + fft.performFrequencyOnlyForwardTransform(spectrumData.data()); + + static constexpr auto mindB = SampleType(-160); + static constexpr auto maxdB = SampleType(0); + + for (auto& s : spectrumData) + s = juce::jmap(juce::jlimit(mindB, maxdB, juce::Decibels::gainToDecibels(s) - juce::Decibels::gainToDecibels(SampleType(fftSize))), mindB, maxdB, SampleType(0), SampleType(1)); + + repaint(); + } + + //============================================================================== + static void plot(const SampleType* data, + size_t numSamples, + juce::Graphics& g, + juce::Rectangle rect, + SampleType scaler = SampleType(1), + SampleType offset = SampleType(0)) + { + auto w = rect.getWidth(); + auto h = rect.getHeight(); + auto right = rect.getRight(); + + auto center = rect.getBottom() - offset; + auto gain = h * scaler; + + for (size_t i = 1; i < numSamples; ++i) + g.drawLine({ juce::jmap(SampleType(i - 1), SampleType(0), SampleType(numSamples - 1), SampleType(right - w), SampleType(right)), + center - gain * data[i - 1], + juce::jmap(SampleType(i), SampleType(0), SampleType(numSamples - 1), SampleType(right - w), SampleType(right)), + center - gain * data[i] }); + } +}; \ No newline at end of file diff --git a/Source/ScopeDataCollector.h b/Source/ScopeDataCollector.h new file mode 100644 index 0000000..e5cd7c8 --- /dev/null +++ b/Source/ScopeDataCollector.h @@ -0,0 +1,62 @@ +#pragma once + +template +class ScopeDataCollector +{ +public: + //============================================================================== + ScopeDataCollector(AudioBufferQueue& queueToUse) + : audioBufferQueue(queueToUse) + { + } + + //============================================================================== + void process(const SampleType* data, size_t numSamples) + { + size_t index = 0; + + if (state == State::waitingForTrigger) + { + while (index++ < numSamples) + { + auto currentSample = *data++; + + if (currentSample >= triggerLevel && prevSample < triggerLevel) + { + numCollected = 0; + state = State::collecting; + break; + } + + prevSample = currentSample; + } + } + + if (state == State::collecting) + { + while (index++ < numSamples) + { + buffer[numCollected++] = *data++; + + if (numCollected == buffer.size()) + { + audioBufferQueue.push(buffer.data(), buffer.size()); + state = State::waitingForTrigger; + prevSample = SampleType(100); + break; + } + } + } + } + +private: + //============================================================================== + AudioBufferQueue& audioBufferQueue; + std::array::bufferSize> buffer; + size_t numCollected; + SampleType prevSample = SampleType(100); + + static constexpr auto triggerLevel = SampleType(0.05); + + enum class State { waitingForTrigger, collecting } state{ State::waitingForTrigger }; +}; \ No newline at end of file diff --git a/Source/SynthVoice.cpp b/Source/SynthVoice.cpp new file mode 100644 index 0000000..bc7be6b --- /dev/null +++ b/Source/SynthVoice.cpp @@ -0,0 +1,107 @@ +#include "SynthVoice.h" + +//============================================================================== +NeuralSynthVoice::NeuralSynthVoice(NeuralSharedParams& sp) : shared(sp) {} + +//============================================================================== +void NeuralSynthVoice::prepare(const juce::dsp::ProcessSpec& spec) +{ + setWaveform(0); + tempBlock = juce::dsp::AudioBlock(heapBlock, spec.numChannels, spec.maximumBlockSize); + processorChain.prepare(spec); + adsr.setSampleRate(spec.sampleRate); +} + +//============================================================================== +void NeuralSynthVoice::noteStarted() +{ + auto velocity = getCurrentlyPlayingNote().noteOnVelocity.asUnsignedFloat(); + auto freqHz = (float)getCurrentlyPlayingNote().getFrequencyInHertz(); + + processorChain.get().setFrequency(freqHz, true); + + juce::ADSR::Parameters p; + p.attack = shared.attack->load(); + p.decay = shared.decay->load(); + p.sustain = shared.sustain->load(); + p.release = shared.release->load(); + + adsr.setParameters(p); + adsr.noteOn(); +} + +//============================================================================== +void NeuralSynthVoice::notePitchbendChanged() +{ + auto freqHz = (float)getCurrentlyPlayingNote().getFrequencyInHertz(); + processorChain.get().setFrequency(freqHz, true); +} + +//============================================================================== +void NeuralSynthVoice::noteStopped(bool allowTailOff) +{ + adsr.noteOff(); //Triggers release phase +} + +//============================================================================== +void NeuralSynthVoice::notePressureChanged() {} +void NeuralSynthVoice::noteTimbreChanged() {} +void NeuralSynthVoice::noteKeyStateChanged() {} + +//============================================================================== +void NeuralSynthVoice::renderNextBlock(juce::AudioBuffer& outputBuffer, int startSample, int numSamples) +{ + if (!adsr.isActive()) + clearCurrentNote(); + + if (waveform != -1) { + setWaveform(waveform); + waveform = -1; + } + + auto block = tempBlock.getSubBlock(0, (size_t)numSamples); + block.clear(); + juce::dsp::ProcessContextReplacing context(block); + processorChain.process(context); + + // 3. Apply ADSR envelope to tempBlock + std::vector channelPtrs; + for (size_t ch = 0; ch < tempBlock.getNumChannels(); ++ch) + channelPtrs.push_back(tempBlock.getChannelPointer(ch)); + + juce::AudioBuffer buffer(channelPtrs.data(), + static_cast(tempBlock.getNumChannels()), + static_cast(tempBlock.getNumSamples())); + + adsr.applyEnvelopeToBuffer(buffer, 0, numSamples); + + juce::dsp::AudioBlock(outputBuffer) + .getSubBlock((size_t)startSample, (size_t)numSamples) + .add(tempBlock); +} + +void NeuralSynthVoice::setWaveform(int waveformType) +{ + auto& osc = processorChain.template get(); + + switch (waveformType) + { + case 0: + osc.initialise([](float x) { return std::sin(x); }); + break; + + case 1: + osc.initialise([](float x) { return x / juce::MathConstants::pi; }); // Saw + break; + + case 2: + osc.initialise([](float x) { return x < 0.0f ? -1.0f : 1.0f; }); // Square + break; + + case 3: + osc.initialise([](float x) { + return 2.0f * std::abs(2.0f * (x / juce::MathConstants::twoPi) - 1.0f) - 1.0f; + }); // Triangle + break; + } +} \ No newline at end of file diff --git a/Source/SynthVoice.h b/Source/SynthVoice.h new file mode 100644 index 0000000..fa8f2fb --- /dev/null +++ b/Source/SynthVoice.h @@ -0,0 +1,100 @@ +#pragma once + +#include +#include "NeuralSharedParams.h" + +#include + +/*struct ADSRProcessor : public juce::dsp::ProcessorBase +{ + // ----------------------------------------------------------------- + void prepare(const juce::dsp::ProcessSpec& spec) override + { + adsr.setSampleRate(spec.sampleRate); + } + + void reset() override { adsr.reset(); } + + void process(const juce::dsp::ProcessContextReplacing &ctx) override + { + DBG("Processing..."); + + auto& outputBlock = context.getOutputBlock(); + const auto numSamples = (int)outputBlock.getNumSamples(); + const auto numChannels = (int)outputBlock.getNumChannels(); + + // Wrap the outputBlock into AudioBuffer + for (int ch = 0; ch < numChannels; ++ch) + buffer.setWritePointer(ch, outputBlock.getChannelPointer(ch)); + + adsr.applyEnvelopeToBuffer(buffer, 0, numSamples); + } + + // ----------------------------------------------------------------- + // These two are NOT part of the ProcessorBase interface – they are + // your private hooks that the voice will call on note events. + void noteOn(const juce::ADSR::Parameters& p) { + adsr.setParameters(p); adsr.noteOn(); + } + void noteOff() { adsr.noteOff(); } + +private: + juce::ADSR adsr; + juce::AudioBuffer buffer; +};*/ + +//============================================================================== +class NeuralSynthVoice : public juce::MPESynthesiserVoice +{ +public: + NeuralSynthVoice(NeuralSharedParams& sp); + + //============================================================================== + void prepare(const juce::dsp::ProcessSpec& spec); + + //============================================================================== + void noteStarted() override; + + //============================================================================== + void notePitchbendChanged() override; + + //============================================================================== + void noteStopped(bool) override; + + //============================================================================== + void notePressureChanged(); + void noteTimbreChanged(); + void noteKeyStateChanged(); + + //============================================================================== + void renderNextBlock(juce::AudioBuffer& outputBuffer, int startSample, int numSamples); + + void setWaveform(int waveformType); + + void changeWaveform(int waveform) noexcept { + this->waveform = waveform; + } + +private: + //============================================================================== + juce::HeapBlock heapBlock; + juce::dsp::AudioBlock tempBlock; + + enum + { + synthIndex + }; + + juce::dsp::ProcessorChain< + juce::dsp::Oscillator + > processorChain; + + juce::ADSR adsr; + NeuralSharedParams& shared; + + static constexpr size_t lfoUpdateRate = 100; + + static inline float msToSecs(float ms) { return ms * 0.001f; } + + std::atomic waveform { -1 }; +}; \ No newline at end of file