├── Source ├── LoudnessMeterComponent.cpp ├── Plasma.cpp ├── PlasmaLabel.h ├── CustomTextButton.h ├── LoudnessMeterComponent.h ├── WaveformComponent.h ├── PlasmaLabel.cpp ├── CustomLookAndFeel.h ├── ResponseCurveComponent.h ├── ShapercurveComponent.h ├── CustomLabel.h ├── CustomTextButton.cpp ├── WaveformComponent.cpp ├── CustomRotarySlider.h ├── CustomLabel.cpp ├── ShapercurveComponent.cpp ├── BaseVisualiser.h ├── PlasmaDistortionProcessor.h ├── Version.h ├── ValueEditor.h ├── BaseVisualiser.cpp ├── CustomRotarySlider.cpp ├── ResponseCurveComponent.cpp ├── PluginProcessor.h ├── PluginEditor.h ├── CustomLookAndFeel.cpp └── PluginProcessor.cpp ├── Preview.png ├── .github └── FUNDING.yml ├── CompressedPreview.webp ├── Resources ├── uninstall.ico ├── Poppins │ ├── Poppins-Black.ttf │ ├── Poppins-Bold.ttf │ ├── Poppins-Light.ttf │ ├── Poppins-Thin.ttf │ ├── Poppins-Italic.ttf │ ├── Poppins-Medium.ttf │ ├── Poppins-Regular.ttf │ ├── Poppins-SemiBold.ttf │ ├── Poppins-BoldItalic.ttf │ ├── Poppins-ExtraBold.ttf │ ├── Poppins-ExtraLight.ttf │ ├── Poppins-ThinItalic.ttf │ ├── Poppins-BlackItalic.ttf │ ├── Poppins-LightItalic.ttf │ ├── Poppins-MediumItalic.ttf │ ├── Poppins-ExtraBoldItalic.ttf │ ├── Poppins-SemiBoldItalic.ttf │ ├── Poppins-ExtraLightItalic.ttf │ └── OFL.txt └── Sedgwick_Ave_Display │ ├── SedgwickAveDisplay-Regular.ttf │ └── OFL.txt ├── Installer ├── readme.md └── Windows │ └── Plasma.iss ├── JuceLibraryCode ├── JuceLV2Defines.h ├── include_juce_dsp.mm ├── include_juce_core.cpp ├── include_juce_core.mm ├── include_juce_dsp.cpp ├── include_juce_events.cpp ├── include_juce_events.mm ├── include_juce_opengl.cpp ├── include_juce_opengl.mm ├── include_juce_graphics.mm ├── include_juce_graphics.cpp ├── include_juce_gui_basics.mm ├── include_juce_gui_extra.cpp ├── include_juce_gui_extra.mm ├── include_juce_audio_utils.cpp ├── include_juce_audio_utils.mm ├── include_juce_gui_basics.cpp ├── include_juce_audio_basics.cpp ├── include_juce_audio_basics.mm ├── include_juce_audio_devices.mm ├── include_juce_audio_formats.mm ├── include_juce_audio_devices.cpp ├── include_juce_audio_formats.cpp ├── include_juce_data_structures.mm ├── include_juce_graphics_Harfbuzz.cpp ├── include_juce_graphics_Sheenbidi.c ├── include_juce_audio_processors.cpp ├── include_juce_audio_processors.mm ├── include_juce_core_CompilationTime.cpp ├── include_juce_data_structures.cpp ├── include_juce_audio_processors_ara.cpp ├── include_juce_audio_plugin_client_AAX.mm ├── include_juce_audio_plugin_client_LV2.mm ├── include_juce_audio_plugin_client_AAX.cpp ├── include_juce_audio_plugin_client_ARA.cpp ├── include_juce_audio_plugin_client_AU_1.mm ├── include_juce_audio_plugin_client_AU_2.mm ├── include_juce_audio_plugin_client_AUv3.mm ├── include_juce_audio_plugin_client_LV2.cpp ├── include_juce_audio_plugin_client_VST2.cpp ├── include_juce_audio_plugin_client_VST2.mm ├── include_juce_audio_plugin_client_VST3.cpp ├── include_juce_audio_plugin_client_VST3.mm ├── include_juce_audio_processors_lv2_libs.cpp ├── include_juce_audio_plugin_client_Unity.cpp ├── include_juce_audio_plugin_client_AAX_utils.cpp ├── include_juce_audio_plugin_client_Standalone.cpp ├── ReadMe.txt ├── BinaryData.h ├── JuceHeader.h └── JucePluginDefines.h ├── Scripts ├── install_linux.sh ├── build_linux.sh └── uninstall_linux.sh ├── .SRCINFO ├── PKGBUILD ├── .vscode └── settings.json ├── CODE_OF_CONDUCT.md ├── README.md ├── .gitignore └── Plasma.jucer /Source/LoudnessMeterComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "LoudnessMeterComponent.h" 2 | -------------------------------------------------------------------------------- /Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Preview.png -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: Dimethoxy 4 | -------------------------------------------------------------------------------- /CompressedPreview.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/CompressedPreview.webp -------------------------------------------------------------------------------- /Resources/uninstall.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/uninstall.ico -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-Black.ttf -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-Bold.ttf -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-Light.ttf -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-Thin.ttf -------------------------------------------------------------------------------- /Source/Plasma.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void say_hello(){ 4 | std::cout << "Hello, from Plasma!\n"; 5 | } 6 | -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-Italic.ttf -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-Medium.ttf -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-Regular.ttf -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-SemiBold.ttf -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-BoldItalic.ttf -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-ExtraBold.ttf -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-ExtraLight.ttf -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-ThinItalic.ttf -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-BlackItalic.ttf -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-LightItalic.ttf -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-MediumItalic.ttf -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-ExtraBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-ExtraBoldItalic.ttf -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /Installer/readme.md: -------------------------------------------------------------------------------- 1 | ### THIS IS NOT WHERE YOU DOWNLOAD THE INSTALLER 2 | Go to our releases [here](https://github.com/Dimethoxy/Plasma/releases) 3 | -------------------------------------------------------------------------------- /Resources/Poppins/Poppins-ExtraLightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Poppins/Poppins-ExtraLightItalic.ttf -------------------------------------------------------------------------------- /JuceLibraryCode/JuceLV2Defines.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef JucePlugin_LV2URI 4 | #define JucePlugin_LV2URI "https://dimethoxy.com/plasma" 5 | #endif 6 | -------------------------------------------------------------------------------- /Scripts/install_linux.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | mkdir -p ~/.vst3 4 | cp -r ./Builds/LinuxMakefile/build/Plasma.vst3 ~/.vst3/Plasma.vst3 5 | echo "Installation complete" -------------------------------------------------------------------------------- /Resources/Sedgwick_Ave_Display/SedgwickAveDisplay-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimethoxy/Plasma/HEAD/Resources/Sedgwick_Ave_Display/SedgwickAveDisplay-Regular.ttf -------------------------------------------------------------------------------- /Scripts/build_linux.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Build the project by running the Make build script in the LinuxMakefile directory as Relase 4 | 5 | cd Builds/LinuxMakefile 6 | make CONFIG=Release 7 | echo "Build complete" -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_dsp.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_core.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_core.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_dsp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_events.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_events.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_opengl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_opengl.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_graphics.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_graphics.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_gui_basics.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_gui_extra.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_gui_extra.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_utils.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_gui_basics.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_basics.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_basics.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_devices.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_formats.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_devices.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_formats.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_data_structures.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_graphics_Harfbuzz.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_graphics_Sheenbidi.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_processors.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_processors.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_core_CompilationTime.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_data_structures.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /Source/PlasmaLabel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class PlasmaLabel : public juce::Label 5 | { 6 | public: 7 | PlasmaLabel(); 8 | void setCustomFontSize(int size); 9 | private: 10 | Font getCustomFont(); 11 | Typeface::Ptr getTypeFace(); 12 | }; 13 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_processors_ara.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_plugin_client_AAX.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_plugin_client_LV2.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_plugin_client_AAX.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_plugin_client_ARA.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_plugin_client_AU_1.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_plugin_client_AU_2.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_plugin_client_AUv3.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_plugin_client_LV2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_plugin_client_VST2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_plugin_client_VST2.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_plugin_client_VST3.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_plugin_client_VST3.mm: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_processors_lv2_libs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_plugin_client_Unity.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_plugin_client_AAX_utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /JuceLibraryCode/include_juce_audio_plugin_client_Standalone.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /Scripts/uninstall_linux.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Define the path to the VST3 plugin 4 | VST3_PATH="$HOME/.vst3/Plasma.vst3" 5 | 6 | # Check if the VST3 plugin exists 7 | if [ -d "$VST3_PATH" ]; then 8 | # Remove the plugin 9 | rm -rf "$VST3_PATH" 10 | echo "Uninstallation complete" 11 | else 12 | echo "Plasma.vst3 not found, nothing to uninstall" 13 | fi 14 | -------------------------------------------------------------------------------- /.SRCINFO: -------------------------------------------------------------------------------- 1 | pkgbase = dimethoxy-plasma-bin 2 | pkgdesc = Asymmetrical Distortion Effect for VST3 and LV2 compatible hosts 3 | pkgver = 1.2.1 4 | pkgrel = 1 5 | url = https://github.com/Dimethoxy/Plasma 6 | arch = x86_64 7 | license = GPL3 8 | provides = dimethoxy-plasma 9 | source = https://github.com/Dimethoxy/Plasma/releases/download/v1.2.1/plasma-v1.2.1-linux.tar.gz 10 | sha256sums = f61cfd287b0d58b9eca419c6c785e66a8bf94caf26b33615aa465c25bd8ee4e1 11 | 12 | pkgname = dimethoxy-plasma-bin 13 | -------------------------------------------------------------------------------- /Source/CustomTextButton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "CustomLookAndFeel.h" 5 | 6 | class CustomTextButton : public TextButton 7 | { 8 | public: 9 | CustomTextButton(); 10 | ~CustomTextButton(); 11 | void paintButton(Graphics& g, 12 | bool shouldDrawButtonAsHighlighted, 13 | bool shouldDrawButtonAsDown) override; 14 | //void paint(Graphics& g) override; 15 | private: 16 | 17 | Typeface::Ptr getCustomTypeface(); 18 | Font getCustomFont(); 19 | CustomLookAndFeel lnf; 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /Installer/Windows/Plasma.iss: -------------------------------------------------------------------------------- 1 | [Setup] 2 | AppName=Plasma 3 | AppVersion=1.2.1 4 | DefaultDirName={commoncf64}\VST3\Dimethoxy 5 | DefaultGroupName=Plasma 6 | OutputBaseFilename=plasma-1.2.1-windows 7 | DirExistsWarning=no 8 | UninstallFilesDir={app}\Plasma 9 | UninstallDisplayIcon={app}\Plasma\uninstall.ico 10 | 11 | [Files] 12 | Source: "..\..\Builds\VisualStudio2022\x64\Release\VST3\Plasma.vst3"; DestDir: "{app}\Plasma"; Flags: recursesubdirs 13 | Source: "..\..\Resources\uninstall.ico"; DestDir: "{app}\Plasma"; 14 | 15 | 16 | -------------------------------------------------------------------------------- /Source/LoudnessMeterComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace Gui { 6 | class LoudnessMeterComponent : public Component 7 | { 8 | public: 9 | void paint(Graphics& g) override 10 | { 11 | auto bounds = getLocalBounds().toFloat(); 12 | g.setColour(Colours::red); 13 | g.fillAll(); 14 | g.setColour(Colours::green); 15 | g.fillRect( 16 | bounds.withTrimmedTop(bounds.getHeight() * (1.0f - level / -60.0f))); 17 | } 18 | void setLevel(const float value) { level = value; }; 19 | 20 | private: 21 | float level = -60.0f; 22 | }; 23 | } -------------------------------------------------------------------------------- /JuceLibraryCode/ReadMe.txt: -------------------------------------------------------------------------------- 1 | 2 | Important Note!! 3 | ================ 4 | 5 | The purpose of this folder is to contain files that are auto-generated by the Projucer, 6 | and ALL files in this folder will be mercilessly DELETED and completely re-written whenever 7 | the Projucer saves your project. 8 | 9 | Therefore, it's a bad idea to make any manual changes to the files in here, or to 10 | put any of your own files in here if you don't want to lose them. (Of course you may choose 11 | to add the folder's contents to your version-control system so that you can re-merge your own 12 | modifications after the Projucer has saved its changes). 13 | -------------------------------------------------------------------------------- /Source/WaveformComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "BaseVisualiser.h" 4 | #include 5 | 6 | class WaveformComponent : public BaseVisualiser 7 | { 8 | public: 9 | WaveformComponent() 10 | : BaseVisualiser(2) 11 | { 12 | // 1024/4 13 | setBufferSize(1024); 14 | setSamplesPerBlock(4); 15 | } 16 | void paintChannel(Graphics&, 17 | Rectangle bounds, 18 | const Range* levels, 19 | int numLevels, 20 | int nextSample) override; 21 | void setColor(Colour c); 22 | void setBackgroundColor(Colour c, Colour f); 23 | 24 | private: 25 | Colour color = Colour(255, 255, 255); 26 | }; -------------------------------------------------------------------------------- /Source/PlasmaLabel.cpp: -------------------------------------------------------------------------------- 1 | #include "PlasmaLabel.h" 2 | 3 | PlasmaLabel::PlasmaLabel() 4 | { 5 | setText("PLASMA", juce::dontSendNotification); 6 | setFont(getFont().withHeight(100)); 7 | setJustificationType(Justification::centredTop); 8 | } 9 | void PlasmaLabel::setCustomFontSize(int size) 10 | { 11 | setFont(getCustomFont().withHeight(size)); 12 | } 13 | Typeface::Ptr PlasmaLabel::getTypeFace() 14 | { 15 | Typeface::Ptr tface = Typeface::createSystemTypefaceFor( 16 | BinaryData::SedgwickAveDisplayRegular_ttf, 17 | BinaryData::SedgwickAveDisplayRegular_ttfSize); 18 | return tface; 19 | } 20 | Font PlasmaLabel::getCustomFont() 21 | { 22 | Font font(getTypeFace()); 23 | return font; 24 | } 25 | -------------------------------------------------------------------------------- /Source/CustomLookAndFeel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "PluginProcessor.h" 5 | 6 | class CustomLookAndFeel : public LookAndFeel_V4 7 | { 8 | void drawRotarySlider( 9 | Graphics& g, 10 | int x, int y, int width, int height, 11 | float sliderPosProportional, float rotaryStartAngle, 12 | float rotaryEndAngle, 13 | juce::Slider&) override; 14 | 15 | void drawButtonBackground( 16 | Graphics& g, 17 | Button& button, 18 | const Colour& backgroundColour, 19 | bool isMouseOverButton, 20 | bool isButtonDown) override; 21 | 22 | void drawLabel(Graphics&, Label&) override; 23 | 24 | private: 25 | Typeface::Ptr getCustomTypeface(); 26 | Font getCustomFont(); 27 | String getAnalyserName(AnalyserType analyserType); 28 | }; -------------------------------------------------------------------------------- /Source/ResponseCurveComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "PluginProcessor.h" 5 | 6 | class ResponseCurveComponent : public Component, 7 | juce::AudioProcessorParameter::Listener, 8 | juce::Timer 9 | { 10 | public: 11 | ResponseCurveComponent(PlasmaAudioProcessor&); 12 | ~ResponseCurveComponent(); 13 | 14 | void parameterValueChanged(int parameterIndex, float newValue) override; 15 | void parameterGestureChanged(int parameterIndex, bool gestureIsStarting) override {}; 16 | void timerCallback() override; 17 | void update(); 18 | void paint(juce::Graphics& g) override; 19 | void setPadding(float newPadding); 20 | void setColor(Colour c); 21 | private: 22 | PlasmaAudioProcessor& audioProcessor; 23 | juce::Atomic parametersChanged{ false }; 24 | MonoChain monoChain; 25 | float padding = 10; 26 | Colour color = Colour(255, 255, 255); 27 | }; -------------------------------------------------------------------------------- /Source/ShapercurveComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "PluginProcessor.h" 5 | #include "PlasmaDistortionProcessor.h" 6 | 7 | class ShapercurveComponent : public Component, 8 | juce::AudioProcessorParameter::Listener, 9 | juce::Timer 10 | { 11 | public: 12 | ShapercurveComponent(PlasmaAudioProcessor&, int stage); 13 | ~ShapercurveComponent(); 14 | 15 | void parameterValueChanged(int parameterIndex, float newValue) override; 16 | void parameterGestureChanged(int parameterIndex, bool gestureIsStarting) override {}; 17 | void timerCallback() override; 18 | void paint(juce::Graphics& g) override; 19 | void setColor(Colour c); 20 | private: 21 | PlasmaAudioProcessor& audioProcessor; 22 | juce::Atomic parametersChanged{ false }; 23 | float earlyDrive = 0.0f; 24 | float lateDrive = 0.0f; 25 | Distortion earlyType = Distortion::Hardclip; 26 | Distortion lateType = Distortion::Hardclip; 27 | int stage = 0; 28 | Colour color = Colour(255, 255, 255); 29 | }; -------------------------------------------------------------------------------- /Source/CustomLabel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CustomLookAndFeel.h" 4 | #include "PluginProcessor.h" 5 | #include 6 | enum FontSizes 7 | { 8 | Main, 9 | Titel, 10 | Tooltipp 11 | }; 12 | class CustomLabel : public Label 13 | { 14 | public: 15 | CustomLabel(String text, int size, Justification justification); 16 | ~CustomLabel(); 17 | void resize(); 18 | 19 | protected: 20 | void paint(Graphics&) override; 21 | 22 | private: 23 | int mainSize = 20; 24 | int titelSize = 29; 25 | int TooltipSize = 18; 26 | int customFontSize; 27 | void setCustomFontSize(int size); 28 | Typeface::Ptr getTypeface(); 29 | Font getCustomFont(); 30 | float getCustomFontSize(); 31 | float getScaledCustomFontSize(); 32 | CustomLookAndFeel lnf; 33 | }; 34 | 35 | class CustomTextbox : public CustomLabel 36 | { 37 | public: 38 | CustomTextbox(String text, int size, Justification justification) 39 | : CustomLabel(text, size, justification) 40 | { 41 | setEditable(true); 42 | }; 43 | }; 44 | -------------------------------------------------------------------------------- /Source/CustomTextButton.cpp: -------------------------------------------------------------------------------- 1 | #include "CustomTextButton.h" 2 | 3 | CustomTextButton::CustomTextButton() 4 | { 5 | setLookAndFeel(&lnf); 6 | } 7 | 8 | CustomTextButton::~CustomTextButton() 9 | { 10 | setLookAndFeel(nullptr); 11 | } 12 | 13 | Typeface::Ptr CustomTextButton::getCustomTypeface() 14 | { 15 | Typeface::Ptr typeface = Typeface::createSystemTypefaceFor( 16 | BinaryData::PoppinsMedium_ttf, 17 | BinaryData::PoppinsMedium_ttfSize); 18 | return typeface; 19 | } 20 | 21 | Font CustomTextButton::getCustomFont() 22 | { 23 | Font font(getCustomTypeface()); 24 | return font; 25 | } 26 | 27 | void CustomTextButton::paintButton(Graphics& g, 28 | bool shouldDrawButtonAsHighlighted, 29 | bool shouldDrawButtonAsDown) 30 | { 31 | 32 | getLookAndFeel().drawButtonBackground( 33 | g, 34 | *this, 35 | Colours::aqua, 36 | shouldDrawButtonAsHighlighted, 37 | shouldDrawButtonAsDown); 38 | /* 39 | getLookAndFeel().drawButtonText( 40 | g, 41 | *this, 42 | shouldDrawButtonAsHighlighted, 43 | shouldDrawButtonAsDown); 44 | */ 45 | } 46 | -------------------------------------------------------------------------------- /PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Lunix (David Hess) 2 | pkgname='dimethoxy-plasma-bin' 3 | pkgver=1.2.1 4 | pkgrel=1 5 | pkgdesc="Asymmetrical Distortion Effect for VST3 and LV2 compatible hosts" 6 | arch=('x86_64') 7 | url="https://github.com/Dimethoxy/Plasma" 8 | license=('GPL3') 9 | provides=('dimethoxy-plasma') 10 | source=("https://github.com/Dimethoxy/Plasma/releases/download/v$pkgver/plasma-v$pkgver-linux.tar.gz") 11 | sha256sums=('f61cfd287b0d58b9eca419c6c785e66a8bf94caf26b33615aa465c25bd8ee4e1') 12 | 13 | package() { 14 | # Define new directories 15 | install -d "$pkgdir/usr/lib/vst3/Dimethoxy/Plasma" "$pkgdir/usr/lib/lv2/Dimethoxy/Plasma" 16 | install -d "$pkgdir/usr/share/licenses/$pkgname" 17 | 18 | # Install plugins (use cp -r for directories) 19 | cp -r "$srcdir/Plasma.vst3" "$pkgdir/usr/lib/vst3/Dimethoxy/Plasma/" 20 | cp -r "$srcdir/Plasma.lv2" "$pkgdir/usr/lib/lv2/Dimethoxy/Plasma/" 21 | 22 | # Download and install the LICENSE from the remote URL 23 | curl -L "https://raw.githubusercontent.com/Dimethoxy/Plasma/refs/heads/main/LICENSE" -o "$pkgdir/usr/share/licenses/$pkgname/LICENSE" 24 | } 25 | -------------------------------------------------------------------------------- /Source/WaveformComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "WaveformComponent.h" 2 | 3 | void 4 | WaveformComponent::paintChannel(Graphics& g, 5 | Rectangle area, 6 | const Range* levels, 7 | int numLevels, 8 | int nextSample) 9 | { 10 | Path p; 11 | getChannelAsPath(p, levels, numLevels, nextSample); 12 | if (isVisible()) { 13 | g.setColour(color); 14 | g.strokePath(p, 15 | PathStrokeType((getHeight() / 250.f)), 16 | AffineTransform::fromTargetPoints(0.0f, 17 | -1.0f, 18 | area.getX(), 19 | area.getY(), 20 | 0.0f, 21 | 1.0f, 22 | area.getX(), 23 | area.getBottom(), 24 | (float)numLevels, 25 | -1.0f, 26 | area.getRight(), 27 | area.getY())); 28 | } 29 | } 30 | 31 | void 32 | WaveformComponent::setColor(Colour c) 33 | { 34 | color = c; 35 | } 36 | 37 | void 38 | WaveformComponent::setBackgroundColor(Colour c, Colour f) 39 | { 40 | setColours(c, f, f); 41 | } 42 | -------------------------------------------------------------------------------- /JuceLibraryCode/BinaryData.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================================= 2 | 3 | This is an auto-generated file: Any edits you make may be overwritten! 4 | 5 | */ 6 | 7 | #pragma once 8 | 9 | namespace BinaryData 10 | { 11 | extern const char* SedgwickAveDisplayRegular_ttf; 12 | const int SedgwickAveDisplayRegular_ttfSize = 135996; 13 | 14 | extern const char* PoppinsMedium_ttf; 15 | const int PoppinsMedium_ttfSize = 156480; 16 | 17 | extern const char* PoppinsRegular_ttf; 18 | const int PoppinsRegular_ttfSize = 158192; 19 | 20 | // Number of elements in the namedResourceList and originalFileNames arrays. 21 | const int namedResourceListSize = 3; 22 | 23 | // Points to the start of a list of resource names. 24 | extern const char* namedResourceList[]; 25 | 26 | // Points to the start of a list of resource filenames. 27 | extern const char* originalFilenames[]; 28 | 29 | // If you provide the name of one of the binary resource variables above, this function will 30 | // return the corresponding data and its size (or a null pointer if the name isn't found). 31 | const char* getNamedResource (const char* resourceNameUTF8, int& dataSizeInBytes); 32 | 33 | // If you provide the name of one of the binary resource variables above, this function will 34 | // return the corresponding original, non-mangled filename (or a null pointer if the name isn't found). 35 | const char* getNamedResourceOriginalFilename (const char* resourceNameUTF8); 36 | } 37 | -------------------------------------------------------------------------------- /Source/CustomRotarySlider.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CustomLookAndFeel.h" 4 | #include 5 | 6 | class CustomRotarySlider 7 | : public Slider 8 | , public MouseListener 9 | { 10 | public: 11 | CustomRotarySlider(RangedAudioParameter& rap, 12 | const String& unitSuffix, 13 | const String& name) 14 | : Slider(Slider::SliderStyle::RotaryHorizontalVerticalDrag, 15 | Slider::TextEntryBoxPosition::NoTextBox) 16 | , param(&rap) 17 | { 18 | setTextValueSuffix(unitSuffix); 19 | setLookAndFeel(&lnf); 20 | setName(name); 21 | setColour(Slider::rotarySliderFillColourId, Colour(255, 0, 0)); 22 | setVelocityModeParameters(1.0, 1, 0.0, false, ModifierKeys::noModifiers); 23 | } 24 | 25 | // Destructor 26 | ~CustomRotarySlider() { setLookAndFeel(nullptr); } 27 | 28 | void mouseDown(const MouseEvent& e); 29 | 30 | void mouseWheelMove(const MouseEvent& e, const MouseWheelDetails& wheel) 31 | { 32 | auto newWheel = wheel; 33 | const auto speed = e.mods.isShiftDown() ? 0.1 : 1.0; 34 | newWheel.deltaY *= speed; 35 | 36 | Slider::mouseWheelMove(e, newWheel); 37 | } 38 | // lets do the mouse wheel thing for dragging the slider as well 39 | 40 | // Misc 41 | const String name = "Slider"; 42 | void paint(Graphics& g) override; 43 | Rectangle getSliderBounds() const; 44 | int getTexHeight() const { return 14; }; 45 | String getTooltipString(); 46 | bool toggle = false; 47 | 48 | private: 49 | CustomLookAndFeel lnf; 50 | RangedAudioParameter* param; 51 | String getAnalyserName(AnalyserType analyserType); 52 | }; 53 | -------------------------------------------------------------------------------- /Source/CustomLabel.cpp: -------------------------------------------------------------------------------- 1 | #include "CustomLabel.h" 2 | #include "PluginEditor.h" 3 | 4 | CustomLabel::CustomLabel(String text, int size, Justification justification) 5 | { 6 | setCustomFontSize(size); 7 | setText(text, juce::dontSendNotification); 8 | setFont(getFont().withHeight(getCustomFontSize())); 9 | setJustificationType(justification); 10 | setLookAndFeel(&lnf); 11 | } 12 | 13 | CustomLabel::~CustomLabel() 14 | { 15 | setLookAndFeel(nullptr); 16 | } 17 | 18 | void CustomLabel::resize() 19 | { 20 | setFont(getFont().withHeight(getScaledCustomFontSize())); 21 | } 22 | 23 | Typeface::Ptr CustomLabel::getTypeface() 24 | { 25 | Typeface::Ptr typeface = Typeface::createSystemTypefaceFor(BinaryData::PoppinsMedium_ttf, BinaryData::PoppinsMedium_ttfSize); 26 | return typeface; 27 | } 28 | 29 | Font CustomLabel::getCustomFont() 30 | { 31 | Font font(getTypeface()); 32 | return font; 33 | } 34 | 35 | void CustomLabel::setCustomFontSize(int size) 36 | { 37 | customFontSize = size; 38 | } 39 | 40 | float CustomLabel::getCustomFontSize() 41 | { 42 | float factor = 1.0f; 43 | switch (customFontSize) 44 | { 45 | case FontSizes::Main: 46 | { 47 | return mainSize * factor; 48 | } 49 | case FontSizes::Titel: 50 | { 51 | return titelSize * factor; 52 | } 53 | case FontSizes::Tooltipp: 54 | { 55 | return TooltipSize * factor; 56 | } 57 | default: 58 | { 59 | return mainSize * factor; 60 | } 61 | } 62 | } 63 | 64 | float CustomLabel::getScaledCustomFontSize() 65 | { 66 | float factor = getBounds().getHeight() / 40.0f; 67 | switch (customFontSize) 68 | { 69 | case FontSizes::Main: 70 | { 71 | return mainSize * factor; 72 | } 73 | case FontSizes::Titel: 74 | { 75 | return titelSize * factor; 76 | } 77 | case FontSizes::Tooltipp: 78 | { 79 | return TooltipSize * factor; 80 | } 81 | default: 82 | { 83 | return mainSize * factor; 84 | } 85 | } 86 | } 87 | 88 | void CustomLabel::paint(Graphics& g) 89 | { 90 | getLookAndFeel().drawLabel(g, *this); 91 | } 92 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "chrono": "cpp", 4 | "memory": "cpp", 5 | "format": "cpp", 6 | "future": "cpp", 7 | "istream": "cpp", 8 | "functional": "cpp", 9 | "array": "cpp", 10 | "deque": "cpp", 11 | "forward_list": "cpp", 12 | "list": "cpp", 13 | "vector": "cpp", 14 | "string_view": "cpp", 15 | "span": "cpp", 16 | "cmath": "cpp", 17 | "complex": "cpp", 18 | "cctype": "cpp", 19 | "clocale": "cpp", 20 | "cstdarg": "cpp", 21 | "cstddef": "cpp", 22 | "cstdio": "cpp", 23 | "cstdlib": "cpp", 24 | "cstring": "cpp", 25 | "ctime": "cpp", 26 | "cwchar": "cpp", 27 | "cwctype": "cpp", 28 | "any": "cpp", 29 | "atomic": "cpp", 30 | "hash_map": "cpp", 31 | "bit": "cpp", 32 | "*.tcc": "cpp", 33 | "bitset": "cpp", 34 | "cfenv": "cpp", 35 | "charconv": "cpp", 36 | "cinttypes": "cpp", 37 | "codecvt": "cpp", 38 | "compare": "cpp", 39 | "concepts": "cpp", 40 | "condition_variable": "cpp", 41 | "cstdint": "cpp", 42 | "map": "cpp", 43 | "set": "cpp", 44 | "string": "cpp", 45 | "unordered_map": "cpp", 46 | "unordered_set": "cpp", 47 | "exception": "cpp", 48 | "algorithm": "cpp", 49 | "iterator": "cpp", 50 | "memory_resource": "cpp", 51 | "numeric": "cpp", 52 | "optional": "cpp", 53 | "random": "cpp", 54 | "ratio": "cpp", 55 | "source_location": "cpp", 56 | "system_error": "cpp", 57 | "tuple": "cpp", 58 | "type_traits": "cpp", 59 | "utility": "cpp", 60 | "hash_set": "cpp", 61 | "fstream": "cpp", 62 | "initializer_list": "cpp", 63 | "iomanip": "cpp", 64 | "iosfwd": "cpp", 65 | "iostream": "cpp", 66 | "limits": "cpp", 67 | "mutex": "cpp", 68 | "new": "cpp", 69 | "numbers": "cpp", 70 | "ostream": "cpp", 71 | "ranges": "cpp", 72 | "semaphore": "cpp", 73 | "shared_mutex": "cpp", 74 | "sstream": "cpp", 75 | "stdexcept": "cpp", 76 | "stdfloat": "cpp", 77 | "stop_token": "cpp", 78 | "streambuf": "cpp", 79 | "text_encoding": "cpp", 80 | "thread": "cpp", 81 | "typeindex": "cpp", 82 | "typeinfo": "cpp", 83 | "valarray": "cpp", 84 | "variant": "cpp" 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /JuceLibraryCode/JuceHeader.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | This is the header file that your files should include in order to get all the 7 | JUCE library headers. You should avoid including the JUCE headers directly in 8 | your own source files, because that wouldn't pick up the correct configuration 9 | options for your app. 10 | 11 | */ 12 | 13 | #pragma once 14 | 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "BinaryData.h" 32 | 33 | #if defined (JUCE_PROJUCER_VERSION) && JUCE_PROJUCER_VERSION < JUCE_VERSION 34 | /** If you've hit this error then the version of the Projucer that was used to generate this project is 35 | older than the version of the JUCE modules being included. To fix this error, re-save your project 36 | using the latest version of the Projucer or, if you aren't using the Projucer to manage your project, 37 | remove the JUCE_PROJUCER_VERSION define. 38 | */ 39 | #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." 40 | #endif 41 | 42 | #if ! DONT_SET_USING_JUCE_NAMESPACE 43 | // If your code uses a lot of JUCE classes, then this will obviously save you 44 | // a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE. 45 | using namespace juce; 46 | #endif 47 | 48 | #if ! JUCE_DONT_DECLARE_PROJECTINFO 49 | namespace ProjectInfo 50 | { 51 | const char* const projectName = "Plasma"; 52 | const char* const companyName = "Dimethoxy"; 53 | const char* const versionString = "1.2.1"; 54 | const int versionNumber = 0x10201; 55 | } 56 | #endif 57 | -------------------------------------------------------------------------------- /Source/ShapercurveComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "ShapercurveComponent.h" 2 | 3 | ShapercurveComponent::ShapercurveComponent(PlasmaAudioProcessor& p, int stage) 4 | : audioProcessor(p) 5 | { 6 | // Listen to parameter changes 7 | const auto& params = audioProcessor.getParameters(); 8 | for (auto param : params) { 9 | param->addListener(this); 10 | } 11 | startTimerHz(60); 12 | this->stage = stage; 13 | } 14 | 15 | ShapercurveComponent::~ShapercurveComponent() 16 | { 17 | const auto& params = audioProcessor.getParameters(); 18 | for (auto param : params) { 19 | param->removeListener(this); 20 | } 21 | } 22 | 23 | void 24 | ShapercurveComponent::parameterValueChanged(int parameterIndex, float newValue) 25 | { 26 | parametersChanged.set(true); 27 | } 28 | 29 | void 30 | ShapercurveComponent::timerCallback() 31 | { 32 | if (parametersChanged.compareAndSetBool(false, true)) { 33 | repaint(); 34 | } 35 | } 36 | 37 | void 38 | ShapercurveComponent::paint(juce::Graphics& g) 39 | { 40 | using namespace juce; 41 | 42 | // Get Chain Settings 43 | auto chainSettings = getChainSettings(audioProcessor.apvts); 44 | 45 | // bounds 46 | auto bounds = getBounds(); 47 | auto lineSize = bounds.getHeight() / 100; 48 | lineSize = (lineSize < 1.0) ? 1.0f : lineSize; 49 | 50 | // Screen 51 | auto x = 0; 52 | auto y = 0; 53 | auto w = bounds.getWidth(); 54 | auto h = bounds.getHeight(); 55 | 56 | // Info 57 | float drive = 2.0; 58 | Distortion type = Distortion::Hardclip; 59 | float bias = 0.0; 60 | float girth = 0.0; 61 | switch (stage) { 62 | case 0: { 63 | type = chainSettings.driveType; 64 | drive = chainSettings.drive; 65 | bias = chainSettings.bias; 66 | girth = chainSettings.girth; 67 | break; 68 | } 69 | case 1: { 70 | type = chainSettings.lateDriveType; 71 | drive = chainSettings.lateDrive; 72 | bias = chainSettings.lateBias; 73 | girth = chainSettings.lateGirth; 74 | break; 75 | } 76 | } 77 | float sampleSize = 2.0 / w; 78 | 79 | // Draw 80 | std::vector samples; 81 | samples.resize(w); 82 | juce::Random random(420); 83 | for (int i = 0; i < w; ++i) { 84 | // Write 85 | samples[i] = i * sampleSize - 1; 86 | 87 | // Distort 88 | DistortionProcessor::distort(samples[i], drive, type); 89 | 90 | // Girth 91 | samples[i] = samples[i] * ((random.nextFloat() * abs(girth)) + 1); 92 | 93 | // Bias 94 | if (samples[i] > 0) { 95 | samples[i] += samples[i] * bias; 96 | } else if (samples[i] < 0) { 97 | samples[i] -= samples[i] * bias; 98 | } 99 | } 100 | Path shaperCurve; 101 | const double outputMin = y + h; 102 | const double outputMax = y; 103 | auto map = [outputMin, outputMax](double input) { 104 | return jmap(input, -1.0, 1.0, outputMin, outputMax); 105 | }; 106 | 107 | shaperCurve.startNewSubPath(x, map(samples.front())); 108 | for (size_t i = 1; i < samples.size(); ++i) { 109 | shaperCurve.lineTo(x + i, map(samples[i])); 110 | } 111 | 112 | g.setColour(Colours::white); 113 | g.drawRect(x, y, w, h, 2.0 * lineSize); 114 | g.strokePath(shaperCurve, PathStrokeType(1.5 * lineSize)); 115 | } 116 | 117 | void 118 | ShapercurveComponent::setColor(Colour c) 119 | { 120 | color = c; 121 | } 122 | -------------------------------------------------------------------------------- /Source/BaseVisualiser.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class BaseVisualiser 4 | : public Component 5 | , private Timer 6 | { 7 | public: 8 | /** Creates a visualiser with the given number of channels. */ 9 | BaseVisualiser(int initialNumChannels); 10 | 11 | /** Destructor. */ 12 | ~BaseVisualiser() override; 13 | 14 | /** Changes the number of channels that the visualiser stores. */ 15 | void setNumChannels(int numChannels); 16 | 17 | /** Changes the number of samples that the visualiser keeps in its history. 18 | Note that this value refers to the number of averaged sample blocks, and 19 | each block is calculated as the peak of a number of incoming audio samples. 20 | To set the number of incoming samples per block, use setSamplesPerBlock(). 21 | */ 22 | void setBufferSize(int bufferSize); 23 | 24 | /** */ 25 | void setSamplesPerBlock(int newNumInputSamplesPerBlock) noexcept; 26 | 27 | /** */ 28 | int getSamplesPerBlock() const noexcept { return inputSamplesPerBlock; } 29 | 30 | /** Clears the contents of the buffers. */ 31 | void clear(); 32 | 33 | /** Pushes a buffer of channels data. 34 | The number of channels provided here is expected to match the number of 35 | channels that this BaseVisualiser has been told to use. 36 | */ 37 | void pushBuffer(const AudioBuffer& bufferToPush); 38 | 39 | /** Pushes a buffer of channels data. 40 | The number of channels provided here is expected to match the number of 41 | channels that this BaseVisualiser has been told to use. 42 | */ 43 | void pushBuffer(const AudioSourceChannelInfo& bufferToPush); 44 | 45 | /** Pushes a buffer of channels data. 46 | The number of channels provided here is expected to match the number of 47 | channels that this BaseVisualiser has been told to use. 48 | */ 49 | void pushBuffer(const float* const* channelData, 50 | int numChannels, 51 | int numSamples); 52 | 53 | /** Pushes a single sample (per channel). 54 | The number of channels provided here is expected to match the number of 55 | channels that this BaseVisualiser has been told to use. 56 | */ 57 | void pushSample(const float* samplesForEachChannel, int numChannels); 58 | 59 | /** Sets the colours used to paint the */ 60 | void setColours(Colour backgroundColour, 61 | Colour waveformColour, 62 | Colour foregroundColour) noexcept; 63 | 64 | /** Sets the frequency at which the component repaints itself. */ 65 | void setRepaintRate(int frequencyInHz); 66 | 67 | /** Draws a channel of audio data in the given bounds. 68 | The default implementation just calls getChannelAsPath() and fits this 69 | into the given area. You may want to override this to draw things 70 | differently. 71 | */ 72 | virtual void paintChannel(Graphics&, 73 | Rectangle bounds, 74 | const Range* levels, 75 | int numLevels, 76 | int nextSample); 77 | 78 | /** Creates a path which contains the waveform shape of a given set of range 79 | data. The path is normalised so that -1 and +1 are its upper and lower 80 | bounds, and it goes from 0 to numLevels on the X axis. 81 | */ 82 | void getChannelAsPath(Path& result, 83 | const Range* levels, 84 | int numLevels, 85 | int nextSample); 86 | 87 | void setForegroundColor(Colour c); 88 | //============================================================================== 89 | /** @internal */ 90 | void paint(Graphics&) override; 91 | void setCornerRadius(int cornerRadius); 92 | 93 | private: 94 | struct ChannelInfo; 95 | 96 | OwnedArray channels; 97 | int numSamples, inputSamplesPerBlock; 98 | Colour backgroundColour, foregroundColour, waveformColour; 99 | 100 | void timerCallback() override; 101 | int cornerRadius; 102 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(BaseVisualiser) 103 | }; 104 | -------------------------------------------------------------------------------- /Source/PlasmaDistortionProcessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "JuceHeader.h" 4 | #include "PluginProcessor.h" 5 | 6 | enum Distortion 7 | { 8 | Hardclip, 9 | Softclip, 10 | Saturate, 11 | Atan, 12 | Crunch, 13 | Bitcrush, 14 | Extreme, 15 | Scream, 16 | Sine, 17 | Cosine, 18 | Harmonize, 19 | Weird, 20 | }; 21 | namespace DistortionProcessor 22 | { 23 | inline float clamp(float d, float min, float max) 24 | { 25 | const float t = d < min ? min : d; 26 | return t > max ? max : t; 27 | } 28 | 29 | template 30 | void distort(Data& data, Drive& drive, Distortion& type) { 31 | switch (type) { 32 | case Distortion::Hardclip: 33 | { 34 | data = clamp(drive * data, -1.0, 1.0); 35 | break; 36 | } 37 | case Distortion::Crunch: 38 | { 39 | if (data > 0.0) { 40 | data = pow(data, 1.0f / drive); 41 | data = 1.27 * atan(data); 42 | } 43 | else { 44 | data = clamp(sin(drive * data), -1.0, 1.0); 45 | data = clamp(drive * data, -1.0, 1.0); 46 | }; 47 | break; 48 | } 49 | case Distortion::Bitcrush: 50 | { 51 | float bitDepth = 10.0f - (drive - 1); 52 | float exponent = bitDepth - 1; 53 | float possibleValues = pow(2, exponent); 54 | float quantized = (data + 1.0f) * possibleValues; 55 | quantized = round(quantized); 56 | data = (quantized / possibleValues) - 1.0f; 57 | break; 58 | } 59 | 60 | case Distortion::Saturate: 61 | { 62 | if (data > 0.0) { 63 | data = clamp(pow(data, 1.0 / ((drive / 4) + 0.75)), -1.0, 1.0); 64 | } 65 | else { 66 | data = -clamp(pow(-data, 1.0 / ((drive / 4) + 0.75)), -1.0, 1.0); 67 | } 68 | break; 69 | } 70 | case Distortion::Atan: 71 | { 72 | if (data != 0.0f) 73 | { 74 | if (data > 0.0f) { 75 | data = pow(data, 1.0f / drive); 76 | data = 1.27f * atan(data); 77 | } 78 | else { 79 | data = pow(-data, 1.0f / drive); 80 | data = 1.27f * atan(data); 81 | data = -data; 82 | } 83 | } 84 | break; 85 | } 86 | case Distortion::Sine: { 87 | data = clamp(sin(drive * data), -1.0, 1.0); 88 | break; 89 | } 90 | case Distortion::Cosine: { 91 | data = clamp(cos(drive * data), -1.0, 1.0); 92 | break; 93 | } 94 | case Distortion::Extreme: { 95 | float invertedDrive = 10.0f - (drive - 1); 96 | if (std::abs(data) >= ((invertedDrive - 1) / 9.0f)) 97 | { 98 | auto signbit = (std::signbit(data) ? -1 : 1); 99 | data = signbit; 100 | } 101 | break; 102 | } 103 | case Distortion::Softclip: { 104 | float threshold1 = 1.0f / 3.0f; 105 | float threshold2 = 2.0f / 3.0f; 106 | 107 | data *= drive; 108 | if (data > threshold2) 109 | data = 1.0f; 110 | else if (data > threshold1) 111 | data = 1.0f - powf(2.0f - 3.0f * data, 2.0f) / 3.0f; 112 | else if (data < -threshold2) 113 | data = -1.0f; 114 | else if (data < -threshold1) 115 | data = -1.0f + powf(2.0f + 3.0f * data, 2.0f) / 3.0f; 116 | else 117 | data = 2.0f * data; 118 | 119 | break; 120 | } 121 | case Distortion::Weird: { 122 | data = data * (drive * 2); 123 | float h1 = sin(2 * data); 124 | float h2 = sin(3 * data); 125 | float h3 = sin(4 * data); 126 | data = sin(h1 + h2 + h3 + data); 127 | break; 128 | } 129 | case Distortion::Scream: { 130 | auto temp = data; 131 | auto normalizedDrive = (drive - 1) / 10.0f; 132 | 133 | if (data > 0.0) { 134 | data = clamp(pow(data, 1.0 / ((drive / 4) + 0.75)), -1.0, 1.0); 135 | } 136 | else { 137 | data = -clamp(pow(-data, 1.0 / ((drive / 4) + 0.75)), -1.0, 1.0); 138 | } 139 | 140 | 141 | if (data <= -0.5) 142 | { 143 | auto offset = 3.0; 144 | temp = 4 * data + offset; 145 | } 146 | else if (data > -0.5 && data < 0.5) 147 | { 148 | temp = -2 * data; 149 | } 150 | else 151 | { 152 | auto offset = -3.0; 153 | temp = 4 * data + offset; 154 | } 155 | 156 | data = (temp * normalizedDrive) + (data * (1 - normalizedDrive)); 157 | 158 | 159 | break; 160 | 161 | } 162 | case Distortion::Harmonize: { 163 | data = data * (drive * 5); 164 | float h1 = sin(2 * data); 165 | float h2 = sin(3 * data); 166 | float h3 = sin(4 * data); 167 | data = (h1 + h2 + h3 + data) / (drive * 5); 168 | break; 169 | } 170 | } 171 | } 172 | } 173 | 174 | -------------------------------------------------------------------------------- /Resources/Poppins/OFL.txt: -------------------------------------------------------------------------------- 1 | Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /Resources/Sedgwick_Ave_Display/OFL.txt: -------------------------------------------------------------------------------- 1 | Copyright 2017 The Sedgwick Ave Project Authors (https://github.com/googlefonts/sedgwickave) 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /Source/Version.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | //============================================================================================= 3 | #include 4 | //============================================================================================= 5 | enum Target 6 | { 7 | Windows, 8 | Mac, 9 | Linux 10 | }; 11 | const auto operatingSystemType = []() { 12 | auto osType = juce::SystemStats::getOperatingSystemType(); 13 | auto win = juce::SystemStats::Windows; 14 | auto win7 = juce::SystemStats::Windows7; 15 | auto win8 = juce::SystemStats::Windows8_0 && juce::SystemStats::Windows8_1; 16 | auto win10 = juce::SystemStats::Windows10; 17 | auto win11 = juce::SystemStats::Windows11; 18 | auto winXP = juce::SystemStats::WinXP; 19 | bool isWindows = osType == win || osType == win7 || osType == win8 || 20 | osType == win10 || osType == win11 || osType == winXP; 21 | auto macOSX_10_7 = juce::SystemStats::MacOSX_10_7; 22 | auto macOSX_10_8 = juce::SystemStats::MacOSX_10_8; 23 | auto macOSX_10_9 = juce::SystemStats::MacOSX_10_9; 24 | auto macOSX_10_10 = juce::SystemStats::MacOSX_10_10; 25 | auto macOSX_10_11 = juce::SystemStats::MacOSX_10_11; 26 | auto macOSX_10_12 = juce::SystemStats::MacOSX_10_12; 27 | auto macOSX_10_13 = juce::SystemStats::MacOSX_10_13; 28 | auto macOSX_10_14 = juce::SystemStats::MacOSX_10_14; 29 | auto macOSX_10_15 = juce::SystemStats::MacOSX_10_15; 30 | auto macOS_11 = juce::SystemStats::MacOS_11; 31 | auto macOS_12 = juce::SystemStats::MacOS_12; 32 | auto macOS_13 = juce::SystemStats::MacOS_13; 33 | auto macOS_14 = juce::SystemStats::MacOS_14; 34 | bool isMac = macOSX_10_7 || macOSX_10_8 || macOSX_10_9 || macOSX_10_10 || 35 | macOSX_10_11 || macOSX_10_12 || macOSX_10_13 || macOSX_10_14 || 36 | macOSX_10_15 || macOS_11 || macOS_12 || macOS_13 || macOS_14; 37 | 38 | if (isWindows) 39 | return juce::SystemStats::Windows; 40 | if (isMac) 41 | return juce::SystemStats::MacOSX; 42 | else 43 | return osType; 44 | }(); 45 | //============================================================================================= 46 | class VersionManager : public juce::AsyncUpdater 47 | { 48 | public: 49 | VersionManager() 50 | : juce::AsyncUpdater() 51 | { 52 | } 53 | void handleAsyncUpdate() 54 | { 55 | t = std::make_unique([this] { updateVersion(); }); 56 | t->detach(); 57 | } 58 | void updateVersion() 59 | { 60 | const bool response = isUpToDate(ProjectInfo::versionString); 61 | juce::String link = ""; 62 | if (!response) { 63 | link = getDownloadLink(); 64 | } 65 | if (killFlag.load()) { 66 | return; 67 | } else { 68 | downloadLink = link; 69 | isLatest.store(!response); 70 | finished.store(true); 71 | } 72 | } 73 | 74 | std::atomic killFlag{ false }; 75 | std::atomic isLatest{ false }; 76 | std::atomic finished{ false }; 77 | juce::String downloadLink{ "" }; 78 | 79 | private: 80 | std::unique_ptr t; 81 | 82 | juce::URL createURL(const juce::String& apiEndpoint) 83 | { 84 | return juce::URL("https://api.dimethoxy.com/" + apiEndpoint); 85 | } 86 | 87 | juce::String sendRequest(const juce::String& apiEndpoint) 88 | { 89 | juce::URL url = createURL(apiEndpoint); 90 | 91 | // Send a GET request to the specified URL 92 | juce::String responseString = url.readEntireTextStream(); 93 | 94 | return responseString; 95 | } 96 | 97 | juce::String extractVersionNumber(const juce::String& payload) 98 | { 99 | juce::var responseJSON = juce::JSON::parse(payload); 100 | juce::String version = responseJSON["version"].toString(); 101 | return version; 102 | } 103 | 104 | bool isUpToDate(const juce::String& currentVersion) 105 | { 106 | try { 107 | String versionParam = String("version=") + ProjectInfo::versionString; 108 | String osParam = String("os=") + SystemStats::getOperatingSystemName(); 109 | String requestParams = String("?") + versionParam + String("&") + osParam; 110 | String apiResponse = sendRequest(String("version?") + requestParams); 111 | String latestVersion = extractVersionNumber(apiResponse); 112 | bool isLatest = (latestVersion == currentVersion) || latestVersion == ""; 113 | return isLatest; 114 | } catch (...) { 115 | return true; 116 | } 117 | } 118 | 119 | juce::String getDownloadLink() 120 | { 121 | juce::String osString; 122 | if (operatingSystemType == 123 | juce::SystemStats::OperatingSystemType::Windows) { 124 | osString = "windows"; 125 | } else if (operatingSystemType == 126 | juce::SystemStats::OperatingSystemType::MacOSX) { 127 | osString = "mac"; 128 | } else if (operatingSystemType == 129 | juce::SystemStats::OperatingSystemType::Linux) { 130 | osString = "archlinux"; 131 | } 132 | juce::String apiResponse = 133 | sendRequest("download?product=plasma&os=" + osString); 134 | juce::var responseJSON = juce::JSON::parse(apiResponse); 135 | return responseJSON["download_url"].toString(); 136 | } 137 | }; 138 | -------------------------------------------------------------------------------- /JuceLibraryCode/JucePluginDefines.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | IMPORTANT! This file is auto-generated each time you save your 4 | project - if you alter its contents, your changes may be overwritten! 5 | 6 | */ 7 | 8 | #pragma once 9 | 10 | //============================================================================== 11 | // Audio plugin settings.. 12 | 13 | #ifndef JucePlugin_Build_VST 14 | #define JucePlugin_Build_VST 0 15 | #endif 16 | #ifndef JucePlugin_Build_VST3 17 | #define JucePlugin_Build_VST3 1 18 | #endif 19 | #ifndef JucePlugin_Build_AU 20 | #define JucePlugin_Build_AU 1 21 | #endif 22 | #ifndef JucePlugin_Build_AUv3 23 | #define JucePlugin_Build_AUv3 0 24 | #endif 25 | #ifndef JucePlugin_Build_AAX 26 | #define JucePlugin_Build_AAX 0 27 | #endif 28 | #ifndef JucePlugin_Build_Standalone 29 | #define JucePlugin_Build_Standalone 0 30 | #endif 31 | #ifndef JucePlugin_Build_Unity 32 | #define JucePlugin_Build_Unity 0 33 | #endif 34 | #ifndef JucePlugin_Build_LV2 35 | #define JucePlugin_Build_LV2 1 36 | #endif 37 | #ifndef JucePlugin_Enable_IAA 38 | #define JucePlugin_Enable_IAA 0 39 | #endif 40 | #ifndef JucePlugin_Enable_ARA 41 | #define JucePlugin_Enable_ARA 0 42 | #endif 43 | #ifndef JucePlugin_Name 44 | #define JucePlugin_Name "Plasma" 45 | #endif 46 | #ifndef JucePlugin_Desc 47 | #define JucePlugin_Desc "Distortion" 48 | #endif 49 | #ifndef JucePlugin_Manufacturer 50 | #define JucePlugin_Manufacturer "Dimethoxy" 51 | #endif 52 | #ifndef JucePlugin_ManufacturerWebsite 53 | #define JucePlugin_ManufacturerWebsite "Dimethoxy.com" 54 | #endif 55 | #ifndef JucePlugin_ManufacturerEmail 56 | #define JucePlugin_ManufacturerEmail "dimethoxy.audio@gmail.com" 57 | #endif 58 | #ifndef JucePlugin_ManufacturerCode 59 | #define JucePlugin_ManufacturerCode 0x446d7478 60 | #endif 61 | #ifndef JucePlugin_PluginCode 62 | #define JucePlugin_PluginCode 0x516d6638 63 | #endif 64 | #ifndef JucePlugin_IsSynth 65 | #define JucePlugin_IsSynth 0 66 | #endif 67 | #ifndef JucePlugin_WantsMidiInput 68 | #define JucePlugin_WantsMidiInput 0 69 | #endif 70 | #ifndef JucePlugin_ProducesMidiOutput 71 | #define JucePlugin_ProducesMidiOutput 0 72 | #endif 73 | #ifndef JucePlugin_IsMidiEffect 74 | #define JucePlugin_IsMidiEffect 0 75 | #endif 76 | #ifndef JucePlugin_EditorRequiresKeyboardFocus 77 | #define JucePlugin_EditorRequiresKeyboardFocus 0 78 | #endif 79 | #ifndef JucePlugin_Version 80 | #define JucePlugin_Version 1.2.1 81 | #endif 82 | #ifndef JucePlugin_VersionCode 83 | #define JucePlugin_VersionCode 0x10201 84 | #endif 85 | #ifndef JucePlugin_VersionString 86 | #define JucePlugin_VersionString "1.2.1" 87 | #endif 88 | #ifndef JucePlugin_VSTUniqueID 89 | #define JucePlugin_VSTUniqueID JucePlugin_PluginCode 90 | #endif 91 | #ifndef JucePlugin_VSTCategory 92 | #define JucePlugin_VSTCategory kPlugCategEffect 93 | #endif 94 | #ifndef JucePlugin_Vst3Category 95 | #define JucePlugin_Vst3Category "Fx|Distortion" 96 | #endif 97 | #ifndef JucePlugin_AUMainType 98 | #define JucePlugin_AUMainType 'aufx' 99 | #endif 100 | #ifndef JucePlugin_AUSubType 101 | #define JucePlugin_AUSubType JucePlugin_PluginCode 102 | #endif 103 | #ifndef JucePlugin_AUExportPrefix 104 | #define JucePlugin_AUExportPrefix PlasmaAU 105 | #endif 106 | #ifndef JucePlugin_AUExportPrefixQuoted 107 | #define JucePlugin_AUExportPrefixQuoted "PlasmaAU" 108 | #endif 109 | #ifndef JucePlugin_AUManufacturerCode 110 | #define JucePlugin_AUManufacturerCode JucePlugin_ManufacturerCode 111 | #endif 112 | #ifndef JucePlugin_CFBundleIdentifier 113 | #define JucePlugin_CFBundleIdentifier com.Dimethoxy.Plasma 114 | #endif 115 | #ifndef JucePlugin_AAXIdentifier 116 | #define JucePlugin_AAXIdentifier com.Dimethoxy.Plasma 117 | #endif 118 | #ifndef JucePlugin_AAXManufacturerCode 119 | #define JucePlugin_AAXManufacturerCode JucePlugin_ManufacturerCode 120 | #endif 121 | #ifndef JucePlugin_AAXProductId 122 | #define JucePlugin_AAXProductId JucePlugin_PluginCode 123 | #endif 124 | #ifndef JucePlugin_AAXCategory 125 | #define JucePlugin_AAXCategory 0 126 | #endif 127 | #ifndef JucePlugin_AAXDisableBypass 128 | #define JucePlugin_AAXDisableBypass 0 129 | #endif 130 | #ifndef JucePlugin_AAXDisableMultiMono 131 | #define JucePlugin_AAXDisableMultiMono 0 132 | #endif 133 | #ifndef JucePlugin_IAAType 134 | #define JucePlugin_IAAType 0x61757278 135 | #endif 136 | #ifndef JucePlugin_IAASubType 137 | #define JucePlugin_IAASubType JucePlugin_PluginCode 138 | #endif 139 | #ifndef JucePlugin_IAAName 140 | #define JucePlugin_IAAName "Dimethoxy: Plasma" 141 | #endif 142 | #ifndef JucePlugin_VSTNumMidiInputs 143 | #define JucePlugin_VSTNumMidiInputs 16 144 | #endif 145 | #ifndef JucePlugin_VSTNumMidiOutputs 146 | #define JucePlugin_VSTNumMidiOutputs 16 147 | #endif 148 | #ifndef JucePlugin_ARAContentTypes 149 | #define JucePlugin_ARAContentTypes 0 150 | #endif 151 | #ifndef JucePlugin_ARATransformationFlags 152 | #define JucePlugin_ARATransformationFlags 0 153 | #endif 154 | #ifndef JucePlugin_ARAFactoryID 155 | #define JucePlugin_ARAFactoryID "com.Dimethoxy.Plasma.factory" 156 | #endif 157 | #ifndef JucePlugin_ARADocumentArchiveID 158 | #define JucePlugin_ARADocumentArchiveID "com.Dimethoxy.Plasma.aradocumentarchive.1.2.1" 159 | #endif 160 | #ifndef JucePlugin_ARACompatibleArchiveIDs 161 | #define JucePlugin_ARACompatibleArchiveIDs "" 162 | #endif 163 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | This project is focused on technical collaboration and development. Discussions 16 | or contributions related to politics, religion, or ideology are not appropriate 17 | in this community and should be avoided. 18 | 19 | ## Our Standards 20 | 21 | Examples of behavior that contributes to a positive environment for our 22 | community include: 23 | 24 | - Demonstrating empathy and kindness toward other people 25 | - Being respectful of differing opinions, viewpoints, and experiences 26 | - Giving and gracefully accepting constructive feedback 27 | - Accepting responsibility and apologizing to those affected by our mistakes, 28 | and learning from the experience 29 | - Focusing on what is best not just for us as individuals, but for the 30 | overall community 31 | 32 | Examples of unacceptable behavior include: 33 | 34 | - The use of sexualized language or imagery, and sexual attention or 35 | advances of any kind 36 | - Trolling, insulting or derogatory comments, and personal or political attacks 37 | - Public or private harassment 38 | - Publishing others' private information, such as a physical or email 39 | address, without their explicit permission 40 | - Other conduct which could reasonably be considered inappropriate in a 41 | professional setting 42 | - Introducing or engaging in discussions about politics, religion, or ideology 43 | 44 | ## Enforcement Responsibilities 45 | 46 | Community leaders are responsible for clarifying and enforcing our standards of 47 | acceptable behavior and will take appropriate and fair corrective action in 48 | response to any behavior that they deem inappropriate, threatening, offensive, 49 | or harmful. 50 | 51 | Community leaders have the right and responsibility to remove, edit, or reject 52 | comments, commits, code, wiki edits, issues, and other contributions that are 53 | not aligned to this Code of Conduct, and will communicate reasons for moderation 54 | decisions when appropriate. 55 | 56 | ## Scope 57 | 58 | This Code of Conduct applies within all community spaces, and also applies when 59 | an individual is officially representing the community in public spaces. 60 | Examples of representing our community include using an official e-mail address, 61 | posting via an official social media account, or acting as an appointed 62 | representative at an online or offline event. 63 | 64 | ## Enforcement 65 | 66 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 67 | reported to the community leaders responsible for enforcement at 68 | . 69 | All complaints will be reviewed and investigated promptly and fairly. 70 | 71 | All community leaders are obligated to respect the privacy and security of the 72 | reporter of any incident. 73 | 74 | ## Enforcement Guidelines 75 | 76 | Community leaders will follow these Community Impact Guidelines in determining 77 | the consequences for any action they deem in violation of this Code of Conduct: 78 | 79 | ### 1. Correction 80 | 81 | **Community Impact**: Use of inappropriate language or other behavior deemed 82 | unprofessional or unwelcome in the community. 83 | 84 | **Consequence**: A private, written warning from community leaders, providing 85 | clarity around the nature of the violation and an explanation of why the 86 | behavior was inappropriate. A public apology may be requested. 87 | 88 | ### 2. Warning 89 | 90 | **Community Impact**: A violation through a single incident or series 91 | of actions. 92 | 93 | **Consequence**: A warning with consequences for continued behavior. No 94 | interaction with the people involved, including unsolicited interaction with 95 | those enforcing the Code of Conduct, for a specified period of time. This 96 | includes avoiding interactions in community spaces as well as external channels 97 | like social media. Violating these terms may lead to a temporary or 98 | permanent ban. 99 | 100 | ### 3. Temporary Ban 101 | 102 | **Community Impact**: A serious violation of community standards, including 103 | sustained inappropriate behavior. 104 | 105 | **Consequence**: A temporary ban from any sort of interaction or public 106 | communication with the community for a specified period of time. No public or 107 | private interaction with the people involved, including unsolicited interaction 108 | with those enforcing the Code of Conduct, is allowed during this period. 109 | Violating these terms may lead to a permanent ban. 110 | 111 | ### 4. Permanent Ban 112 | 113 | **Community Impact**: Demonstrating a pattern of violation of community 114 | standards, including sustained inappropriate behavior, harassment of an 115 | individual, or aggression toward or disparagement of classes of individuals. 116 | 117 | **Consequence**: A permanent ban from any sort of public interaction within 118 | the community. 119 | 120 | ## Attribution 121 | 122 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 123 | version 2.0, available at 124 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 125 | 126 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 127 | enforcement ladder](https://github.com/mozilla/diversity). 128 | 129 | [homepage]: https://www.contributor-covenant.org 130 | 131 | For answers to common questions about this code of conduct, see the FAQ at 132 | https://www.contributor-covenant.org/faq. Translations are available at 133 | https://www.contributor-covenant.org/translations. 134 | -------------------------------------------------------------------------------- /Source/ValueEditor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CustomLabel.h" 4 | #include "CustomRotarySlider.h" 5 | #include "ValueEditor.h" 6 | #include 7 | 8 | // class ValueEditorBackground : public Component 9 | // {}; 10 | 11 | class ValueEditor 12 | : public Component 13 | , public TextEditor::Listener 14 | { 15 | public: 16 | ValueEditor() 17 | : textbox("0", FontSizes::Main, Justification::centredLeft) 18 | , titleLabel("Value Editor", FontSizes::Main, Justification::centredBottom) 19 | { 20 | addAndMakeVisible(textbox); 21 | addAndMakeVisible(titleLabel); 22 | textbox.onEditorHide = [this] { this->textEditorHide(); }; 23 | } 24 | 25 | void resized() override 26 | { 27 | titleLabel.setBoundsRelative(0.10f, 0.0f, 0.8f, 0.49f); 28 | textbox.setBoundsRelative(0.35f, 0.52f, 0.3f, 0.12f); 29 | } 30 | 31 | void paint(Graphics& g) override 32 | { 33 | g.setColour(backgroundColor); 34 | g.fillRoundedRectangle(getLocalBounds().toFloat(), cornerSize); 35 | g.setColour(textColor); 36 | const float reduction = getWidth() * 0.13f; 37 | const auto innerBounds = getLocalBounds() 38 | .reduced(reduction) 39 | .withCentre(getLocalBounds().getCentre()) 40 | .toFloat(); 41 | g.drawRoundedRectangle(innerBounds, cornerSize, reduction / 20.0f); 42 | } 43 | 44 | void setColour(Colour background, Colour text) 45 | { 46 | backgroundColor = background; 47 | textColor = text; 48 | } 49 | 50 | const String readValue(CustomRotarySlider* slider) 51 | { 52 | const auto rawValue = slider->getValue(); 53 | const String name = slider->getName(); 54 | if (name == "Symmetry") { 55 | return String(rawValue * 100.0f); 56 | } else if (name == "Girth") { 57 | return String(rawValue * 100.0f); 58 | } else if (name == "Drive") { 59 | return String((rawValue - 1.0f) * 10.0f); 60 | } else if (name == "Slope") { 61 | int slope = static_cast((rawValue + 1) * 12.0f); 62 | if (slope <= 96) { 63 | return String(slope); 64 | } else { 65 | return String("Peak Only"); 66 | } 67 | } else if (name == "Distortion") { 68 | const int dist = static_cast(rawValue); 69 | if (dist == 0) { 70 | return String("Hard Clip"); 71 | } else if (dist == 1) { 72 | return String("Soft Clip"); 73 | } else if (dist == 2) { 74 | return String("Saturate"); 75 | } else if (dist == 3) { 76 | return String("Atan"); 77 | } else if (dist == 4) { 78 | return String("Crunch"); 79 | } else if (dist == 5) { 80 | return String("Bitcrush"); 81 | } else if (dist == 6) { 82 | return String("Extreme"); 83 | } else if (dist == 7) { 84 | return String("Scream"); 85 | } else if (dist == 8) { 86 | return String("Sine"); 87 | } else if (dist == 9) { 88 | return String("Cosine"); 89 | } else if (dist == 10) { 90 | return String("Harmonize"); 91 | } else if (dist == 11) { 92 | return String("Weird"); 93 | }; 94 | } 95 | return String(rawValue); 96 | } 97 | 98 | const float writeValue(String value) 99 | { 100 | if (name == "Symmetry") { 101 | return value.getFloatValue() / 100.0f; 102 | } else if (name == "Girth") { 103 | return value.getFloatValue() / 100.0f; 104 | } else if (name == "Drive") { 105 | return (value.getFloatValue() / 10.0f) + 1.0f; 106 | } else if (name == "Slope") { 107 | if (value == "Peak Only") { 108 | return 7.0f; 109 | } else { 110 | return (value.getFloatValue() / 12.0f) - 1.0f; 111 | } 112 | } else if (name == "Distortion") { 113 | if (value == "Hard Clip") { 114 | return 0.0f; 115 | } else if (value == "Soft Clip") { 116 | return 1.0f; 117 | } else if (value == "Saturate") { 118 | return 2.0f; 119 | } else if (value == "Atan") { 120 | return 3.0f; 121 | } else if (value == "Crunch") { 122 | return 4.0f; 123 | } else if (value == "Bitcrush") { 124 | return 5.0f; 125 | } else if (value == "Extreme") { 126 | return 6.0f; 127 | } else if (value == "Scream") { 128 | return 7.0f; 129 | } else if (value == "Sine") { 130 | return 8.0f; 131 | } else if (value == "Cosine") { 132 | return 9.0f; 133 | } else if (value == "Harmonize") { 134 | return 10.0f; 135 | } else if (value == "Weird") { 136 | return 11.0f; 137 | } 138 | } 139 | return value.getFloatValue(); 140 | } 141 | 142 | void setSlider(CustomRotarySlider* slider) 143 | { 144 | this->slider = slider; 145 | this->name = slider->getName(); 146 | titleLabel.setText(slider->getName() + ":", dontSendNotification); 147 | const auto convertedValue = readValue(slider); 148 | textbox.setText(convertedValue, dontSendNotification); 149 | textbox.showEditor(); 150 | textbox.grabKeyboardFocus(); 151 | lastValue = slider->getValue(); 152 | } 153 | 154 | void textEditorHide() 155 | { 156 | const String newText = textbox.getText(); 157 | const float newValue = writeValue(newText); 158 | slider->setValue(newValue); 159 | const float setValue = slider->getValue(); 160 | textbox.setText(String(setValue), dontSendNotification); 161 | setVisible(false); 162 | } 163 | 164 | void setBackgroundColor(Colour color) { backgroundColor = color; } 165 | 166 | void setCornerRadius(float corner) { cornerSize = corner; } 167 | 168 | void setFontColor(Colour color) 169 | { 170 | textbox.setColour(Label::ColourIds::textColourId, color); 171 | textbox.setColour(Label::ColourIds::textWhenEditingColourId, color); 172 | textbox.setColour(TextEditor::ColourIds::highlightedTextColourId, color); 173 | titleLabel.setColour(Label::ColourIds::textColourId, color); 174 | textColor = color; 175 | repaint(); 176 | } 177 | 178 | private: 179 | CustomRotarySlider* slider; 180 | String name = "Value Editor"; 181 | CustomTextbox textbox; 182 | CustomLabel titleLabel; 183 | Colour backgroundColor = Colour(40, 42, 54); 184 | Colour textColor = Colour(68, 71, 90); 185 | float cornerSize = 5.0f; 186 | float lastValue = 0.0f; 187 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Plasma 2 | 3 | Plasma is a free & open-source distortion powerhouse for VST3 hosts. Originally designed for Hardstyle, Gabber, Hardcore, and anything that needs raw, aggressive energy, Plasma lets you twist and destroy your sound with 12 brutal distortion styles and filters with extreme resonance capabilities. 4 | 5 | But don’t box it in—Plasma is a sound design weapon for any genre. Use it to add bite to guitars, weight to basslines, or grit to synths. Whether you're sculpting punishing drops or crushing breakbeats, Plasma delivers. 6 | 7 |
8 | Image of the GUI 9 |
10 | 11 | ## 🔥 Features 12 | 13 | - **Free & Open-Source** – No paywalls, no restrictions 14 | - **Asymmetrical Distortion** – Analog-inspired digital mayhem 15 | - **12 Distortion Styles** – From subtle warmth to total destruction 16 | - **4 Filters** – Highpass, lowpass, dual, and peak filters with up to 64dB resonance for extreme sound shaping 17 | - **Girth Effect** – Uses noise to erode the sound, adding high-end dirt and texture. 18 | - **Oscilloscope** – See your sound shaping in real time 19 | - **Customizable UI** – Minimalist vector interface with color options 20 | - **Scalable UI** – Perfect for high-res screens 21 | - **Intuitive Workflow** – Get to your sound quickly with easy-to-navigate controls. 22 | - **Low CPU impact** – Crush your sounds, not your processor 23 | - **Cross-platform** – Supports Windows, macOS, and Linux 24 | - **Multi-Format Support** – Works with VST3, LV2, and AU formats. 25 | - **Regular Updates** – Continuous improvements and new features 26 | - **Privacy First** – We take your privacy seriously, no tracking or data collection 27 | 28 | ## 💖 Donations 29 | 30 | If you love Plasma, consider supporting its development. 31 | [Donate via PayPal](https://www.paypal.com/donate/?hosted_button_id=8SJXCUYV5ZHKG) 32 | 33 | Your donation helps keep Plasma free, improves future updates, and supports the creation of new audio tools for the community. Thank you! 34 | 35 | ## 🔻 Downloads 36 | 37 | You can download our pre-built binaries for Windows, MacOS and Linux [here](https://github.com/Dimethoxy/Plasma/releases). 38 | 39 | ## 🐧 Arch Linux 40 | 41 | There is now an AUR package available for Arch Linux users. 42 | 43 | You can install it easily by using your favorite AUR helper (e.g. [yay](https://github.com/Jguer/yay)): 44 | ```bash 45 | yay -S dimethoxy-plasma-bin 46 | ``` 47 | Or manually: 48 | 49 | ```bash 50 | sudo pacman -S --needed base-devel 51 | git clone https://aur.archlinux.org/dimethoxy-plasma-bin.git 52 | cd dimethoxy-plasma-bin 53 | makepkg -si 54 | ``` 55 | We ensure Arch Linux users receive updates as soon as they're available, directly through the AUR. 56 | 57 | ## 💻 System Requirements 58 | 59 | ### Windows 60 | 61 | - Windows 10 or later 62 | - 64-bit Intel/AMD quad-core CPU or equivalent 63 | - 50 MB disk space 64 | - 64-bit DAW with VST3 support 65 | - ARM versions of Windows are NOT supported 66 | 67 | ### MacOS 68 | 69 | - MacOS 10.13 or later 70 | - Intel or Apple Silicon CPU 71 | - At least 50 MB of free disk space 72 | - 64-bit DAW with VST3 or AU support 73 | 74 | ### Linux 75 | 76 | - Mainstream x86_64 Linux distribution 77 | - 64-bit Intel/AMD quad-core CPU or equivalent 78 | - At least 50 MB of free disk space 79 | - 64-bit DAW with VST3 or LV2 support 80 | 81 | ## 🛠️ Build Instructions 82 | 83 | If you want to compile Plasma from source yourself, follow these steps: 84 | 85 | ### Requirements 86 | 87 | Before building Plasma, ensure you have the following: 88 | 89 | #### JUCE Build Requirements 90 | 91 | - **C++ Standard:** 17 92 | - **macOS/iOS:** Xcode 12.4 (Intel macOS 10.15.4, Apple Silicon macOS 11.0) 93 | - **Windows:** Visual Studio 2019 (Windows 10) 94 | - **Linux:** g++ 7.0 or Clang 6.0 95 | - **Android:** Android Studio (NDK 26) 96 | 97 | For full details on dependencies, refer to the [JUCE documentation](https://github.com/juce-framework/JUCE?tab=readme-ov-file#minimum-system-requirements). 98 | 99 | #### Additional Requirements 100 | 101 | - **Git** – Required for cloning the repository. If you haven't installed it yet, follow the [Git installation guide](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git). 102 | - **Linux Users:** You must also install the [JUCE dependencies for Linux](https://github.com/juce-framework/JUCE/blob/master/docs/Linux%20Dependencies.md). 103 | 104 | ### Steps to Build 105 | 106 | 1. Clone the Plasma Repository: 107 | ```bash 108 | git clone https://github.com/Dimethoxy/Plasma.git 109 | ``` 110 | 2. Download JUCE 8 from the [JUCE releases page](https://github.com/juce-framework/JUCE/releases/tag/8.0.6). 111 | 3. Extract JUCE to a location on your computer. 112 | 4. Open the Projucer app inside the JUCE folder you just extracted. 113 | 5. In Projucer, go to the top menu, click on File, then select Open. 114 | 6. Navigate to the cloned Plasma repository and choose the `Plasma.jucer` file to open the project. 115 | 7. Make sure to save the project once, this will generate the build files. 116 | 8. Build the project: 117 | - Windows/MacOS: 118 | - After saving, click the button at the top center of Projucer to open it in Visual Studio (Windows) or Xcode (macOS). 119 | - Now Build the project as usual in the IDE. 120 | - Linux 121 | - Navigate to the `Builds/LinuxMakefile/` folder inside the Plasma project. 122 | - Run the Makefile with one of these commands: 123 | ```bash 124 | make CONFIG=Release 125 | ``` 126 | ```bash 127 | make CONFIG=Debug 128 | ``` 129 | 130 | ## 📜 License 131 | 132 | The source code is licensed under the **GPLv3**. If you build or distribute it, you must comply with [GNU GPLv3](http://www.gnu.org/licenses/). 133 | 134 | ## ⚠️ Warranty 135 | 136 | You and your end-users use the software at your own risk. 137 | 138 | **THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.** 139 | -------------------------------------------------------------------------------- /Source/BaseVisualiser.cpp: -------------------------------------------------------------------------------- 1 | #include "BaseVisualiser.h" 2 | 3 | struct BaseVisualiser::ChannelInfo 4 | { 5 | ChannelInfo(BaseVisualiser& o, int bufferSize) 6 | : owner(o) 7 | { 8 | setBufferSize(bufferSize); 9 | clear(); 10 | } 11 | 12 | void clear() noexcept 13 | { 14 | levels.fill({}); 15 | value = {}; 16 | subSample = 0; 17 | } 18 | 19 | void pushSamples(const float* inputSamples, int num) noexcept 20 | { 21 | for (int i = 0; i < num; ++i) 22 | pushSample(inputSamples[i]); 23 | } 24 | 25 | void pushSample(float newSample) noexcept 26 | { 27 | if (--subSample <= 0) { 28 | if (++nextSample == levels.size()) 29 | nextSample = 0; 30 | 31 | levels.getReference(nextSample) = value; 32 | subSample = owner.getSamplesPerBlock(); 33 | value = Range(newSample, newSample); 34 | } else { 35 | value = value.getUnionWith(newSample); 36 | } 37 | } 38 | 39 | void setBufferSize(int newSize) 40 | { 41 | levels.removeRange(newSize, levels.size()); 42 | levels.insertMultiple(-1, {}, newSize - levels.size()); 43 | 44 | if (nextSample >= newSize) 45 | nextSample = 0; 46 | } 47 | 48 | BaseVisualiser& owner; 49 | Array> levels; 50 | Range value; 51 | std::atomic nextSample{ 0 }, subSample{ 0 }; 52 | 53 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ChannelInfo) 54 | }; 55 | 56 | //============================================================================== 57 | BaseVisualiser::BaseVisualiser(int initialNumChannels) 58 | : numSamples(1024) 59 | , inputSamplesPerBlock(256) 60 | , backgroundColour(Colours::black) 61 | , waveformColour(Colours::white) 62 | { 63 | setOpaque(true); 64 | setNumChannels(initialNumChannels); 65 | setRepaintRate(60); 66 | } 67 | 68 | BaseVisualiser::~BaseVisualiser() {} 69 | 70 | void 71 | BaseVisualiser::setNumChannels(int numChannels) 72 | { 73 | channels.clear(); 74 | 75 | for (int i = 0; i < numChannels; ++i) 76 | channels.add(new ChannelInfo(*this, numSamples)); 77 | } 78 | 79 | void 80 | BaseVisualiser::setBufferSize(int newNumSamples) 81 | { 82 | numSamples = newNumSamples; 83 | 84 | for (auto* c : channels) 85 | c->setBufferSize(newNumSamples); 86 | } 87 | 88 | void 89 | BaseVisualiser::clear() 90 | { 91 | for (auto* c : channels) 92 | c->clear(); 93 | } 94 | 95 | void 96 | BaseVisualiser::pushBuffer(const float* const* d, int numChannels, int num) 97 | { 98 | numChannels = jmin(numChannels, channels.size()); 99 | 100 | for (int i = 0; i < numChannels; ++i) 101 | channels.getUnchecked(i)->pushSamples(d[i], num); 102 | } 103 | 104 | void 105 | BaseVisualiser::pushBuffer(const AudioBuffer& buffer) 106 | { 107 | pushBuffer(buffer.getArrayOfReadPointers(), 108 | buffer.getNumChannels(), 109 | buffer.getNumSamples()); 110 | } 111 | 112 | void 113 | BaseVisualiser::pushBuffer(const AudioSourceChannelInfo& buffer) 114 | { 115 | auto numChannels = jmin(buffer.buffer->getNumChannels(), channels.size()); 116 | 117 | for (int i = 0; i < numChannels; ++i) 118 | channels.getUnchecked(i)->pushSamples( 119 | buffer.buffer->getReadPointer(i, buffer.startSample), buffer.numSamples); 120 | } 121 | 122 | void 123 | BaseVisualiser::pushSample(const float* d, int numChannels) 124 | { 125 | numChannels = jmin(numChannels, channels.size()); 126 | 127 | for (int i = 0; i < numChannels; ++i) 128 | channels.getUnchecked(i)->pushSample(d[i]); 129 | } 130 | 131 | void 132 | BaseVisualiser::setSamplesPerBlock(int newSamplesPerPixel) noexcept 133 | { 134 | inputSamplesPerBlock = newSamplesPerPixel; 135 | } 136 | 137 | void 138 | BaseVisualiser::setRepaintRate(int frequencyInHz) 139 | { 140 | startTimerHz(frequencyInHz); 141 | } 142 | 143 | void 144 | BaseVisualiser::timerCallback() 145 | { 146 | repaint(); 147 | } 148 | 149 | void 150 | BaseVisualiser::setColours(Colour bk, Colour wf, Colour fg) noexcept 151 | { 152 | backgroundColour = bk; 153 | foregroundColour = fg; 154 | waveformColour = wf; 155 | repaint(); 156 | } 157 | 158 | void 159 | BaseVisualiser::paint(Graphics& g) 160 | { 161 | g.fillAll(foregroundColour); 162 | g.setColour(backgroundColour); 163 | g.fillRoundedRectangle(getLocalBounds().toFloat(), cornerRadius); 164 | auto r = getLocalBounds().toFloat(); 165 | auto channelHeight = r.getHeight() / (float)channels.size(); 166 | 167 | g.setColour(waveformColour); 168 | 169 | for (auto* c : channels) 170 | paintChannel(g, 171 | r.removeFromTop(channelHeight), 172 | c->levels.begin(), 173 | c->levels.size(), 174 | c->nextSample); 175 | } 176 | 177 | void 178 | BaseVisualiser::getChannelAsPath(Path& path, 179 | const Range* levels, 180 | int numLevels, 181 | int nextSample) 182 | { 183 | path.preallocateSpace(4 * numLevels + 8); 184 | 185 | for (int i = 0; i < numLevels; ++i) { 186 | auto level = -(levels[(nextSample + i) % numLevels].getEnd()); 187 | 188 | if (i == 0) 189 | path.startNewSubPath(0.0f, level); 190 | else 191 | path.lineTo((float)i, level); 192 | } 193 | 194 | for (int i = numLevels; --i >= 0;) 195 | path.lineTo((float)i, -(levels[(nextSample + i) % numLevels].getStart())); 196 | 197 | path.closeSubPath(); 198 | } 199 | 200 | void 201 | BaseVisualiser::paintChannel(Graphics& g, 202 | Rectangle area, 203 | const Range* levels, 204 | int numLevels, 205 | int nextSample) 206 | { 207 | Path p; 208 | getChannelAsPath(p, levels, numLevels, nextSample); 209 | 210 | g.fillPath(p, 211 | AffineTransform::fromTargetPoints(0.0f, 212 | -1.0f, 213 | area.getX(), 214 | area.getY(), 215 | 0.0f, 216 | 1.0f, 217 | area.getX(), 218 | area.getBottom(), 219 | (float)numLevels, 220 | -1.0f, 221 | area.getRight(), 222 | area.getY())); 223 | } 224 | 225 | void 226 | BaseVisualiser::setCornerRadius(int cornerRadius) 227 | { 228 | this->cornerRadius = cornerRadius; 229 | } -------------------------------------------------------------------------------- /Source/CustomRotarySlider.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CustomRotarySlider.h" 4 | #include "PluginEditor.h" 5 | 6 | void 7 | CustomRotarySlider::mouseDown(const MouseEvent& e) 8 | { 9 | 10 | ModifierKeys modifiers = ModifierKeys::getCurrentModifiersRealtime(); 11 | 12 | if (modifiers.isShiftDown()) 13 | this->setMouseDragSensitivity(4000); 14 | else 15 | this->setMouseDragSensitivity(200); 16 | 17 | if (modifiers.isRightButtonDown()) { 18 | auto* parent = this->getParentComponent(); 19 | auto* editor = dynamic_cast(parent); 20 | auto* hostContext = editor->getHostContext(); 21 | if (hostContext == nullptr) 22 | return; 23 | auto contextMenu = hostContext->getContextMenuForParameter(param); 24 | if (contextMenu == nullptr) 25 | return; 26 | auto position = editor->getMouseXYRelative(); 27 | contextMenu->showNativeMenu(position); 28 | } else if (modifiers.isCtrlDown() || modifiers.isCommandDown() || 29 | modifiers.isMiddleButtonDown()) { 30 | auto* parent = getParentComponent(); 31 | auto* editor = dynamic_cast(parent); 32 | auto& valueEditor = editor->getValueEditor(); 33 | valueEditor.setVisible(true); 34 | valueEditor.setSlider(this); 35 | } else { 36 | Slider::mouseDown(e); // to the usual thing .... drag the slider 37 | } 38 | } 39 | 40 | void 41 | CustomRotarySlider::paint(juce::Graphics& g) 42 | { 43 | auto startAngleRadian = degreesToRadians(180.0f + 45.0f); 44 | auto endAngleRadian = 45 | degreesToRadians(180.0f - 45.0f) + MathConstants::twoPi; 46 | auto range = getRange(); 47 | auto sliderBounds = getSliderBounds(); 48 | 49 | g.setColour(Colours::yellow); 50 | // g.drawRect(sliderBounds); 51 | 52 | getLookAndFeel().drawRotarySlider( 53 | g, 54 | sliderBounds.getX(), 55 | sliderBounds.getY(), 56 | sliderBounds.getWidth(), 57 | sliderBounds.getHeight(), 58 | jmap(getValue(), range.getStart(), range.getEnd(), 0.0, 1.0), 59 | startAngleRadian, 60 | endAngleRadian, 61 | *this); 62 | } 63 | 64 | Rectangle 65 | CustomRotarySlider::getSliderBounds() const 66 | { 67 | return getLocalBounds(); 68 | } 69 | 70 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 71 | // Tooltips 72 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 73 | String 74 | CustomRotarySlider::getTooltipString() 75 | { 76 | int selectedOption = (int)getValue(); 77 | if (getName() == "Distortion") { 78 | switch ((int)selectedOption) { 79 | case Hardclip: 80 | return ("Distortion Type : Hard Clip"); 81 | break; 82 | case Softclip: 83 | return ("Distortion Type : Soft Clip"); 84 | break; 85 | case Saturate: 86 | return ("Distortion Type : Saturate"); 87 | break; 88 | case Atan: 89 | return ("Distortion Type : Atan"); 90 | break; 91 | case Crunch: 92 | return ("Distortion Type : Crunch"); 93 | break; 94 | case Bitcrush: 95 | return ("Distortion Type : Bitcrush"); 96 | break; 97 | case Extreme: 98 | return ("Distortion Type : Extreme"); 99 | break; 100 | case Scream: 101 | return ("Distortion Type : Scream"); 102 | break; 103 | case Sine: 104 | return ("Distortion Type : Sine"); 105 | break; 106 | case Cosine: 107 | return ("Distortion Type : Cosine"); 108 | break; 109 | case Harmonize: 110 | return ("Distortion Type : Harmonize"); 111 | break; 112 | case Weird: 113 | return ("Distortion Type : Weird"); 114 | break; 115 | } 116 | } else if (getName() == "Slope") { 117 | if (selectedOption >= 8) 118 | return "Slope : Peak Only"; 119 | int slope = (selectedOption + 1) * 12; 120 | String str; 121 | str << "Slope : "; 122 | str << slope; 123 | str << " db/oct"; 124 | return (str); 125 | } else if (getName() == "Symmetry") { 126 | auto value = round(getValue() * 100); 127 | String str; 128 | str << "Symmetry : "; 129 | if (value == 0) { 130 | str << "Centered"; 131 | } else { 132 | str << value; 133 | str << "%"; 134 | } 135 | return str; 136 | } else if (getName() == "Analyser Type") { 137 | AnalyserType analyserType = static_cast(selectedOption); 138 | String str = getAnalyserName(analyserType); 139 | return "Analyser Type : " + str; 140 | } else if (getName() == "Lowpass" || getName() == "Highpass" || 141 | getName() == "Peak") { 142 | String str; 143 | str << (round(getValue() * 100)) / 100; 144 | return (String)getName() + " : " + str + " " + (String)getTextValueSuffix(); 145 | } else if (getName() == "Peak Resonance") { 146 | String str; 147 | str << (round(getValue() * 100)) / 100; 148 | return "Resonance : " + str + " " + (String)getTextValueSuffix(); 149 | } else if (getName() == "Dual Peak Resonance") { 150 | String str; 151 | str << (round(getValue() * 100)) / 100; 152 | return "Resonance : " + str + " " + (String)getTextValueSuffix(); 153 | } else if (getName() == "Drive") { 154 | String str; 155 | str << round((getValue() - 1) * 10); 156 | return "Drive : " + str + "%"; 157 | } else if (getName() == "Girth") { 158 | int value = round(getValue() * 100); 159 | if (value >= 0) { 160 | String str; 161 | str << value; 162 | str << "%"; 163 | return (String)getName() + " Stereo : " + str + " " + 164 | (String)getTextValueSuffix(); 165 | } else { 166 | String str; 167 | str << -value; 168 | str << "%"; 169 | return (String)getName() + " Mono : " + str + " " + 170 | (String)getTextValueSuffix(); 171 | } 172 | } else { 173 | String str; 174 | str << (round(getValue() * 100)) / 100; 175 | return (String)getName() + " : " + str + "" + (String)getTextValueSuffix(); 176 | } 177 | return ""; 178 | } 179 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 180 | // Analyser Name 181 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 182 | String 183 | CustomRotarySlider::getAnalyserName(AnalyserType analyserType) 184 | { 185 | switch (analyserType) { 186 | case AnalyserType::Automatic: { 187 | return "Automatic"; 188 | break; 189 | } 190 | case AnalyserType::Options: { 191 | return "Options"; 192 | break; 193 | } 194 | case AnalyserType::Response: { 195 | return "Filter Response"; 196 | break; 197 | } 198 | case AnalyserType::Shapercurve: { 199 | return "Shapercurve"; 200 | break; 201 | } 202 | case AnalyserType::Waveform: { 203 | return "Waveform"; 204 | break; 205 | } 206 | } 207 | return "Unknown Analyser Type"; 208 | } 209 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Builds/ 2 | Installer/Mac/build 3 | Installer/Windows/Output 4 | *.DS_Store 5 | 6 | # Arch Linux related folders and files 7 | pkg/ 8 | src/ 9 | *.pkg.tar.xz 10 | 11 | 12 | # User-specific files 13 | *.rsuser 14 | *.suo 15 | *.user 16 | *.userosscache 17 | *.sln.docstates 18 | 19 | # User-specific files (MonoDevelop/Xamarin Studio) 20 | *.userprefs 21 | 22 | # Build results 23 | [Dd]ebug/ 24 | [Dd]ebugPublic/ 25 | [Rr]elease/ 26 | [Rr]eleases/ 27 | x64/ 28 | x86/ 29 | [Aa][Rr][Mm]/ 30 | [Aa][Rr][Mm]64/ 31 | bld/ 32 | [Bb]in/ 33 | [Oo]bj/ 34 | [Ll]og/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUNIT 49 | *.VisualState.xml 50 | TestResult.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # StyleCop 66 | StyleCopReport.xml 67 | 68 | # Files built by Visual Studio 69 | *_i.c 70 | *_p.c 71 | *_h.h 72 | *.ilk 73 | *.meta 74 | *.obj 75 | *.iobj 76 | *.pch 77 | *.pdb 78 | *.ipdb 79 | *.pgc 80 | *.pgd 81 | *.rsp 82 | *.sbr 83 | *.tlb 84 | *.tli 85 | *.tlh 86 | *.tmp 87 | *.tmp_proj 88 | *_wpftmp.csproj 89 | *.log 90 | *.vspscc 91 | *.vssscc 92 | .builds 93 | *.pidb 94 | *.svclog 95 | *.scc 96 | 97 | # Chutzpah Test files 98 | _Chutzpah* 99 | 100 | # Visual C++ cache files 101 | ipch/ 102 | *.aps 103 | *.ncb 104 | *.opendb 105 | *.opensdf 106 | *.sdf 107 | *.cachefile 108 | *.VC.db 109 | *.VC.VC.opendb 110 | 111 | # Visual Studio profiler 112 | *.psess 113 | *.vsp 114 | *.vspx 115 | *.sap 116 | 117 | # Visual Studio Trace Files 118 | *.e2e 119 | 120 | # TFS 2012 Local Workspace 121 | $tf/ 122 | 123 | # Guidance Automation Toolkit 124 | *.gpState 125 | 126 | # ReSharper is a .NET coding add-in 127 | _ReSharper*/ 128 | *.[Rr]e[Ss]harper 129 | *.DotSettings.user 130 | 131 | # JustCode is a .NET coding add-in 132 | .JustCode 133 | 134 | # TeamCity is a build add-in 135 | _TeamCity* 136 | 137 | # DotCover is a Code Coverage Tool 138 | *.dotCover 139 | 140 | # AxoCover is a Code Coverage Tool 141 | .axoCover/* 142 | !.axoCover/settings.json 143 | 144 | # Visual Studio code coverage results 145 | *.coverage 146 | *.coveragexml 147 | 148 | # NCrunch 149 | _NCrunch_* 150 | .*crunch*.local.xml 151 | nCrunchTemp_* 152 | 153 | # MightyMoose 154 | *.mm.* 155 | AutoTest.Net/ 156 | 157 | # Web workbench (sass) 158 | .sass-cache/ 159 | 160 | # Installshield output folder 161 | [Ee]xpress/ 162 | 163 | # DocProject is a documentation generator add-in 164 | DocProject/buildhelp/ 165 | DocProject/Help/*.HxT 166 | DocProject/Help/*.HxC 167 | DocProject/Help/*.hhc 168 | DocProject/Help/*.hhk 169 | DocProject/Help/*.hhp 170 | DocProject/Help/Html2 171 | DocProject/Help/html 172 | 173 | # Click-Once directory 174 | publish/ 175 | 176 | # Publish Web Output 177 | *.[Pp]ublish.xml 178 | *.azurePubxml 179 | # Note: Comment the next line if you want to checkin your web deploy settings, 180 | # but database connection strings (with potential passwords) will be unencrypted 181 | *.pubxml 182 | *.publishproj 183 | 184 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 185 | # checkin your Azure Web App publish settings, but sensitive information contained 186 | # in these scripts will be unencrypted 187 | PublishScripts/ 188 | 189 | # NuGet Packages 190 | *.nupkg 191 | # The packages folder can be ignored because of Package Restore 192 | **/[Pp]ackages/* 193 | # except build/, which is used as an MSBuild target. 194 | !**/[Pp]ackages/build/ 195 | # Uncomment if necessary however generally it will be regenerated when needed 196 | #!**/[Pp]ackages/repositories.config 197 | # NuGet v3's project.json files produces more ignorable files 198 | *.nuget.props 199 | *.nuget.targets 200 | 201 | # Microsoft Azure Build Output 202 | csx/ 203 | *.build.csdef 204 | 205 | # Microsoft Azure Emulator 206 | ecf/ 207 | rcf/ 208 | 209 | # Windows Store app package directories and files 210 | AppPackages/ 211 | BundleArtifacts/ 212 | Package.StoreAssociation.xml 213 | _pkginfo.txt 214 | *.appx 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- Backup*.rdl 265 | 266 | # Microsoft Fakes 267 | FakesAssemblies/ 268 | 269 | # GhostDoc plugin setting file 270 | *.GhostDoc.xml 271 | 272 | # Node.js Tools for Visual Studio 273 | .ntvs_analysis.dat 274 | node_modules/ 275 | 276 | # Visual Studio 6 build log 277 | *.plg 278 | 279 | # Visual Studio 6 workspace options file 280 | *.opt 281 | 282 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 283 | *.vbw 284 | 285 | # Visual Studio LightSwitch build output 286 | **/*.HTMLClient/GeneratedArtifacts 287 | **/*.DesktopClient/GeneratedArtifacts 288 | **/*.DesktopClient/ModelManifest.xml 289 | **/*.Server/GeneratedArtifacts 290 | **/*.Server/ModelManifest.xml 291 | _Pvt_Extensions 292 | 293 | # Paket dependency manager 294 | .paket/paket.exe 295 | paket-files/ 296 | 297 | # FAKE - F# Make 298 | .fake/ 299 | 300 | # JetBrains Rider 301 | .idea/ 302 | *.sln.iml 303 | 304 | # CodeRush personal settings 305 | .cr/personal 306 | 307 | # Python Tools for Visual Studio (PTVS) 308 | __pycache__/ 309 | *.pyc 310 | 311 | # Cake - Uncomment if you are using it 312 | # tools/** 313 | # !tools/packages.config 314 | 315 | # Tabs Studio 316 | *.tss 317 | 318 | # Telerik's JustMock configuration file 319 | *.jmconfig 320 | 321 | # BizTalk build output 322 | *.btp.cs 323 | *.btm.cs 324 | *.odx.cs 325 | *.xsd.cs 326 | 327 | # OpenCover UI analysis results 328 | OpenCover/ 329 | 330 | # Azure Stream Analytics local run output 331 | ASALocalRun/ 332 | 333 | # MSBuild Binary and Structured Log 334 | *.binlog 335 | 336 | # NVidia Nsight GPU debugger configuration file 337 | *.nvuser 338 | 339 | # MFractors (Xamarin productivity tool) working folder 340 | .mfractor/ 341 | 342 | # Local History for Visual Studio 343 | .localhistory/ 344 | 345 | # BeatPulse healthcheck temp database 346 | healthchecksdb 347 | -------------------------------------------------------------------------------- /Source/ResponseCurveComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "ResponseCurveComponent.h" 2 | 3 | ResponseCurveComponent::ResponseCurveComponent(PlasmaAudioProcessor& p) 4 | : audioProcessor(p) 5 | { 6 | // Listen to parameter changes 7 | const auto& params = audioProcessor.getParameters(); 8 | for (auto param : params) { 9 | param->addListener(this); 10 | } 11 | startTimer(60); 12 | } 13 | 14 | ResponseCurveComponent::~ResponseCurveComponent() 15 | { 16 | const auto& params = audioProcessor.getParameters(); 17 | for (auto param : params) { 18 | param->removeListener(this); 19 | } 20 | } 21 | 22 | void 23 | ResponseCurveComponent::parameterValueChanged(int parameterIndex, 24 | float newValue) 25 | { 26 | parametersChanged.set(true); 27 | } 28 | 29 | void 30 | ResponseCurveComponent::timerCallback() 31 | { 32 | if (parametersChanged.compareAndSetBool(false, true)) { 33 | update(); 34 | } 35 | } 36 | 37 | void 38 | ResponseCurveComponent::update() 39 | { 40 | // Update Monochain 41 | auto chainSettings = getChainSettings(audioProcessor.apvts); 42 | 43 | // Coefficients 44 | auto highPassCoefficients = 45 | makeHighPassFilter(chainSettings, audioProcessor.getSampleRate()); 46 | auto highPassResonanceCoefficients = 47 | makeHighPassResonance(chainSettings, audioProcessor.getSampleRate()); 48 | auto peakCoefficients = 49 | makePeakFilter(chainSettings, audioProcessor.getSampleRate(), 0.0); 50 | auto lowPassResonanceCoefficients = 51 | makeLowPassResonance(chainSettings, audioProcessor.getSampleRate()); 52 | auto lowPassCoefficients = 53 | makeLowPassFilter(chainSettings, audioProcessor.getSampleRate()); 54 | 55 | // Dual Peak 56 | auto dualPeakWidth = chainSettings.dualPeakWidth; 57 | auto dualPeakFreq = chainSettings.dualPeakFreq; 58 | 59 | auto logFreq = juce::mapFromLog10(dualPeakFreq, 20.0f, 20000.0f); 60 | auto width = dualPeakWidth / 500.0f; 61 | 62 | auto logFreqA = logFreq - width; 63 | auto logFreqB = logFreq + width; 64 | 65 | auto freqA = juce::mapToLog10(logFreqA, 20.0f, 20000.0f); 66 | auto freqB = juce::mapToLog10(logFreqB, 20.0f, 20000.0f); 67 | 68 | auto offsetA = freqA - dualPeakFreq; 69 | auto offsetB = freqB - dualPeakFreq; 70 | 71 | auto dualPeakACoefficients = 72 | makeDualPeakFilter(chainSettings, audioProcessor.getSampleRate(), offsetA); 73 | auto dualPeakBCoefficients = 74 | makeDualPeakFilter(chainSettings, audioProcessor.getSampleRate(), offsetB); 75 | 76 | // Updates 77 | updatePassFilter(monoChain.get(), 78 | highPassCoefficients, 79 | chainSettings.highPassSlope); 80 | updateCoefficients( 81 | monoChain.get().coefficients, 82 | highPassResonanceCoefficients); 83 | updateCoefficients(monoChain.get().coefficients, 84 | peakCoefficients); 85 | updateCoefficients(monoChain.get().coefficients, 86 | dualPeakACoefficients); 87 | updateCoefficients(monoChain.get().coefficients, 88 | dualPeakBCoefficients); 89 | updateCoefficients( 90 | monoChain.get().coefficients, 91 | lowPassResonanceCoefficients); 92 | updatePassFilter(monoChain.get(), 93 | lowPassCoefficients, 94 | chainSettings.lowPassSlope); 95 | 96 | // Repaint 97 | repaint(); 98 | } 99 | 100 | void 101 | ResponseCurveComponent::paint(juce::Graphics& g) 102 | { 103 | using namespace juce; 104 | 105 | // bounds 106 | auto bounds = getBounds(); 107 | auto lineSize = bounds.getHeight() / 100; 108 | lineSize = (lineSize < 1.0f) ? 1.0f : lineSize; 109 | 110 | // Screen 111 | auto x = padding; 112 | auto y = padding; 113 | auto w = bounds.getWidth() - padding; 114 | auto h = bounds.getHeight() - padding; 115 | 116 | // g.setColour(Colours::black); 117 | // g.fillRect(x, y, w, h); 118 | auto& highpass = monoChain.get(); 119 | auto& highpassResonance = monoChain.get(); 120 | auto& peak = monoChain.get(); 121 | auto& dualPeakA = monoChain.get(); 122 | auto& dualPeakB = monoChain.get(); 123 | auto& lowpass = monoChain.get(); 124 | auto& lowpassResonance = monoChain.get(); 125 | 126 | auto sampleRate = audioProcessor.getSampleRate(); 127 | 128 | std::vector mags; 129 | mags.resize(w); 130 | for (int i = 0; i < w; ++i) { 131 | // Magnitude 132 | double mag = 1.f; 133 | auto freq = mapToLog10(double(i) / double(w), 20.0, 20000.0); 134 | 135 | // Highpass 136 | if (!highpass.isBypassed<0>()) 137 | mag *= highpass.get<0>().coefficients->getMagnitudeForFrequency( 138 | freq, sampleRate); 139 | if (!highpass.isBypassed<1>()) 140 | mag *= highpass.get<1>().coefficients->getMagnitudeForFrequency( 141 | freq, sampleRate); 142 | if (!highpass.isBypassed<2>()) 143 | mag *= highpass.get<2>().coefficients->getMagnitudeForFrequency( 144 | freq, sampleRate); 145 | if (!highpass.isBypassed<3>()) 146 | mag *= highpass.get<3>().coefficients->getMagnitudeForFrequency( 147 | freq, sampleRate); 148 | if (!highpass.isBypassed<4>()) 149 | mag *= highpass.get<4>().coefficients->getMagnitudeForFrequency( 150 | freq, sampleRate); 151 | if (!highpass.isBypassed<5>()) 152 | mag *= highpass.get<5>().coefficients->getMagnitudeForFrequency( 153 | freq, sampleRate); 154 | if (!highpass.isBypassed<6>()) 155 | mag *= highpass.get<6>().coefficients->getMagnitudeForFrequency( 156 | freq, sampleRate); 157 | if (!highpass.isBypassed<7>()) 158 | mag *= highpass.get<7>().coefficients->getMagnitudeForFrequency( 159 | freq, sampleRate); 160 | 161 | // Highpass Resonance 162 | if (!monoChain.isBypassed()) 163 | mag *= highpassResonance.coefficients->getMagnitudeForFrequency( 164 | freq, sampleRate); 165 | 166 | // Peak 167 | if (!monoChain.isBypassed()) 168 | mag *= peak.coefficients->getMagnitudeForFrequency(freq, sampleRate); 169 | 170 | // Dual Peak A 171 | if (!monoChain.isBypassed()) 172 | mag *= dualPeakA.coefficients->getMagnitudeForFrequency(freq, sampleRate); 173 | 174 | // Dual Peak B 175 | if (!monoChain.isBypassed()) 176 | mag *= dualPeakB.coefficients->getMagnitudeForFrequency(freq, sampleRate); 177 | 178 | // Lowpass 179 | if (!lowpass.isBypassed<0>()) 180 | mag *= lowpass.get<0>().coefficients->getMagnitudeForFrequency( 181 | freq, sampleRate); 182 | if (!lowpass.isBypassed<1>()) 183 | mag *= lowpass.get<1>().coefficients->getMagnitudeForFrequency( 184 | freq, sampleRate); 185 | if (!lowpass.isBypassed<2>()) 186 | mag *= lowpass.get<2>().coefficients->getMagnitudeForFrequency( 187 | freq, sampleRate); 188 | if (!lowpass.isBypassed<3>()) 189 | mag *= lowpass.get<3>().coefficients->getMagnitudeForFrequency( 190 | freq, sampleRate); 191 | if (!lowpass.isBypassed<4>()) 192 | mag *= lowpass.get<4>().coefficients->getMagnitudeForFrequency( 193 | freq, sampleRate); 194 | if (!lowpass.isBypassed<5>()) 195 | mag *= lowpass.get<5>().coefficients->getMagnitudeForFrequency( 196 | freq, sampleRate); 197 | if (!lowpass.isBypassed<6>()) 198 | mag *= lowpass.get<6>().coefficients->getMagnitudeForFrequency( 199 | freq, sampleRate); 200 | if (!lowpass.isBypassed<7>()) 201 | mag *= lowpass.get<7>().coefficients->getMagnitudeForFrequency( 202 | freq, sampleRate); 203 | 204 | // Lowpass Resonance 205 | if (!monoChain.isBypassed()) 206 | mag *= lowpassResonance.coefficients->getMagnitudeForFrequency( 207 | freq, sampleRate); 208 | 209 | // Write 210 | mags[i] = Decibels::gainToDecibels(mag); 211 | } 212 | 213 | Path responseCurve; 214 | const double outputMin = y + h; 215 | const double outputMax = y; 216 | auto map = [outputMin, outputMax](double input) { 217 | return jmap(input, -64.0, 64.0, outputMin, outputMax); 218 | }; 219 | 220 | responseCurve.startNewSubPath(x, map(mags.front())); 221 | for (size_t i = 1; i < mags.size(); ++i) { 222 | responseCurve.lineTo(x + i, map(mags[i])); 223 | } 224 | g.setColour(color); 225 | g.strokePath(responseCurve, PathStrokeType(lineSize)); 226 | } 227 | 228 | void 229 | ResponseCurveComponent::setPadding(float newPadding) 230 | { 231 | padding = newPadding; 232 | } 233 | 234 | void 235 | ResponseCurveComponent::setColor(Colour c) 236 | { 237 | color = c; 238 | } 239 | -------------------------------------------------------------------------------- /Source/PluginProcessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "./LUFSMeter/Ebu128LoudnessMeter.h" 3 | #include "PlasmaDistortionProcessor.h" 4 | #include "Version.h" 5 | #include "WaveformComponent.h" 6 | #include 7 | // Math 8 | const float pi = 3.14159265358979323846; 9 | 10 | // Enums 11 | enum ChainPositions 12 | { 13 | HighPass, 14 | HighPassResonance, 15 | Peak, 16 | DualPeakA, 17 | DualPeakB, 18 | LowPass, 19 | LowPassResonance, 20 | }; 21 | enum Slope 22 | { 23 | Slope_12, 24 | Slope_24, 25 | Slope_36, 26 | Slope_48, 27 | Slope_60, 28 | Slope_72, 29 | Slope_84, 30 | Slope_96, 31 | None 32 | }; 33 | enum AnalyserType 34 | { 35 | Automatic, 36 | Waveform, 37 | Response, 38 | Shapercurve, 39 | Options 40 | }; 41 | 42 | // Chain Settings 43 | struct ChainSettings 44 | { 45 | float drive{ 10.0f }, girth{ 0.0f }, bias{ 0.0f }, preGain{ 0.0f }; 46 | float lateDrive{ 0.0f }, lateBias{ 0.0f }, lateGirth{ 0.0f }, gain{ 0.0f }; 47 | float peakFreq{ 0 }, peakGain{ 0 }, peakQuality{ 1.0f }, peakStereo{ 0.0f }; 48 | float dualPeakFreq{ 0 }, dualPeakGain{ 0 }, dualPeakQuality{ 1.0f }, 49 | dualPeakWidth{ 300.0f }; 50 | float highPassFreq{ 20.0f }, lowPassFreq{ 20.0f }; 51 | float highPassResonanceQuality{ 1.0 }, highPassResonance{ 0.0 }; 52 | float lowPassResonanceQuality{ 1.0 }, lowPassResonance{ 0.0 }; 53 | float mix{ 100.0f }; 54 | Slope highPassSlope{ Slope::Slope_12 }, lowPassSlope{ Slope::Slope_12 }; 55 | AnalyserType analyserType{ AnalyserType::Response }; 56 | Distortion driveType{ Distortion::Hardclip }, 57 | lateDriveType{ Distortion::Hardclip }; 58 | }; 59 | ChainSettings 60 | getChainSettings(juce::AudioProcessorValueTreeState& apvts); 61 | 62 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 63 | // Filters 64 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 65 | 66 | // MonoChain 67 | using Filter = juce::dsp::IIR::Filter; 68 | using PassFilter = juce::dsp::ProcessorChain; 76 | using MonoChain = juce::dsp::ProcessorChain; // LowPass Resonance 83 | 84 | // Coefficients 85 | using Coefficients = Filter::CoefficientsPtr; 86 | void 87 | updateCoefficients(Coefficients& old, const Coefficients& replacements); 88 | 89 | Coefficients 90 | makePeakFilter(const ChainSettings& chainSettings, 91 | double sampleRate, 92 | float offset); 93 | Coefficients 94 | makeDualPeakFilter(const ChainSettings& chainSettings, 95 | double sampleRate, 96 | float offset); 97 | Coefficients 98 | makeHighPassResonance(const ChainSettings& chainSettings, double sampleRate); 99 | Coefficients 100 | makeLowPassResonance(const ChainSettings& chainSettings, double sampleRate); 101 | 102 | template 103 | void 104 | update(ChainType& chain, const CoefficientType& coefficients) 105 | { 106 | updateCoefficients(chain.template get().coefficients, 107 | coefficients[Index]); 108 | chain.template setBypassed(false); 109 | } 110 | template 111 | void 112 | updatePassFilter(ChainType& filter, 113 | const CoefficientType& filterCoefficients, 114 | const Slope& filterSlope) 115 | { 116 | filter.template setBypassed<0>(true); 117 | filter.template setBypassed<1>(true); 118 | filter.template setBypassed<2>(true); 119 | filter.template setBypassed<3>(true); 120 | filter.template setBypassed<4>(true); 121 | filter.template setBypassed<5>(true); 122 | filter.template setBypassed<6>(true); 123 | filter.template setBypassed<7>(true); 124 | 125 | switch (filterSlope) { 126 | case Slope_96: { 127 | update<7>(filter, filterCoefficients); 128 | } 129 | case Slope_84: { 130 | update<6>(filter, filterCoefficients); 131 | } 132 | case Slope_72: { 133 | update<5>(filter, filterCoefficients); 134 | } 135 | case Slope_60: { 136 | update<4>(filter, filterCoefficients); 137 | } 138 | case Slope_48: { 139 | update<3>(filter, filterCoefficients); 140 | } 141 | case Slope_36: { 142 | update<2>(filter, filterCoefficients); 143 | } 144 | case Slope_24: { 145 | update<1>(filter, filterCoefficients); 146 | } 147 | case Slope_12: { 148 | update<0>(filter, filterCoefficients); 149 | } 150 | case None: { 151 | break; 152 | } 153 | } 154 | } 155 | 156 | inline auto 157 | makeHighPassFilter(const ChainSettings& chainSettings, double sampleRate) 158 | { 159 | return juce::dsp::FilterDesign:: 160 | designIIRHighpassHighOrderButterworthMethod( 161 | chainSettings.highPassFreq, 162 | sampleRate, 163 | 2 * (chainSettings.highPassSlope + 1)); 164 | } 165 | inline auto 166 | makeLowPassFilter(const ChainSettings& chainSettings, double sampleRate) 167 | { 168 | return juce::dsp::FilterDesign:: 169 | designIIRLowpassHighOrderButterworthMethod( 170 | chainSettings.lowPassFreq, 171 | sampleRate, 172 | 2 * (chainSettings.lowPassSlope + 1)); 173 | } 174 | 175 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 176 | // AudioProcessor 177 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 178 | 179 | class PlasmaAudioProcessor : public juce::AudioProcessor 180 | { 181 | public: 182 | PlasmaAudioProcessor(); 183 | ~PlasmaAudioProcessor() override; 184 | void prepareToPlay(double sampleRate, int samplesPerBlock) override; 185 | void releaseResources() override; 186 | 187 | #ifndef JucePlugin_PreferredChannelConfigurations 188 | bool isBusesLayoutSupported(const BusesLayout& layouts) const override; 189 | #endif 190 | void processBlock(juce::AudioBuffer&, juce::MidiBuffer&) override; 191 | juce::AudioProcessorEditor* createEditor() override; 192 | bool hasEditor() const override; 193 | const juce::String getName() const override; 194 | bool acceptsMidi() const override; 195 | bool producesMidi() const override; 196 | bool isMidiEffect() const override; 197 | double getTailLengthSeconds() const override; 198 | int getNumPrograms() override; 199 | int getCurrentProgram() override; 200 | void setCurrentProgram(int index) override; 201 | const juce::String getProgramName(int index) override; 202 | void changeProgramName(int index, const juce::String& newName) override; 203 | void getStateInformation(juce::MemoryBlock& destData) override; 204 | void setStateInformation(const void* data, int sizeInBytes) override; 205 | 206 | //============================================================================== 207 | 208 | static juce::AudioProcessorValueTreeState::ParameterLayout 209 | createParameterLayout(); 210 | juce::AudioProcessorValueTreeState apvts{ *this, 211 | nullptr, 212 | "Parameters", 213 | createParameterLayout() }; 214 | 215 | WaveformComponent waveformComponent; 216 | VersionManager versionManager; 217 | 218 | private: 219 | // Clean Buffer 220 | AudioSampleBuffer cleanBuffer; 221 | 222 | // LoudnessMeter 223 | float rmsLevelLeftIn{ 0.0f }, rmsLevelRight{ 0.0f }; 224 | float rmsLevelLeftOut{ 0.0f }, rmsLevelRightOut{ 0.0f }; 225 | float peakLevelLeftIn{ 0.0f }, peakLevelRightIn{ 0.0f }; 226 | float peakLevelLeftOut{ 0.0f }, peakLevelRightOut{ 0.0f }; 227 | Ebu128LoudnessMeter loudnessMeterIn; 228 | Ebu128LoudnessMeter loudnessMeterOut; 229 | float momentaryLoudnessIn{ 0.0f }, momentaryLoudnessOut{ 0.0f }; 230 | float integratedLoudnessIn{ 0.0f }, integratedLoudnessOut{ 0.0f }; 231 | 232 | // Filters 233 | MonoChain leftChain, rightChain; 234 | void updatePeakFilter(const ChainSettings& chainSettings); 235 | void updateDualPeakFilter(const ChainSettings& chainSettings); 236 | void updateHighPassResonance(const ChainSettings& chainSettings); 237 | void updateLowPassResonance(const ChainSettings& chainSettings); 238 | void updateHighPass(const ChainSettings& chainSettings); 239 | void updateLowPass(const ChainSettings& chainSettings); 240 | void updateFilters(); 241 | 242 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 243 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PlasmaAudioProcessor); 244 | }; 245 | -------------------------------------------------------------------------------- /Source/PluginEditor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CustomLabel.h" 4 | #include "CustomRotarySlider.h" 5 | #include "CustomTextButton.h" 6 | #include "LoudnessMeterComponent.h" 7 | #include "PlasmaLabel.h" 8 | #include "PluginProcessor.h" 9 | #include "ResponseCurveComponent.h" 10 | #include "ShapercurveComponent.h" 11 | #include "ValueEditor.h" 12 | #include "Version.h" 13 | #include 14 | 15 | //============================================================================================= 16 | 17 | const juce::String PLASMA_VERSION = ProjectInfo::versionString; 18 | // 19 | 20 | const Colour backgroundColorFactory = Colour(40, 42, 54); 21 | const Colour foregroundColorFactory = Colour(68, 71, 90); 22 | const Colour accentColorFactory = Colour(80, 250, 123); 23 | 24 | //============================================================================================= 25 | 26 | class PlasmaAudioProcessorEditor 27 | : public AudioProcessorEditor 28 | , public MultiTimer 29 | , public Button::Listener 30 | , public Slider::Listener 31 | , public Label::Listener 32 | { 33 | public: 34 | PlasmaAudioProcessorEditor(PlasmaAudioProcessor&); 35 | ~PlasmaAudioProcessorEditor() override; 36 | 37 | void paint(juce::Graphics&) override; 38 | void resized() override; 39 | 40 | void timerCallback(int timerID) override; 41 | void buttonClicked(Button* button) override; 42 | void sliderValueChanged(Slider* slider) override; 43 | void sliderDragStarted(Slider* slider) override; 44 | void sliderDragEnded(Slider* slider) override; 45 | void labelTextChanged(Label* label) override; 46 | void editorHidden(Label* label, TextEditor& textEditor) override; 47 | 48 | // Colors 49 | Colour getBackgroundColor(); 50 | Colour getForegroundColor(); 51 | Colour getAccentColor(); 52 | Colour getFontColor(); 53 | Colour getOptionsFontColor(); 54 | 55 | void setBackgroundColor(Colour c); 56 | void setForegroundColor(Colour c); 57 | void setAccentColor(Colour c); 58 | void setFontColor(Colour c); 59 | void setOptionsFontColor(Colour c); 60 | void updateTextboxes(); 61 | ValueEditor& getValueEditor(); 62 | 63 | private: 64 | // Scaling 65 | CustomTextButton scaleUpButton, scaleDownButton, configButton, 66 | safeConfigButton, resetConfigButton, updateButton; 67 | 68 | // Audio Processor 69 | PlasmaAudioProcessor& audioProcessor; 70 | 71 | // Config 72 | ApplicationProperties applicationProperties; 73 | PropertiesFile::Options options; 74 | int scale = 100; 75 | bool showConfig = false; 76 | void configWindow(bool visibility); 77 | WaveformComponent* waveformComponent; 78 | AnalyserType autoAnalyserType; 79 | bool isAutoAnalyser; 80 | void setAnalyserType(AnalyserType analyser); 81 | AnalyserType lastAnalyserType = AnalyserType::Automatic; 82 | int cornerRadius = 5; 83 | int cornerRadiusFallback = 5; 84 | 85 | // Sliders 86 | CustomRotarySlider 87 | // Drive 88 | gainSlider, 89 | driveSlider, girthSlider, biasSlider, driveTypeSlider, 90 | // Highpass 91 | highPassFreqSlider, highPassResonanceSlider, highPassResonanceQualitySlider, 92 | highPassSlopeSlider, 93 | // Peak 94 | peakStereoSlider, peakFreqSlider, peakGainSlider, peakQualitySlider, 95 | // DualPeak 96 | dualPeakWidthSlider, dualPeakFreqSlider, dualPeakGainSlider, 97 | dualPeakQualitySlider, 98 | // Lowpass 99 | lowPassFreqSlider, lowPassResonanceSlider, lowPassResonanceQualitySlider, 100 | lowPassSlopeSlider, 101 | // lateDrive 102 | lateBiasSlider, lateDriveTypeSlider, lateGirthSlider, lateDriveSlider, 103 | preGainSlider, 104 | // Output 105 | mixSlider, analyserSlider; 106 | 107 | // Response Curve Component 108 | ResponseCurveComponent responseCurveComponent; 109 | ShapercurveComponent earlyShapercurveComponent; 110 | ShapercurveComponent lateShapercurveComponent; 111 | 112 | // Loudness Meter Components 113 | Gui::LoudnessMeterComponent loudnessMeterIn, loudnessMeterOut; 114 | 115 | // Value Editor 116 | ValueEditor valueEditor; 117 | 118 | // Attachments 119 | using APVTS = juce::AudioProcessorValueTreeState; 120 | using Attachment = APVTS::SliderAttachment; 121 | Attachment highPassFreqSliderAttachment, lowPassFreqSliderAttachment, 122 | biasSliderAttachment, lateBiasSliderAttachment, driveTypeSliderAttachment, 123 | lateDriveTypeSliderAttachment, highPassResonanceSliderAttachment, 124 | lowPassResonanceSliderAttachment, peakStereoSliderAttachment, 125 | peakFreqSliderAttachment, peakGainSliderAttachment, 126 | peakQualitySliderAttachment, dualPeakWidthSliderAttachment, 127 | dualPeakFreqSliderAttachment, dualPeakGainSliderAttachment, 128 | dualPeakQualitySliderAttachment, highPassResonanceQualitySliderAttachment, 129 | lowPassResonanceQualitySliderAttachment, highPassSlopeSliderAttachment, 130 | lowPassSlopeSliderAttachment, preGainSliderAttachment, 131 | driveSliderAttachment, girthSliderAttachment, lateGirthSliderAttachment, 132 | lateDriveSliderAttachment, gainSliderAttachment, analyserSliderAttachment, 133 | mixSliderAttachment; 134 | 135 | // Layout 136 | float sc(float val); 137 | Rectangle headerArea(); 138 | Rectangle monitorArea(); 139 | Rectangle inArea(); 140 | Rectangle outArea(); 141 | Rectangle earlyArea(); 142 | Rectangle highpassArea(); 143 | Rectangle peakArea(); 144 | Rectangle dualPeakArea(); 145 | Rectangle lowpassArea(); 146 | Rectangle lateArea(); 147 | int boxWidth = 135; 148 | int boxHeight = 550; 149 | 150 | // Fontsizes 151 | float fs_mainLabel(); 152 | float fs_titelLabel(); 153 | float padding = 10.0f; 154 | float knobLabelHeight = 0.80f; 155 | 156 | // Labels 157 | PlasmaLabel plasmaLabel; 158 | CustomLabel tooltipLabel, 159 | // Drive 160 | gainLabel, driveLabel, girthLabel, biasLabel, driveTypeLabel, 161 | // Highpass 162 | highPassFreqLabel, highPassResonanceLabel, highPassResonanceQualityLabel, 163 | highPassSlopeLabel, 164 | // Peak 165 | peakStereoLabel, peakFreqLabel, peakGainLabel, peakQualityLabel, 166 | // Dual Peak 167 | dualPeakWidthLabel, dualPeakFreqLabel, dualPeakGainLabel, 168 | dualPeakQualityLabel, 169 | // Lowpass 170 | lowPassFreqLabel, lowPassResonanceLabel, lowPassResonanceQualityLabel, 171 | lowPassSlopeLabel, 172 | // lateDrive 173 | lateBiasLabel, lateDriveTypeLabel, lateGirthLabel, lateDriveLabel, 174 | preGainLabel, mixLabel, analyserLabel, 175 | // Titels 176 | inLabel, outLabel, earlyLabel, highpassLabel, peakLabel, dualPeakLabel, 177 | lowpassLabel, lateLabel, 178 | // Options 179 | optionsLabel; 180 | 181 | // Options Labels 182 | CustomLabel configOscilloscopeBufferSizeLabel, 183 | configOscilloscopeSamplesPerBlockLabel, configBackgroundColorLabel, 184 | configForegroundColorLabel, configAccentColorLabel, configCornerRadiusLabel; 185 | CustomTextbox configOscilloscopeBufferSizeTextbox, 186 | configOscilloscopeSamplesPerBlockTextbox, configBackgroundColorTextbox, 187 | configForegroundColorTextbox, configAccentColorTextbox, 188 | configCornerRadiusTextbox; 189 | 190 | // Color 191 | bool testColorString(String string); 192 | Colour backgroundColor = backgroundColorFactory; 193 | Colour foregroundColor = foregroundColorFactory; 194 | Colour accentColor = accentColorFactory; 195 | Colour fontColor = Colour(255, 255, 255); 196 | Colour optionsFontColor = Colour(255, 255, 255); 197 | Colour parseColourFromString(String str); 198 | void loadBackgroundColor(PropertiesFile* commonSettings); 199 | void loadForegroundColor(PropertiesFile* commonSettings); 200 | void loadAccentColor(PropertiesFile* commonSettings); 201 | void saveBackgroundColor(PropertiesFile* commonSettings); 202 | void saveForegroundColor(PropertiesFile* commonSettings); 203 | void saveAccentColor(PropertiesFile* commonSettings); 204 | Colour backgroundColorFallback = backgroundColorFactory; 205 | Colour foregroundColorFallback = foregroundColorFactory; 206 | Colour accentColorFallback = accentColorFactory; 207 | 208 | // Oscilloscope Settings 209 | int oscilloscopeBufferSize = 1024; 210 | int oscilloscopeSamplesPerBlock = 4; 211 | int oscilloscopeBufferSizeFallback = 1024; 212 | int oscilloscopeSamplesPerBlockFallback = 4; 213 | void loadOscilloscopeBufferSize(PropertiesFile* commonSettings); 214 | void loadOscilloscopeSamplesPerBlock(PropertiesFile* commonSettings); 215 | void loadCornerRadius(PropertiesFile* commonSettings); 216 | void saveOscilloscopeBufferSize(PropertiesFile* commonSettings); 217 | void saveOscilloscopeSamplesPerBlock(PropertiesFile* commonSettings); 218 | void saveCornerRadius(PropertiesFile* commonSettings); 219 | void setOscilloscopeBufferSize(int oscilloscopeBufferSize); 220 | void setOscilloscopeSamplesPerBlock(int oscilloscopeSamplesPerBlock); 221 | void setCornerRadius(int cornerRadius); 222 | 223 | // Component Vectors 224 | std::vector getLabels(); 225 | std::vector getOptionsLabels(); 226 | std::vector getSliders(); 227 | std::vector getComps(); 228 | std::vector getButtons(); 229 | std::vector getOptionsButtons(); 230 | std::vector getTextboxes(); 231 | 232 | OpenGLContext openGLContext; 233 | VersionManager& versionManager; 234 | // End 235 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PlasmaAudioProcessorEditor); 236 | }; 237 | -------------------------------------------------------------------------------- /Source/CustomLookAndFeel.cpp: -------------------------------------------------------------------------------- 1 | #include "CustomLookAndFeel.h" 2 | #include "PluginEditor.h" 3 | 4 | void 5 | CustomLookAndFeel::drawLabel(Graphics& g, Label& label) 6 | { 7 | g.fillAll(label.findColour(Label::backgroundColourId)); 8 | 9 | if (!label.isBeingEdited()) { 10 | auto alpha = label.isEnabled() ? 1.0f : 0.5f; 11 | const Font font(getLabelFont(label)); 12 | 13 | g.setColour( 14 | label.findColour(Label::textColourId).withMultipliedAlpha(alpha)); 15 | g.setFont(font); 16 | 17 | auto textArea = 18 | getLabelBorderSize(label).subtractedFrom(label.getLocalBounds()); 19 | 20 | g.drawFittedText( 21 | label.getText(), 22 | textArea, 23 | label.getJustificationType(), 24 | jmax(1, (int)((float)textArea.getHeight() / font.getHeight())), 25 | label.getMinimumHorizontalScale()); 26 | g.setColour( 27 | label.findColour(Label::outlineColourId).withMultipliedAlpha(alpha)); 28 | } 29 | 30 | // Border for textbox 31 | if (label.isEditable()) { 32 | g.setColour(label.findColour(Label::textColourId)); 33 | g.drawRect(label.getLocalBounds()); 34 | } 35 | } 36 | 37 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 38 | // Buttons 39 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 40 | void 41 | CustomLookAndFeel::drawButtonBackground(Graphics& g, 42 | Button& button, 43 | const Colour& backgroundColour, 44 | bool isMouseOverButton, 45 | bool isButtonDown) 46 | { 47 | auto text = button.getButtonText(); 48 | auto bounds = button.getBounds(); 49 | Rectangle area(0, 0, bounds.getWidth(), bounds.getHeight()); 50 | auto center = area.getCentre(); 51 | float lineSize = bounds.getHeight() / 15.0; 52 | 53 | // Select Color 54 | g.setColour(button.findColour(TextButton::ColourIds::textColourOnId)); 55 | 56 | // Draw Foreground 57 | float iconSize = 2.5 * lineSize; 58 | float fontSize = 4.4 * iconSize; 59 | if (operatingSystemType != juce::SystemStats::OperatingSystemType::Windows) { 60 | fontSize = 4.0 * iconSize; 61 | } 62 | if (text == "O") { 63 | g.setFont(getCustomFont().withHeight(fontSize)); 64 | g.drawText("Config", area, Justification::centred, false); 65 | } 66 | if (text == "U") { 67 | g.setFont(getCustomFont().withHeight(fontSize)); 68 | g.drawText("Update available", area, Justification::centred, false); 69 | } else if (text == "S") { 70 | g.setFont(getCustomFont().withHeight(fontSize)); 71 | g.drawText("Save", area, Justification::centred, false); 72 | } else if (text == "R") { 73 | g.setFont(getCustomFont().withHeight(fontSize)); 74 | g.drawText("Reset", area, Justification::centred, false); 75 | } else if (text == "+") { 76 | Point p1(center.x, center.y - iconSize); 77 | Point p2(center.x, center.y + iconSize); 78 | Point p3(center.x + iconSize, center.y); 79 | Point p4(center.x - iconSize, center.y); 80 | Line l1(p1, p2); 81 | Line l2(p3, p4); 82 | g.drawLine(l1, lineSize); 83 | g.drawLine(l2, lineSize); 84 | } else if (text == "-") { 85 | Point p3(center.x + iconSize, center.y); 86 | Point p4(center.x - iconSize, center.y); 87 | Line l2(p3, p4); 88 | g.drawLine(l2, lineSize); 89 | } 90 | 91 | if (!button.isMouseButtonDown()) { 92 | g.drawRoundedRectangle( 93 | area.reduced(lineSize * 1.5), 4 * lineSize, lineSize); 94 | } else { 95 | g.drawRoundedRectangle(area.reduced(lineSize), 4 * lineSize, lineSize); 96 | } 97 | 98 | // Outline 99 | // 100 | } 101 | 102 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 103 | // Slider 104 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 105 | void 106 | CustomLookAndFeel::drawRotarySlider(juce::Graphics& g, 107 | int x, 108 | int y, 109 | int width, 110 | int height, 111 | float sliderPosProportional, 112 | float rotaryStartAngle, 113 | float rotaryEndAngle, 114 | juce::Slider& slider) 115 | { 116 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 117 | // Check Type and Generate String 118 | 119 | // Default Skewfactor 120 | auto skewFactor = 0.5; 121 | 122 | // Selector Parameters 123 | bool isSelector = false; 124 | int numOptions = 4; 125 | int selectedOption = 0; 126 | 127 | // Symmertry 128 | bool isCentered = false; 129 | bool isInverted = false; 130 | auto range = rotaryEndAngle - rotaryStartAngle; 131 | auto center = range / 2; 132 | 133 | // Style Setup 134 | if (slider.getName() == "Distortion") { 135 | isSelector = true; 136 | numOptions = 12; 137 | selectedOption = (int)slider.getValue(); 138 | } else if (slider.getName() == "Slope") { 139 | isSelector = true; 140 | numOptions = 9; 141 | selectedOption = (int)slider.getValue(); 142 | } else if (slider.getName() == "Symmetry") { 143 | isCentered = true; 144 | // auto value = round(slider.getValue() * 100); 145 | } else if (slider.getName() == "Analyser Type") { 146 | isSelector = true; 147 | numOptions = 5; 148 | selectedOption = (int)slider.getValue(); 149 | } else if (slider.getName() == "Lowpass" || slider.getName() == "Highpass" || 150 | slider.getName() == "Peak" || slider.getName() == "Dual Peak") { 151 | skewFactor = 0.82; 152 | if (slider.getName() == "Lowpass") 153 | isInverted = true; 154 | } else if (slider.getName() == "Peak Resonance") { 155 | isCentered = true; 156 | } else if (slider.getName() == "Lowpass Resonance") { 157 | isCentered = true; 158 | } else if (slider.getName() == "Highpass Resonance") { 159 | isCentered = true; 160 | } else if (slider.getName() == "Dual Peak Resonance") { 161 | isCentered = true; 162 | } else if (slider.getName() == "Girth") { 163 | String str; 164 | isCentered = true; 165 | } else if (slider.getName() == "Dual Peak Resonance") { 166 | } 167 | 168 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 169 | // Drawing 170 | 171 | // Calculations 172 | NormalisableRange targetRange{ 0, 1 }; 173 | targetRange.setSkewForCentre(skewFactor); 174 | auto normalisedPos = targetRange.convertFrom0to1(sliderPosProportional); 175 | auto bounds = 176 | Rectangle(x, y, width, height).toFloat().reduced(width / 12); 177 | auto radius = jmin(bounds.getWidth(), bounds.getHeight()) / 2.3f; 178 | auto toAngle = 179 | rotaryStartAngle + normalisedPos * (rotaryEndAngle - rotaryStartAngle); 180 | auto lineW = jmin((float)width / 12, radius * 0.5f); 181 | auto arcRadius = radius - lineW * 0.5f; 182 | auto thumbWidth = lineW * 2.0f; 183 | auto lineSize = bounds.getHeight() / 40; 184 | Colour fill = slider.findColour(Slider::rotarySliderFillColourId); 185 | Colour color = slider.findColour(Slider::ColourIds::thumbColourId); 186 | Colour backgroundColor = 187 | slider.findColour(Slider::ColourIds::backgroundColourId); 188 | // Draw Rail or Selector 189 | if (!isSelector) { 190 | // Draw Dark Rail 191 | Path backgroundArc; 192 | backgroundArc.addCentredArc(bounds.getCentreX(), 193 | bounds.getCentreY(), 194 | arcRadius, 195 | arcRadius, 196 | 0.0f, 197 | rotaryStartAngle, 198 | rotaryEndAngle, 199 | true); 200 | // juce::Colour halfFill(fill.getHue(), fill.getSaturation(), 201 | // fill.getLightness()/3.0f, fill.getAlpha()); 202 | g.setColour(backgroundColor); 203 | g.strokePath( 204 | backgroundArc, 205 | PathStrokeType(lineW, PathStrokeType::curved, PathStrokeType::rounded)); 206 | 207 | // Draw Light Rail 208 | if (slider.isEnabled()) { 209 | Path valueArc; 210 | if (!isCentered) { 211 | if (!isInverted) { 212 | valueArc.addCentredArc(bounds.getCentreX(), 213 | bounds.getCentreY(), 214 | arcRadius, 215 | arcRadius, 216 | 0.0f, 217 | rotaryStartAngle, 218 | toAngle, 219 | true); 220 | } else { 221 | valueArc.addCentredArc(bounds.getCentreX(), 222 | bounds.getCentreY(), 223 | arcRadius, 224 | arcRadius, 225 | 0.0f, 226 | rotaryEndAngle, 227 | toAngle, 228 | true); 229 | } 230 | } else { 231 | valueArc.addCentredArc(bounds.getCentreX(), 232 | bounds.getCentreY(), 233 | arcRadius, 234 | arcRadius, 235 | 0.0f, 236 | rotaryStartAngle + center, 237 | toAngle, 238 | true); 239 | } 240 | g.setColour(fill); 241 | g.strokePath( 242 | valueArc, 243 | PathStrokeType(lineW, PathStrokeType::curved, PathStrokeType::rounded)); 244 | } 245 | // Draw Thumb 246 | Point thumbPoint( 247 | bounds.getCentreX() + 248 | arcRadius * std::cos(toAngle - MathConstants::halfPi), 249 | bounds.getCentreY() + 250 | arcRadius * std::sin(toAngle - MathConstants::halfPi)); 251 | g.setColour(backgroundColor); 252 | g.fillEllipse( 253 | Rectangle(thumbWidth, thumbWidth).withCentre(thumbPoint)); 254 | g.setColour(color); 255 | g.drawEllipse( 256 | Rectangle(thumbWidth, thumbWidth).withCentre(thumbPoint), 257 | lineSize); 258 | } else { 259 | // Draw Selector 260 | auto spacing = (rotaryEndAngle - rotaryStartAngle) / (numOptions - 1); 261 | auto r = bounds.getHeight() / 2.5; 262 | auto dotSize = thumbWidth; 263 | auto radianOffset = rotaryStartAngle - rotaryEndAngle; 264 | auto angle = rotaryStartAngle; 265 | 266 | for (int i = 0; i < numOptions; i++) { 267 | // Calculate Position 268 | auto x = r * cos(angle - radianOffset); 269 | auto y = r * sin(angle - radianOffset); 270 | 271 | // Check if selected 272 | if (selectedOption != i) { 273 | 274 | // Dot Ring Unselected 275 | Point outer(bounds.getCentreX() + x, bounds.getCentreY() + y); 276 | g.setColour(color); 277 | g.drawEllipse( 278 | Rectangle(dotSize / 2, dotSize / 2).withCentre(outer), 279 | lineSize); 280 | 281 | } else { 282 | Point inner(bounds.getCentreX() + x, bounds.getCentreY() + y); 283 | g.setColour(fill); 284 | g.fillEllipse( 285 | Rectangle(dotSize / 2, dotSize / 2).withCentre(inner)); 286 | Point outer(bounds.getCentreX() + x, bounds.getCentreY() + y); 287 | g.setColour(color); 288 | g.drawEllipse(Rectangle(dotSize, dotSize).withCentre(outer), 289 | lineSize); 290 | } 291 | angle += spacing; 292 | } 293 | } 294 | 295 | // Calculate Knob 296 | auto sliderAngleRadian = 297 | jmap(normalisedPos, 0.0f, 1.0f, rotaryStartAngle, rotaryEndAngle); 298 | auto offset = width / 4; 299 | float r = width / 6; 300 | if (slider.isMouseButtonDown()) { 301 | offset = width / 4.5; 302 | r = width / 5; 303 | } 304 | auto circleBounds = Rectangle(bounds.getX() + offset, 305 | bounds.getY() + offset, 306 | bounds.getWidth() - 2 * offset, 307 | bounds.getHeight() - 2 * offset); 308 | 309 | // Get Sine / Cosine 310 | float s, c; 311 | c = cos(-sliderAngleRadian); 312 | s = sin(-sliderAngleRadian); 313 | 314 | // Calculate Indicator 315 | float x0, x1, x2, y0, y1, y2; 316 | x0 = circleBounds.getCentreX(); 317 | y0 = circleBounds.getCentreY(); 318 | x1 = 0; 319 | y1 = 0; 320 | x2 = -r * s; 321 | y2 = -r * c; 322 | x1 = x1 + x0; 323 | y1 = y1 + y0; 324 | x2 = x2 + x0; 325 | y2 = y2 + y0; 326 | 327 | // Draw Knob 328 | g.setColour(color); 329 | g.drawLine(x1, y1, x2, y2, lineSize); 330 | g.drawEllipse(circleBounds, lineSize); 331 | 332 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 333 | } 334 | 335 | Typeface::Ptr 336 | CustomLookAndFeel::getCustomTypeface() 337 | { 338 | Typeface::Ptr typeface = Typeface::createSystemTypefaceFor( 339 | BinaryData::PoppinsMedium_ttf, BinaryData::PoppinsMedium_ttfSize); 340 | return typeface; 341 | } 342 | 343 | Font 344 | CustomLookAndFeel::getCustomFont() 345 | { 346 | Font font(getCustomTypeface()); 347 | return font; 348 | } 349 | -------------------------------------------------------------------------------- /Plasma.jucer: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 16 | 18 | 19 | 21 | 23 | 25 | 26 | 28 | 30 | 31 | 33 | 35 | 37 | 39 | 41 | 42 | 43 | 45 | 47 | 48 | 49 | 51 | 53 | 55 | 57 | 59 | 61 | 63 | 65 | 67 | 69 | 71 | 72 | 73 | 74 | 75 | 76 | 78 | 79 | 80 | 81 | 83 | 85 | 87 | 89 | 91 | 93 | 95 | 97 | 99 | 101 | 103 | 105 | 107 | 109 | 111 | 113 | 115 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /Source/PluginProcessor.cpp: -------------------------------------------------------------------------------- 1 | #include "PluginProcessor.h" 2 | #include "PluginEditor.h" 3 | 4 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 5 | // JUCE 6 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 7 | PlasmaAudioProcessor::PlasmaAudioProcessor() 8 | #ifndef JucePlugin_PreferredChannelConfigurations 9 | : AudioProcessor( 10 | BusesProperties() 11 | #if !JucePlugin_IsMidiEffect 12 | #if !JucePlugin_IsSynth 13 | .withInput("Input", juce::AudioChannelSet::stereo(), true) 14 | #endif 15 | .withOutput("Output", juce::AudioChannelSet::stereo(), true) 16 | #endif 17 | ) 18 | #endif 19 | { 20 | } 21 | 22 | PlasmaAudioProcessor::~PlasmaAudioProcessor() {} 23 | 24 | //============================================================================== 25 | const juce::String 26 | PlasmaAudioProcessor::getName() const 27 | { 28 | return JucePlugin_Name; 29 | } 30 | 31 | bool 32 | PlasmaAudioProcessor::acceptsMidi() const 33 | { 34 | #if JucePlugin_WantsMidiInput 35 | return true; 36 | #else 37 | return false; 38 | #endif 39 | } 40 | 41 | bool 42 | PlasmaAudioProcessor::producesMidi() const 43 | { 44 | #if JucePlugin_ProducesMidiOutput 45 | return true; 46 | #else 47 | return false; 48 | #endif 49 | } 50 | 51 | bool 52 | PlasmaAudioProcessor::isMidiEffect() const 53 | { 54 | #if JucePlugin_IsMidiEffect 55 | return true; 56 | #else 57 | return false; 58 | #endif 59 | } 60 | 61 | double 62 | PlasmaAudioProcessor::getTailLengthSeconds() const 63 | { 64 | return 0.0; 65 | } 66 | 67 | int 68 | PlasmaAudioProcessor::getNumPrograms() 69 | { 70 | return 1; // NB: some hosts don't cope very well if you tell them there are 0 71 | // programs, 72 | // so this should be at least 1, even if you're not really implementing 73 | // programs. 74 | } 75 | 76 | int 77 | PlasmaAudioProcessor::getCurrentProgram() 78 | { 79 | return 0; 80 | } 81 | 82 | void 83 | PlasmaAudioProcessor::setCurrentProgram(int index) 84 | { 85 | } 86 | 87 | const juce::String 88 | PlasmaAudioProcessor::getProgramName(int index) 89 | { 90 | return {}; 91 | } 92 | 93 | void 94 | PlasmaAudioProcessor::changeProgramName(int index, const juce::String& newName) 95 | { 96 | } 97 | 98 | //============================================================================== 99 | 100 | void 101 | PlasmaAudioProcessor::releaseResources() 102 | { 103 | // When playback stops, you can use this as an opportunity to free up any 104 | // spare memory, etc. 105 | } 106 | 107 | #ifndef JucePlugin_PreferredChannelConfigurations 108 | bool 109 | PlasmaAudioProcessor::isBusesLayoutSupported(const BusesLayout& layouts) const 110 | { 111 | #if JucePlugin_IsMidiEffect 112 | juce::ignoreUnused(layouts); 113 | return true; 114 | #else 115 | // This is the place where you check if the layout is supported. 116 | // In this template code we only support mono or stereo. 117 | // Some plugin hosts, such as certain GarageBand versions, will only 118 | // load plugins that support stereo bus layouts. 119 | if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::mono() && 120 | layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo()) 121 | return false; 122 | 123 | // This checks if the input layout matches the output layout 124 | #if !JucePlugin_IsSynth 125 | if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet()) 126 | return false; 127 | #endif 128 | 129 | return true; 130 | #endif 131 | } 132 | #endif 133 | 134 | //============================================================================== 135 | bool 136 | PlasmaAudioProcessor::hasEditor() const 137 | { 138 | return true; // (change this to false if you choose to not supply an editor) 139 | } 140 | 141 | juce::AudioProcessorEditor* 142 | PlasmaAudioProcessor::createEditor() 143 | { 144 | // return new juce::GenericAudioProcessorEditor(*this); 145 | return new PlasmaAudioProcessorEditor(*this); 146 | } 147 | 148 | //============================================================================== 149 | void 150 | PlasmaAudioProcessor::getStateInformation(juce::MemoryBlock& destData) 151 | { 152 | juce::MemoryOutputStream mos(destData, true); 153 | apvts.state.writeToStream(mos); 154 | } 155 | 156 | void 157 | PlasmaAudioProcessor::setStateInformation(const void* data, int sizeInBytes) 158 | { 159 | auto tree = juce::ValueTree::readFromData(data, sizeInBytes); 160 | if (tree.isValid()) { 161 | apvts.replaceState(tree); 162 | updateFilters(); 163 | } 164 | } 165 | 166 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 167 | // Prepare 168 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 169 | 170 | juce::AudioProcessor* JUCE_CALLTYPE 171 | createPluginFilter() 172 | { 173 | return new PlasmaAudioProcessor(); 174 | } 175 | 176 | void 177 | PlasmaAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) 178 | { 179 | juce::dsp::ProcessSpec spec; 180 | spec.maximumBlockSize = samplesPerBlock; 181 | spec.numChannels = 1; 182 | spec.sampleRate = sampleRate; 183 | 184 | leftChain.prepare(spec); 185 | rightChain.prepare(spec); 186 | 187 | // Filter 188 | updateFilters(); 189 | 190 | // Allocate Clean Buffer 191 | cleanBuffer.setSize(getNumInputChannels(), samplesPerBlock); 192 | 193 | // Waveform 194 | waveformComponent.clear(); 195 | 196 | // Trigger VersionManager 197 | versionManager.triggerAsyncUpdate(); 198 | 199 | // Loudness Meter 200 | const int expectedRequestRate = sampleRate / samplesPerBlock; 201 | loudnessMeterIn.prepareToPlay(sampleRate, 2, samplesPerBlock, 3); 202 | loudnessMeterOut.prepareToPlay(sampleRate, 2, samplesPerBlock, 3); 203 | } 204 | 205 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 206 | // ProcessBlock 207 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 208 | 209 | void 210 | PlasmaAudioProcessor::processBlock(juce::AudioBuffer& buffer, 211 | juce::MidiBuffer& midiMessages) 212 | { 213 | juce::ScopedNoDenormals noDenormals; 214 | auto totalNumInputChannels = getTotalNumInputChannels(); 215 | auto totalNumOutputChannels = getTotalNumOutputChannels(); 216 | 217 | for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) 218 | buffer.clear(i, 0, buffer.getNumSamples()); 219 | float gain, preGain; 220 | // Get Settings 221 | auto chainSettings = getChainSettings(apvts); 222 | if (chainSettings.preGain > -32.f) { 223 | preGain = Decibels::decibelsToGain(chainSettings.preGain); 224 | } else { 225 | preGain = 0.0f; 226 | } 227 | if (chainSettings.gain > -32.f) { 228 | gain = Decibels::decibelsToGain(chainSettings.gain); 229 | } else { 230 | gain = 0.f; 231 | } 232 | float mixWet = chainSettings.mix / 100; 233 | float mixDry = (100.0 - chainSettings.mix) / 100; 234 | // bool killswitch = false; 235 | 236 | // Clean 237 | AudioSampleBuffer tmpBuffer(cleanBuffer.getArrayOfWritePointers(), 238 | buffer.getNumChannels(), 239 | buffer.getNumSamples()); 240 | for (int ch = 0; ch < buffer.getNumChannels(); ++ch) 241 | tmpBuffer.copyFrom(ch, 0, buffer, ch, 0, buffer.getNumSamples()); 242 | 243 | // Clean RMS 244 | auto leftRms = buffer.getRMSLevel(0, 0, buffer.getNumSamples()); 245 | auto rightRms = buffer.getRMSLevel(1, 0, buffer.getNumSamples()); 246 | 247 | // Clean Loudness Meter 248 | loudnessMeterIn.processBlock(buffer); 249 | 250 | // Distortion Unit 251 | std::vector randoms(buffer.getNumSamples()); 252 | for (int& n : randoms) 253 | n = rand(); 254 | for (int channel = 0; channel < 2; ++channel) { 255 | auto* channelData = buffer.getWritePointer(channel); 256 | 257 | for (int sample = 0; sample < buffer.getNumSamples(); sample++) { 258 | if (channelData[sample] != 0.0) { 259 | // Pre Gain 260 | channelData[sample] = 261 | DistortionProcessor::clamp(channelData[sample] * preGain, -1.0, 1.0); 262 | 263 | // Girth 264 | if (chainSettings.girth >= 0.0f) 265 | channelData[sample] = 266 | channelData[sample] * 267 | ((((float)(rand() % 100)) / 100 * chainSettings.girth) + 1); 268 | else { 269 | channelData[sample] = 270 | channelData[sample] * 271 | ((((float)(randoms[sample] % 100)) / 100 * -chainSettings.girth) + 272 | 1); 273 | } 274 | 275 | // Drive 276 | DistortionProcessor::distort( 277 | channelData[sample], chainSettings.drive, chainSettings.driveType); 278 | 279 | // Bias 280 | // channelData[sample] = clamp(channelData[sample] + 281 | // chainSettings.bias, -1.0, 1.0); 282 | if (channelData[sample] > 0) { 283 | channelData[sample] += channelData[sample] * chainSettings.bias; 284 | } else if (channelData[sample] < 0) { 285 | channelData[sample] -= channelData[sample] * chainSettings.bias; 286 | } 287 | } 288 | } 289 | } 290 | 291 | // DSP 292 | juce::dsp::AudioBlock block(buffer); 293 | 294 | // Filter 295 | updateFilters(); 296 | auto threshold = 0.0f; 297 | if (leftRms != threshold) { 298 | auto leftBlock = block.getSingleChannelBlock(0); 299 | juce::dsp::ProcessContextReplacing leftContext(leftBlock); 300 | leftChain.process(leftContext); 301 | } else { 302 | auto data = buffer.getWritePointer(0); 303 | for (int sample = 0; sample < buffer.getNumSamples(); sample++) { 304 | data[sample] = 0.0f; 305 | } 306 | } 307 | 308 | if (rightRms != threshold) { 309 | auto rightBlock = block.getSingleChannelBlock(1); 310 | juce::dsp::ProcessContextReplacing rightContext(rightBlock); 311 | rightChain.process(rightContext); 312 | } else { 313 | auto data = buffer.getWritePointer(1); 314 | for (int sample = 0; sample < buffer.getNumSamples(); sample++) { 315 | data[sample] = 0.0f; 316 | } 317 | } 318 | 319 | // Late Stage 320 | for (int& n : randoms) 321 | n = rand(); 322 | for (int channel = 0; channel < totalNumInputChannels; ++channel) { 323 | auto* channelData = buffer.getWritePointer(channel); 324 | auto* cleanData = tmpBuffer.getWritePointer(channel); 325 | for (int sample = 0; sample < buffer.getNumSamples(); sample++) { 326 | if (channelData[sample] != 0.0) { 327 | // Reduce Loudness 328 | channelData[sample] = 329 | DistortionProcessor::clamp(channelData[sample], -1, 1); 330 | 331 | // Girth 332 | if (chainSettings.lateGirth >= 0.0f) 333 | channelData[sample] = 334 | channelData[sample] * 335 | ((((float)(rand() % 100)) / 100 * chainSettings.lateGirth) + 1); 336 | else { 337 | channelData[sample] = 338 | channelData[sample] * ((((float)(randoms[sample] % 100)) / 100 * 339 | -chainSettings.lateGirth) + 340 | 1); 341 | } 342 | 343 | // Drive 344 | DistortionProcessor::distort(channelData[sample], 345 | chainSettings.lateDrive, 346 | chainSettings.lateDriveType); 347 | 348 | // Bias 349 | if (channelData[sample] > 0) { 350 | channelData[sample] += channelData[sample] * chainSettings.lateBias; 351 | } else if (channelData[sample] < 0) { 352 | channelData[sample] -= channelData[sample] * chainSettings.lateBias; 353 | } 354 | // Mix 355 | channelData[sample] = 356 | cleanData[sample] * mixDry + channelData[sample] * mixWet; 357 | 358 | // Reduce Loudness for Waveform Analyser 359 | channelData[sample] = 360 | 0.5 * DistortionProcessor::clamp(channelData[sample], -1, 1); 361 | } 362 | } 363 | } 364 | 365 | // Update Waveform Analyser 366 | waveformComponent.pushBuffer(buffer); 367 | for (int channel = 0; channel < totalNumInputChannels; ++channel) { 368 | auto* channelData = buffer.getWritePointer(channel); 369 | for (int sample = 0; sample < buffer.getNumSamples(); sample++) { 370 | // Gain 371 | channelData[sample] = channelData[sample] * gain * 2; 372 | } 373 | } 374 | 375 | // Loudness Meter 376 | loudnessMeterOut.processBlock(buffer); 377 | } 378 | 379 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 380 | // AudioProcessorValueTreeState 381 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 382 | 383 | juce::AudioProcessorValueTreeState::ParameterLayout 384 | PlasmaAudioProcessor::createParameterLayout() 385 | { 386 | juce::AudioProcessorValueTreeState::ParameterLayout layout; 387 | 388 | // Pre Gain 389 | layout.add(std::make_unique( 390 | "Pre Gain", 391 | "Pre Gain", 392 | juce::NormalisableRange(-64.0f, 64.0f, 0.2f, 1.0f), 393 | 0.0f)); 394 | // Drive 395 | juce::StringArray distortionArray; 396 | distortionArray.add("Hard Clip"); 397 | distortionArray.add("Soft Clip"); 398 | distortionArray.add("Saturate"); 399 | distortionArray.add("Atan"); 400 | distortionArray.add("Crunch"); 401 | distortionArray.add("Bitcrush"); 402 | distortionArray.add("Extreme"); 403 | distortionArray.add("Scream"); 404 | distortionArray.add("Sine"); 405 | distortionArray.add("Cosine"); 406 | distortionArray.add("Harmonic"); 407 | distortionArray.add("Weird"); 408 | layout.add(std::make_unique( 409 | "Drive", 410 | "Drive", 411 | juce::NormalisableRange(1.0f, 11.0f, 0.01f, 0.5f), 412 | 0.0f)); 413 | layout.add(std::make_unique( 414 | "Distortion Type", "Distortion Type", distortionArray, 0)); 415 | // Girth 416 | layout.add(std::make_unique( 417 | "Girth", 418 | "Girth", 419 | juce::NormalisableRange(-1.0f, 1.0f, 0.01f, 1.0f), 420 | 0.0f)); 421 | // Bias 422 | layout.add(std::make_unique( 423 | "Bias", 424 | "Bias", 425 | juce::NormalisableRange(-1.0f, 1.0f, 0.01f, 1.0f), 426 | 0.0f)); 427 | // Peak 428 | layout.add(std::make_unique( 429 | "Peak Stereo", 430 | "Peak Stereo", 431 | juce::NormalisableRange(0.0f, 100.0f, 0.1f, 1.0f), 432 | 0.0f)); 433 | layout.add(std::make_unique( 434 | "Peak Freq", 435 | "Peak Freq", 436 | juce::NormalisableRange(20.0f, 20000.0f, 0.1f, 0.18), 437 | 450.0f)); 438 | layout.add(std::make_unique( 439 | "Peak Gain", 440 | "Peak Gain", 441 | juce::NormalisableRange(-64.0f, 64.0f, 0.1f, 1.0f), 442 | 0.0f)); 443 | layout.add(std::make_unique( 444 | "Peak Q", 445 | "Peak Q", 446 | juce::NormalisableRange(0.1f, 5.0f, 0.01f, 1.0f), 447 | 1.0f)); 448 | // Dual Peak 449 | layout.add(std::make_unique( 450 | "Dual Peak Width", 451 | "Dual Peak Width", 452 | juce::NormalisableRange(0.0f, 100.0f, 0.1f, 1.0f), 453 | 0.0f)); 454 | layout.add(std::make_unique( 455 | "Dual Peak Freq", 456 | "Dual Peak Freq", 457 | juce::NormalisableRange(20.0f, 20000.0f, 0.1f, 0.18), 458 | 450.0f)); 459 | layout.add(std::make_unique( 460 | "Dual Peak Gain", 461 | "Dual Peak Gain", 462 | juce::NormalisableRange(-64.0f, 64.0f, 0.1f, 1.0f), 463 | 0.0f)); 464 | layout.add(std::make_unique( 465 | "Dual Peak Q", 466 | "Dual Peak Q", 467 | juce::NormalisableRange(0.1f, 5.0f, 0.01f, 1.0f), 468 | 1.0f)); 469 | // Slope Array 470 | juce::StringArray slopeArray; 471 | for (int i = 0; i < 8; i++) { 472 | juce::String str; 473 | str << (12 + i * 12); 474 | str << " db/Oct"; 475 | slopeArray.add(str); 476 | } 477 | slopeArray.add("Peak Only"); 478 | // Highpass 479 | layout.add(std::make_unique( 480 | "Highpass Slope", "Highpass Slope", slopeArray, 0)); 481 | layout.add(std::make_unique( 482 | "Highpass Freq", 483 | "Highpass Freq", 484 | juce::NormalisableRange(20.0f, 20000.0f, 0.1f, 0.18f), 485 | 20.0f)); 486 | layout.add(std::make_unique( 487 | "Highpass Resonance", 488 | "Highpass Resonance", 489 | juce::NormalisableRange(-64.0f, 64.0f, 0.1f, 1.0f), 490 | 0.0f)); 491 | layout.add(std::make_unique( 492 | "Highpass Resonance Q", 493 | "Highpass Resonance Q", 494 | juce::NormalisableRange(0.1f, 5.0f, 0.01f, 1.0f), 495 | 1.0f)); 496 | // Lowpass 497 | layout.add(std::make_unique( 498 | "Lowpass Slope", "Lowpass Slope", slopeArray, 0)); 499 | layout.add(std::make_unique( 500 | "Lowpass Freq", 501 | "Lowpass Freq", 502 | juce::NormalisableRange(20.0f, 20000.0f, 0.1f, 0.18f), 503 | 20000.0f)); 504 | layout.add(std::make_unique( 505 | "Lowpass Resonance", 506 | "Lowpass Resonance", 507 | juce::NormalisableRange(-64.0f, 64.0f, 0.1f, 1.0f), 508 | 0.0f)); 509 | layout.add(std::make_unique( 510 | "Lowpass Resonance Q", 511 | "Lowpass Resonance Q", 512 | juce::NormalisableRange(0.1f, 5.0f, 0.01f, 1.0f), 513 | 1.0f)); 514 | // Late Drive 515 | layout.add(std::make_unique( 516 | "Late Distortion Type", "Late Distortion Type", distortionArray, 0)); 517 | layout.add(std::make_unique( 518 | "Late Drive", 519 | "Late Drive", 520 | juce::NormalisableRange(1.0f, 11.0f, 0.01f, 0.5f), 521 | 0.0f)); 522 | // Late Girth 523 | layout.add(std::make_unique( 524 | "Late Girth", 525 | "Late Girth", 526 | juce::NormalisableRange(-1.0f, 1.0f, 0.01f, 1.0f), 527 | 0.0f)); 528 | // Late Bias 529 | layout.add(std::make_unique( 530 | "Late Bias", 531 | "Late Bias", 532 | juce::NormalisableRange(-1.0f, 1.0f, 0.01f, 1.0f), 533 | 0.0f)); 534 | // Gain 535 | layout.add(std::make_unique( 536 | "Gain", 537 | "Gain", 538 | juce::NormalisableRange(-64.0f, 64.0f, 0.2f, 1.0f), 539 | 0.0f)); 540 | // Mix 541 | layout.add(std::make_unique( 542 | "Mix", 543 | "Mix", 544 | juce::NormalisableRange(0.0f, 100.0f, 0.01f, 1.0f), 545 | 100.0f)); 546 | // Analyser 547 | juce::StringArray analyserArray; 548 | for (int i = 0; i < 5; i++) { 549 | juce::String str; 550 | str << "Type "; 551 | str << i; 552 | analyserArray.add(str); 553 | } 554 | layout.add(std::make_unique( 555 | "Analyser Type", "Analyser Type", analyserArray, 0)); 556 | return layout; 557 | } 558 | 559 | ChainSettings 560 | getChainSettings(juce::AudioProcessorValueTreeState& apvts) 561 | { 562 | ChainSettings settings; 563 | // Distortion Unit 564 | settings.preGain = apvts.getRawParameterValue("Pre Gain")->load(); 565 | settings.drive = apvts.getRawParameterValue("Drive")->load(); 566 | settings.girth = apvts.getRawParameterValue("Girth")->load(); 567 | settings.bias = apvts.getRawParameterValue("Bias")->load(); 568 | settings.driveType = static_cast( 569 | apvts.getRawParameterValue("Distortion Type")->load()); 570 | // Peak 571 | settings.peakStereo = apvts.getRawParameterValue("Peak Stereo")->load(); 572 | settings.peakFreq = apvts.getRawParameterValue("Peak Freq")->load(); 573 | settings.peakGain = apvts.getRawParameterValue("Peak Gain")->load(); 574 | settings.peakQuality = apvts.getRawParameterValue("Peak Q")->load(); 575 | // Dual Peak 576 | settings.dualPeakWidth = 577 | apvts.getRawParameterValue("Dual Peak Width")->load(); 578 | settings.dualPeakFreq = apvts.getRawParameterValue("Dual Peak Freq")->load(); 579 | settings.dualPeakGain = apvts.getRawParameterValue("Dual Peak Gain")->load(); 580 | settings.dualPeakQuality = apvts.getRawParameterValue("Dual Peak Q")->load(); 581 | // Highpass 582 | settings.highPassFreq = apvts.getRawParameterValue("Highpass Freq")->load(); 583 | settings.highPassResonance = 584 | apvts.getRawParameterValue("Highpass Resonance")->load(); 585 | settings.highPassResonanceQuality = 586 | apvts.getRawParameterValue("Highpass Resonance Q")->load(); 587 | settings.highPassSlope = 588 | static_cast(apvts.getRawParameterValue("Highpass Slope")->load()); 589 | // Lowpass 590 | settings.lowPassFreq = apvts.getRawParameterValue("Lowpass Freq")->load(); 591 | settings.lowPassResonance = 592 | apvts.getRawParameterValue("Lowpass Resonance")->load(); 593 | settings.lowPassResonanceQuality = 594 | apvts.getRawParameterValue("Lowpass Resonance Q")->load(); 595 | settings.lowPassSlope = 596 | static_cast(apvts.getRawParameterValue("Lowpass Slope")->load()); 597 | 598 | // Late 599 | settings.lateDriveType = static_cast( 600 | apvts.getRawParameterValue("Late Distortion Type")->load()); 601 | settings.lateDrive = apvts.getRawParameterValue("Late Drive")->load(); 602 | settings.lateGirth = apvts.getRawParameterValue("Late Girth")->load(); 603 | settings.lateBias = apvts.getRawParameterValue("Late Bias")->load(); 604 | settings.gain = apvts.getRawParameterValue("Gain")->load(); 605 | // Mix 606 | settings.mix = apvts.getRawParameterValue("Mix")->load(); 607 | // Analyser 608 | settings.analyserType = static_cast( 609 | apvts.getRawParameterValue("Analyser Type")->load()); 610 | return settings; 611 | } 612 | 613 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 614 | // Filters 615 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 616 | 617 | void 618 | PlasmaAudioProcessor::updateFilters() 619 | { 620 | auto chainSettings = getChainSettings(apvts); 621 | updateHighPass(chainSettings); 622 | updateHighPassResonance(chainSettings); 623 | updatePeakFilter(chainSettings); 624 | updateDualPeakFilter(chainSettings); 625 | updateLowPass(chainSettings); 626 | updateLowPassResonance(chainSettings); 627 | } 628 | Coefficients 629 | makePeakFilter(const ChainSettings& chainSettings, 630 | double sampleRate, 631 | float offset) 632 | { 633 | return juce::dsp::IIR::Coefficients::makePeakFilter( 634 | sampleRate, 635 | DistortionProcessor::clamp(chainSettings.peakFreq + offset, 20, 20000), 636 | chainSettings.peakQuality, 637 | juce::Decibels::decibelsToGain(chainSettings.peakGain)); 638 | } 639 | Coefficients 640 | makeDualPeakFilter(const ChainSettings& chainSettings, 641 | double sampleRate, 642 | float offset) 643 | { 644 | return juce::dsp::IIR::Coefficients::makePeakFilter( 645 | sampleRate, 646 | DistortionProcessor::clamp(chainSettings.dualPeakFreq + offset, 20, 20000), 647 | chainSettings.dualPeakQuality, 648 | juce::Decibels::decibelsToGain(chainSettings.dualPeakGain)); 649 | } 650 | Coefficients 651 | makeLowPassResonance(const ChainSettings& chainSettings, double sampleRate) 652 | { 653 | auto gain = chainSettings.lowPassResonance; 654 | return juce::dsp::IIR::Coefficients::makePeakFilter( 655 | sampleRate, 656 | chainSettings.lowPassFreq, 657 | chainSettings.lowPassResonanceQuality, 658 | juce::Decibels::decibelsToGain(gain)); 659 | } 660 | Coefficients 661 | makeHighPassResonance(const ChainSettings& chainSettings, double sampleRate) 662 | { 663 | auto gain = chainSettings.highPassResonance; 664 | return juce::dsp::IIR::Coefficients::makePeakFilter( 665 | sampleRate, 666 | chainSettings.highPassFreq, 667 | chainSettings.highPassResonanceQuality, 668 | juce::Decibels::decibelsToGain(gain)); 669 | } 670 | void 671 | PlasmaAudioProcessor::updatePeakFilter(const ChainSettings& chainSettings) 672 | { 673 | auto peakCoefficientsL = 674 | makePeakFilter(chainSettings, getSampleRate(), chainSettings.peakStereo); 675 | auto peakCoefficientsR = 676 | makePeakFilter(chainSettings, getSampleRate(), -chainSettings.peakStereo); 677 | updateCoefficients(leftChain.get().coefficients, 678 | *peakCoefficientsL); 679 | updateCoefficients(rightChain.get().coefficients, 680 | *peakCoefficientsR); 681 | } 682 | 683 | void 684 | PlasmaAudioProcessor::updateDualPeakFilter(const ChainSettings& chainSettings) 685 | { 686 | auto dualPeakWidth = chainSettings.dualPeakWidth; 687 | auto dualPeakFreq = chainSettings.dualPeakFreq; 688 | 689 | auto logFreq = juce::mapFromLog10(dualPeakFreq, 20.0f, 20000.0f); 690 | auto width = dualPeakWidth / 500.0f; 691 | 692 | auto logFreqA = logFreq - width; 693 | auto logFreqB = logFreq + width; 694 | 695 | auto freqA = juce::mapToLog10(logFreqA, 20.0f, 20000.0f); 696 | auto freqB = juce::mapToLog10(logFreqB, 20.0f, 20000.0f); 697 | 698 | auto offsetA = freqA - dualPeakFreq; 699 | auto offsetB = freqB - dualPeakFreq; 700 | 701 | auto peakCoefficientsA = 702 | makeDualPeakFilter(chainSettings, getSampleRate(), offsetA); 703 | auto peakCoefficientsB = 704 | makeDualPeakFilter(chainSettings, getSampleRate(), offsetB); 705 | 706 | updateCoefficients(leftChain.get().coefficients, 707 | *peakCoefficientsA); 708 | updateCoefficients(rightChain.get().coefficients, 709 | *peakCoefficientsA); 710 | 711 | updateCoefficients(leftChain.get().coefficients, 712 | *peakCoefficientsB); 713 | updateCoefficients(rightChain.get().coefficients, 714 | *peakCoefficientsB); 715 | } 716 | 717 | void 718 | PlasmaAudioProcessor::updateHighPassResonance( 719 | const ChainSettings& chainSettings) 720 | { 721 | auto gain = chainSettings.highPassResonance; 722 | auto peakCoefficients = juce::dsp::IIR::Coefficients::makePeakFilter( 723 | getSampleRate(), 724 | chainSettings.highPassFreq, 725 | chainSettings.highPassResonanceQuality, 726 | juce::Decibels::decibelsToGain(gain)); 727 | 728 | updateCoefficients( 729 | leftChain.get().coefficients, 730 | *peakCoefficients); 731 | updateCoefficients( 732 | rightChain.get().coefficients, 733 | *peakCoefficients); 734 | } 735 | 736 | void 737 | PlasmaAudioProcessor::updateLowPassResonance(const ChainSettings& chainSettings) 738 | { 739 | auto gain = chainSettings.lowPassResonance; 740 | auto peakCoefficients = juce::dsp::IIR::Coefficients::makePeakFilter( 741 | getSampleRate(), 742 | chainSettings.lowPassFreq, 743 | chainSettings.lowPassResonanceQuality, 744 | juce::Decibels::decibelsToGain(gain)); 745 | 746 | updateCoefficients( 747 | leftChain.get().coefficients, 748 | *peakCoefficients); 749 | updateCoefficients( 750 | rightChain.get().coefficients, 751 | *peakCoefficients); 752 | } 753 | 754 | void 755 | PlasmaAudioProcessor::updateHighPass(const ChainSettings& chainSettings) 756 | { 757 | auto highPassCoefficients = 758 | makeHighPassFilter(chainSettings, getSampleRate()); 759 | 760 | auto& leftHighPass = leftChain.get(); 761 | updatePassFilter( 762 | leftHighPass, highPassCoefficients, chainSettings.highPassSlope); 763 | 764 | auto& rightHighPass = rightChain.get(); 765 | updatePassFilter( 766 | rightHighPass, highPassCoefficients, chainSettings.highPassSlope); 767 | } 768 | 769 | void 770 | PlasmaAudioProcessor::updateLowPass(const ChainSettings& chainSettings) 771 | { 772 | auto lowPassCoefficients = makeLowPassFilter(chainSettings, getSampleRate()); 773 | 774 | auto& leftLowPass = leftChain.get(); 775 | updatePassFilter( 776 | leftLowPass, lowPassCoefficients, chainSettings.lowPassSlope); 777 | 778 | auto& rightLowPass = rightChain.get(); 779 | updatePassFilter( 780 | rightLowPass, lowPassCoefficients, chainSettings.lowPassSlope); 781 | } 782 | 783 | void 784 | updateCoefficients(Coefficients& old, const Coefficients& replacements) 785 | { 786 | *old = *replacements; 787 | } 788 | --------------------------------------------------------------------------------