├── .gitignore ├── CMake └── FindJUCE-GIT.cmake ├── CMakeLists.txt ├── Plugins ├── BasicMidiEffect │ ├── CMakeLists.txt │ ├── MidiEffect.jucer │ └── Source │ │ ├── MidiProcessor.cpp │ │ ├── MidiProcessor.h │ │ ├── PluginEditor.cpp │ │ ├── PluginEditor.h │ │ ├── PluginProcessor.cpp │ │ └── PluginProcessor.h ├── CMakeLists.txt └── DynamicParameters │ ├── CMakeLists.txt │ ├── DynamicParameters.jucer │ └── Source │ ├── CustomProcessor.h │ ├── ParameterHelpers.h │ ├── PluginEditor.cpp │ ├── PluginEditor.h │ ├── PluginProcessor.cpp │ └── PluginProcessor.h ├── Standalone ├── CMakeLists.txt ├── ConsoleToot │ ├── CMakeLists.txt │ ├── ConsoleToot.jucer │ ├── README.md │ └── Source │ │ └── Main.cpp └── LoadingSVG │ ├── CMakeLists.txt │ ├── LoadingSVG.jucer │ └── Source │ ├── Main.cpp │ ├── MainComponent.h │ └── SVGDisplay.h └── _clang-format /.gitignore: -------------------------------------------------------------------------------- 1 | *.user 2 | 3 | Builds 4 | JuceLibraryCode 5 | 6 | build 7 | cmake-build-debug 8 | cmake-build-release 9 | .idea 10 | 11 | IDEWorkspaceChecks.plist 12 | UserInterfaceState.xcuserstate 13 | xcschememanagement.plist 14 | *.xcscheme 15 | .vscode 16 | *.xcworkspace 17 | *.DS_Store 18 | *.entitlements 19 | 20 | workspace.xml 21 | xcuserdata 22 | -------------------------------------------------------------------------------- /CMake/FindJUCE-GIT.cmake: -------------------------------------------------------------------------------- 1 | include(FetchContent QUIET) 2 | 3 | #Helper file to grab JUCE automatically from git. 4 | #You can set this to use a specific commit, a git submodule, etc. 5 | 6 | macro(update_juce_from_git) 7 | # If JUCE is a submodule you could use SOURCE_DIR here instead of the GIT_* args 8 | FetchContent_Declare(juce 9 | GIT_REPOSITORY "https://github.com/juce-framework/juce" 10 | GIT_SHALLOW TRUE 11 | GIT_PROGRESS TRUE 12 | GIT_TAG "origin/develop") 13 | 14 | FetchContent_GetProperties(juce) 15 | 16 | if (NOT juce_POPULATED) 17 | message("Updating JUCE from git...") 18 | FetchContent_Populate(juce) 19 | message("JUCE update finished") 20 | endif () 21 | endmacro() 22 | 23 | update_juce_from_git() 24 | 25 | #useful to build stuff like the projucer, audio plugin host, etc in your own project 26 | set(JUCE_SOURCE_ROOT ${CMAKE_CURRENT_BINARY_DIR}/_deps/juce-src) 27 | add_subdirectory(${JUCE_SOURCE_ROOT}) 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(AudioDevExamples) 3 | 4 | #Updates or clones JUCE from git, and configures it for subdirectories: 5 | include (CMake/FindJUCE-GIT.cmake) 6 | 7 | #adding project folders: 8 | add_subdirectory(Standalone) 9 | add_subdirectory(Plugins) 10 | -------------------------------------------------------------------------------- /Plugins/BasicMidiEffect/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(BasicMidiEffect VERSION 0.0.1) 2 | 3 | set (BaseTargetName ${PROJECT_NAME}) 4 | 5 | juce_add_plugin("${BaseTargetName}" 6 | # VERSION ... # Set this if the plugin version is different to the project version 7 | # ICON_BIG ... # ICON_* arguments specify a path to an image file to use as an icon for the Standalone 8 | # ICON_SMALL ... 9 | COMPANY_NAME "AudioDevExamples" 10 | IS_SYNTH FALSE 11 | NEEDS_MIDI_INPUT TRUE 12 | NEEDS_MIDI_OUTPUT TRUE 13 | IS_MIDI_EFFECT FALSE 14 | EDITOR_WANTS_KEYBOARD_FOCUS FALSE 15 | COPY_PLUGIN_AFTER_BUILD TRUE 16 | PLUGIN_MANUFACTURER_CODE ADex 17 | PLUGIN_CODE BMfx 18 | FORMATS AU VST3 Standalone 19 | PRODUCT_NAME "Basic Midi Effect") 20 | 21 | juce_generate_juce_header(${BaseTargetName}) 22 | 23 | target_sources(${BaseTargetName} PRIVATE 24 | Source/PluginProcessor.cpp 25 | Source/PluginEditor.cpp 26 | Source/MidiProcessor.cpp) 27 | 28 | target_compile_definitions(${BaseTargetName} PUBLIC 29 | JUCE_WEB_BROWSER=0 30 | JUCE_USE_CURL=0 31 | JUCE_VST3_CAN_REPLACE_VST2=0 32 | JucePlugin_PreferredChannelConfigurations={1,2},{2,2}) 33 | 34 | target_link_libraries(${BaseTargetName} PRIVATE juce::juce_audio_utils) 35 | -------------------------------------------------------------------------------- /Plugins/BasicMidiEffect/MidiEffect.jucer: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 10 | 11 | 13 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /Plugins/BasicMidiEffect/Source/MidiProcessor.cpp: -------------------------------------------------------------------------------- 1 | #include "MidiProcessor.h" 2 | 3 | constexpr int interval = 4; 4 | 5 | void MidiProcessor::process(MidiBuffer& midiMessages) 6 | { 7 | processedBuffer.clear(); 8 | processMidiInput(midiMessages); 9 | midiMessages.swapWith(processedBuffer); 10 | } 11 | 12 | void MidiProcessor::processMidiInput(const MidiBuffer& midiMessages) 13 | { 14 | //new JUCE 6 way of iterating through the midi buffer: 15 | for (auto message: midiMessages) 16 | addTransposedNote(message.getMessage(), message.samplePosition); 17 | } 18 | 19 | void MidiProcessor::addTransposedNote(MidiMessage messageToTranspose, int samplePos) 20 | { 21 | //Adds the original event first 22 | processedBuffer.addEvent(messageToTranspose, samplePos); 23 | 24 | auto oldNoteNum = messageToTranspose.getNoteNumber(); 25 | messageToTranspose.setNoteNumber(oldNoteNum + interval); 26 | 27 | processedBuffer.addEvent(messageToTranspose, samplePos); 28 | } 29 | -------------------------------------------------------------------------------- /Plugins/BasicMidiEffect/Source/MidiProcessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "JuceHeader.h" 4 | 5 | //A very simple class, that takes a midi buffer and adds another note 6 | //At at fixed interval for each incoming note on or off: 7 | 8 | class MidiProcessor 9 | { 10 | public: 11 | void process(MidiBuffer& midiMessages); 12 | 13 | private: 14 | 15 | void processMidiInput(const MidiBuffer& midiMessages); 16 | void addTransposedNote(MidiMessage messageToTranspose, int samplePos); 17 | 18 | //We create a temporary buffer that represents our changes 19 | MidiBuffer processedBuffer; 20 | }; -------------------------------------------------------------------------------- /Plugins/BasicMidiEffect/Source/PluginEditor.cpp: -------------------------------------------------------------------------------- 1 | #include "PluginProcessor.h" 2 | #include "PluginEditor.h" 3 | 4 | MidiEffectAudioProcessorEditor::MidiEffectAudioProcessorEditor (MidiEffectAudioProcessor& p) 5 | : AudioProcessorEditor (&p), processor (p) 6 | { 7 | // Make sure that before the constructor has finished, you've set the 8 | // editor's size to whatever you need it to be. 9 | setSize (400, 300); 10 | } 11 | 12 | MidiEffectAudioProcessorEditor::~MidiEffectAudioProcessorEditor() 13 | { 14 | } 15 | 16 | //============================================================================== 17 | void MidiEffectAudioProcessorEditor::paint (Graphics& g) 18 | { 19 | // (Our component is opaque, so we must completely fill the background with a solid colour) 20 | g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId)); 21 | 22 | g.setColour (Colours::white); 23 | g.setFont (15.0f); 24 | g.drawFittedText ("Midi Transpose effect", getLocalBounds(), Justification::centred, 1); 25 | } 26 | 27 | void MidiEffectAudioProcessorEditor::resized() 28 | { 29 | // This is generally where you'll want to lay out the positions of any 30 | // subcomponents in your editor.. 31 | } 32 | -------------------------------------------------------------------------------- /Plugins/BasicMidiEffect/Source/PluginEditor.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | 4 | This file was auto-generated! 5 | 6 | It contains the basic framework code for a JUCE plugin editor. 7 | 8 | ============================================================================== 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "../JuceLibraryCode/JuceHeader.h" 14 | #include "PluginProcessor.h" 15 | 16 | //============================================================================== 17 | /** 18 | */ 19 | class MidiEffectAudioProcessorEditor : public AudioProcessorEditor 20 | { 21 | public: 22 | MidiEffectAudioProcessorEditor (MidiEffectAudioProcessor&); 23 | ~MidiEffectAudioProcessorEditor(); 24 | 25 | //============================================================================== 26 | void paint (Graphics&) override; 27 | void resized() override; 28 | 29 | private: 30 | // This reference is provided as a quick way for your editor to 31 | // access the processor object that created it. 32 | MidiEffectAudioProcessor& processor; 33 | 34 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiEffectAudioProcessorEditor) 35 | }; 36 | -------------------------------------------------------------------------------- /Plugins/BasicMidiEffect/Source/PluginProcessor.cpp: -------------------------------------------------------------------------------- 1 | #include "PluginProcessor.h" 2 | #include "PluginEditor.h" 3 | 4 | MidiEffectAudioProcessor::MidiEffectAudioProcessor() 5 | #ifndef JucePlugin_PreferredChannelConfigurations 6 | : AudioProcessor (BusesProperties() 7 | #if ! JucePlugin_IsMidiEffect 8 | #if ! JucePlugin_IsSynth 9 | .withInput ("Input", AudioChannelSet::stereo(), true) 10 | #endif 11 | .withOutput ("Output", AudioChannelSet::stereo(), true) 12 | #endif 13 | ) 14 | #endif 15 | { 16 | } 17 | 18 | //============================================================================== 19 | const String MidiEffectAudioProcessor::getName() const 20 | { 21 | return JucePlugin_Name; 22 | } 23 | 24 | bool MidiEffectAudioProcessor::acceptsMidi() const 25 | { 26 | #if JucePlugin_WantsMidiInput 27 | return true; 28 | #else 29 | return false; 30 | #endif 31 | } 32 | 33 | bool MidiEffectAudioProcessor::producesMidi() const 34 | { 35 | #if JucePlugin_ProducesMidiOutput 36 | return true; 37 | #else 38 | return false; 39 | #endif 40 | } 41 | 42 | bool MidiEffectAudioProcessor::isMidiEffect() const 43 | { 44 | #if JucePlugin_IsMidiEffect 45 | return true; 46 | #else 47 | return false; 48 | #endif 49 | } 50 | 51 | double MidiEffectAudioProcessor::getTailLengthSeconds() const 52 | { 53 | return 0.0; 54 | } 55 | 56 | int MidiEffectAudioProcessor::getNumPrograms() 57 | { 58 | return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs, 59 | // so this should be at least 1, even if you're not really implementing programs. 60 | } 61 | 62 | int MidiEffectAudioProcessor::getCurrentProgram() 63 | { 64 | return 0; 65 | } 66 | 67 | void MidiEffectAudioProcessor::setCurrentProgram (int index) 68 | { 69 | } 70 | 71 | const String MidiEffectAudioProcessor::getProgramName (int index) 72 | { 73 | return {}; 74 | } 75 | 76 | void MidiEffectAudioProcessor::changeProgramName (int index, const String& newName) 77 | { 78 | } 79 | 80 | //============================================================================== 81 | void MidiEffectAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) 82 | { 83 | // Use this method as the place to do any pre-playback 84 | // initialisation that you need.. 85 | } 86 | 87 | void MidiEffectAudioProcessor::releaseResources() 88 | { 89 | // When playback stops, you can use this as an opportunity to free up any 90 | // spare memory, etc. 91 | } 92 | 93 | #ifndef JucePlugin_PreferredChannelConfigurations 94 | bool MidiEffectAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const 95 | { 96 | #if JucePlugin_IsMidiEffect 97 | ignoreUnused (layouts); 98 | return true; 99 | #else 100 | // This is the place where you check if the layout is supported. 101 | // In this template code we only support mono or stereo. 102 | if (layouts.getMainOutputChannelSet() != AudioChannelSet::mono() 103 | && layouts.getMainOutputChannelSet() != AudioChannelSet::stereo()) 104 | return false; 105 | 106 | // This checks if the input layout matches the output layout 107 | #if ! JucePlugin_IsSynth 108 | if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet()) 109 | return false; 110 | #endif 111 | 112 | return true; 113 | #endif 114 | } 115 | #endif 116 | 117 | void MidiEffectAudioProcessor::processBlock (AudioBuffer& buffer, MidiBuffer& midiMessages) 118 | { 119 | //Clearing the buffer to mute any audio that might come in 120 | buffer.clear(); 121 | 122 | //Only forwarding the call to the actual processor: 123 | midiProcessor.process(midiMessages); 124 | } 125 | 126 | //============================================================================== 127 | bool MidiEffectAudioProcessor::hasEditor() const 128 | { 129 | return true; // (change this to false if you choose to not supply an editor) 130 | } 131 | 132 | AudioProcessorEditor* MidiEffectAudioProcessor::createEditor() 133 | { 134 | return new MidiEffectAudioProcessorEditor (*this); 135 | } 136 | 137 | //============================================================================== 138 | void MidiEffectAudioProcessor::getStateInformation (MemoryBlock& destData) 139 | { 140 | // You should use this method to store your parameters in the memory block. 141 | // You could do that either as raw data, or use the XML or ValueTree classes 142 | // as intermediaries to make it easy to save and load complex data. 143 | } 144 | 145 | void MidiEffectAudioProcessor::setStateInformation (const void* data, int sizeInBytes) 146 | { 147 | // You should use this method to restore your parameters from this memory block, 148 | // whose contents will have been created by the getStateInformation() call. 149 | } 150 | 151 | //============================================================================== 152 | // This creates new instances of the plugin.. 153 | AudioProcessor* JUCE_CALLTYPE createPluginFilter() 154 | { 155 | return new MidiEffectAudioProcessor(); 156 | } 157 | -------------------------------------------------------------------------------- /Plugins/BasicMidiEffect/Source/PluginProcessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "JuceHeader.h" 4 | #include "MidiProcessor.h" 5 | 6 | /* This is a very basic project, just showing how to create a simple 7 | * midi processing effect. All the processor does here is forward the 8 | * processing call to a MidiProcessor object, that adds an interval 9 | * to each incoming note 10 | * */ 11 | 12 | //#undef JucePlugin_IsMidiEffect 13 | //#if JucePlugin_Build_AU 14 | //#define JucePlugin_IsMidiEffect 1 15 | //#else 16 | //#define JucePlugin_IsMidiEffect 0 17 | //#endif 18 | 19 | class MidiEffectAudioProcessor : public AudioProcessor 20 | { 21 | public: 22 | MidiEffectAudioProcessor(); 23 | 24 | //============================================================================== 25 | void prepareToPlay (double sampleRate, int samplesPerBlock) override; 26 | void releaseResources() override; 27 | 28 | #ifndef JucePlugin_PreferredChannelConfigurations 29 | bool isBusesLayoutSupported (const BusesLayout& layouts) const override; 30 | #endif 31 | 32 | void processBlock (AudioBuffer&, MidiBuffer&) override; 33 | 34 | //============================================================================== 35 | AudioProcessorEditor* createEditor() override; 36 | bool hasEditor() const override; 37 | 38 | //============================================================================== 39 | const String getName() const override; 40 | 41 | bool acceptsMidi() const override; 42 | bool producesMidi() const override; 43 | bool isMidiEffect() const override; 44 | double getTailLengthSeconds() const override; 45 | 46 | //============================================================================== 47 | int getNumPrograms() override; 48 | int getCurrentProgram() override; 49 | void setCurrentProgram (int index) override; 50 | const String getProgramName (int index) override; 51 | void changeProgramName (int index, const String& newName) override; 52 | 53 | //============================================================================== 54 | void getStateInformation (MemoryBlock& destData) override; 55 | void setStateInformation (const void* data, int sizeInBytes) override; 56 | 57 | private: 58 | 59 | //This is the actual processor that does something with midi events: 60 | MidiProcessor midiProcessor; 61 | 62 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiEffectAudioProcessor) 63 | }; 64 | -------------------------------------------------------------------------------- /Plugins/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(BasicMidiEffect) 2 | add_subdirectory(DynamicParameters) -------------------------------------------------------------------------------- /Plugins/DynamicParameters/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(DynamicParameters VERSION 0.0.1) 2 | 3 | set (BaseTargetName ${PROJECT_NAME}) 4 | 5 | juce_add_plugin("${BaseTargetName}" 6 | # VERSION ... # Set this if the plugin version is different to the project version 7 | # ICON_BIG ... # ICON_* arguments specify a path to an image file to use as an icon for the Standalone 8 | # ICON_SMALL ... 9 | COMPANY_NAME "AudioDevExamples" 10 | IS_SYNTH FALSE 11 | NEEDS_MIDI_INPUT FALSE 12 | NEEDS_MIDI_OUTPUT FALSE 13 | IS_MIDI_EFFECT FALSE 14 | EDITOR_WANTS_KEYBOARD_FOCUS FALSE 15 | COPY_PLUGIN_AFTER_BUILD TRUE 16 | PLUGIN_MANUFACTURER_CODE ADex 17 | PLUGIN_CODE DYpm 18 | FORMATS AU VST3 Standalone 19 | PRODUCT_NAME "Dynamic Parameters") 20 | 21 | juce_generate_juce_header(${BaseTargetName}) 22 | 23 | target_sources(${BaseTargetName} PRIVATE 24 | Source/PluginProcessor.cpp 25 | Source/PluginEditor.cpp) 26 | 27 | target_compile_definitions(${BaseTargetName} PUBLIC 28 | JUCE_WEB_BROWSER=0 29 | JUCE_USE_CURL=0 30 | JUCE_VST3_CAN_REPLACE_VST2=0 31 | JucePlugin_PreferredChannelConfigurations={1,2},{2,2}) 32 | 33 | target_link_libraries(${BaseTargetName} PRIVATE juce::juce_audio_utils) 34 | -------------------------------------------------------------------------------- /Plugins/DynamicParameters/DynamicParameters.jucer: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 9 | 11 | 13 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /Plugins/DynamicParameters/Source/CustomProcessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ParameterHelpers.h" 4 | 5 | using Layout = AudioProcessorValueTreeState::ParameterLayout; 6 | 7 | //A parameter class, meant to help the processor with creating and caching 8 | //The parameters, and hand them as a ParameterLayout for use by the plugin 9 | struct ProcessorParams 10 | { 11 | void addParams(Layout& layout, 12 | const String& prefix = String()) 13 | { 14 | ParameterList list(layout); 15 | 16 | //Create all your processor parameters, in this case appending the processor name: 17 | bypass = list.addNamed(prefix + "Bypass", false); 18 | gain = list.addNamed(prefix + "Gain", 0.0f, 1.0f, 0.1f); 19 | 20 | //When exiting the scope, parameters will be added to the given layout 21 | } 22 | 23 | //A cached version of the parameter you can use in the process block 24 | AudioParameterFloat* gain = nullptr; 25 | AudioParameterBool* bypass = nullptr; 26 | }; 27 | 28 | //A simple processor class, only applying simple gain, and possibly bypassed 29 | //Reads the value from the cached parameter pointers in the ProcessorParams class 30 | struct Processor 31 | { 32 | void process(AudioBuffer& buffer) 33 | { 34 | if (!params.bypass->get()) 35 | buffer.applyGain(params.gain->get()); 36 | } 37 | 38 | ProcessorParams params; 39 | }; 40 | 41 | //A simple chainer class, providing an interface for the processor to get the 42 | //parameter layout from all processors combined, and later call process() 43 | //on all of them: 44 | 45 | struct Processors 46 | { 47 | Layout getLayout() 48 | { 49 | Layout layout; 50 | 51 | int index = 0; 52 | 53 | for (auto& processor: processors) 54 | { 55 | //Creates the processor name using some prefix and it's index 56 | String processorName = "Processor " + String(index++) + " "; 57 | 58 | //Asks each processor to add it's own parameters 59 | processor.params.addParams(layout, processorName); 60 | } 61 | 62 | return layout; 63 | } 64 | 65 | //Simple forwarding to the actual processing functions 66 | void process(AudioBuffer& buffer) 67 | { 68 | for (auto& processor: processors) 69 | processor.process(buffer); 70 | } 71 | 72 | Processor processors[3]; 73 | }; -------------------------------------------------------------------------------- /Plugins/DynamicParameters/Source/ParameterHelpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "JuceHeader.h" 4 | 5 | /* 6 | A little helper class to simplify creating a new parameter list, 7 | caching it and saving it to a parameter layout. 8 | 9 | Use it in a scoped way: 10 | 11 | void addParams(AudioProcessorValueTreeState::ParameterLayout& layout) 12 | { 13 | ParameterList list; 14 | 15 | gain = list.add("Gain", "Gain", 0.0f, 1.0f, 0.1f); 16 | bypass = list.addNamed("Bypass", false); 17 | } 18 | */ 19 | class ParameterList 20 | { 21 | public: 22 | //Constructor: stores a reference to the ParameterLayout 23 | //During the destructor, all parameters added using add() or addNamed() 24 | //Will be added to the layout 25 | explicit ParameterList( 26 | AudioProcessorValueTreeState::ParameterLayout& layoutToUse) 27 | : layout(layoutToUse) 28 | { 29 | } 30 | 31 | //Destructor: only here values will be added to the layout 32 | ~ParameterList() { layout.add(params.begin(), params.end()); } 33 | 34 | //Adds the parameter to the list, returning a pointer to it 35 | //which you can store for future reference in your processor 36 | template 37 | T* add(Args&&... args) 38 | { 39 | auto newParam = new T(std::forward(args)...); 40 | params.emplace_back(newParam); 41 | 42 | return newParam; 43 | } 44 | 45 | //Similar to add(), but also copies the value used for parameterID field 46 | //into the name field, to avoid code duplication 47 | template 48 | T* addNamed(const ParamName& name, Args&&... args) 49 | { 50 | return add(name, name, std::forward(args)...); 51 | } 52 | 53 | private: 54 | AudioProcessorValueTreeState::ParameterLayout& layout; 55 | std::vector> params; 56 | }; 57 | -------------------------------------------------------------------------------- /Plugins/DynamicParameters/Source/PluginEditor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | 4 | This file was auto-generated! 5 | 6 | It contains the basic framework code for a JUCE plugin editor. 7 | 8 | ============================================================================== 9 | */ 10 | 11 | #include "PluginProcessor.h" 12 | #include "PluginEditor.h" 13 | 14 | //============================================================================== 15 | DynamicParametersAudioProcessorEditor::DynamicParametersAudioProcessorEditor (DynamicParametersAudioProcessor& p) 16 | : AudioProcessorEditor (&p), processor (p) 17 | { 18 | // Make sure that before the constructor has finished, you've set the 19 | // editor's size to whatever you need it to be. 20 | setSize (400, 300); 21 | } 22 | 23 | DynamicParametersAudioProcessorEditor::~DynamicParametersAudioProcessorEditor() 24 | { 25 | } 26 | 27 | //============================================================================== 28 | void DynamicParametersAudioProcessorEditor::paint (Graphics& g) 29 | { 30 | // (Our component is opaque, so we must completely fill the background with a solid colour) 31 | g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId)); 32 | 33 | g.setColour (Colours::white); 34 | g.setFont (15.0f); 35 | g.drawFittedText ("Hello World!", getLocalBounds(), Justification::centred, 1); 36 | } 37 | 38 | void DynamicParametersAudioProcessorEditor::resized() 39 | { 40 | // This is generally where you'll want to lay out the positions of any 41 | // subcomponents in your editor.. 42 | } 43 | -------------------------------------------------------------------------------- /Plugins/DynamicParameters/Source/PluginEditor.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | 4 | This file was auto-generated! 5 | 6 | It contains the basic framework code for a JUCE plugin editor. 7 | 8 | ============================================================================== 9 | */ 10 | 11 | #pragma once 12 | 13 | #include "../JuceLibraryCode/JuceHeader.h" 14 | #include "PluginProcessor.h" 15 | 16 | //============================================================================== 17 | /** 18 | */ 19 | class DynamicParametersAudioProcessorEditor : public AudioProcessorEditor 20 | { 21 | public: 22 | DynamicParametersAudioProcessorEditor (DynamicParametersAudioProcessor&); 23 | ~DynamicParametersAudioProcessorEditor(); 24 | 25 | //============================================================================== 26 | void paint (Graphics&) override; 27 | void resized() override; 28 | 29 | private: 30 | // This reference is provided as a quick way for your editor to 31 | // access the processor object that created it. 32 | DynamicParametersAudioProcessor& processor; 33 | 34 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DynamicParametersAudioProcessorEditor) 35 | }; 36 | -------------------------------------------------------------------------------- /Plugins/DynamicParameters/Source/PluginProcessor.cpp: -------------------------------------------------------------------------------- 1 | #include "PluginProcessor.h" 2 | #include "PluginEditor.h" 3 | 4 | //============================================================================== 5 | DynamicParametersAudioProcessor::DynamicParametersAudioProcessor() 6 | #ifndef JucePlugin_PreferredChannelConfigurations 7 | : AudioProcessor(BusesProperties() 8 | #if !JucePlugin_IsMidiEffect 9 | #if !JucePlugin_IsSynth 10 | .withInput("Input", AudioChannelSet::stereo(), true) 11 | #endif 12 | .withOutput("Output", AudioChannelSet::stereo(), true) 13 | #endif 14 | ) 15 | #endif 16 | { 17 | } 18 | 19 | //============================================================================== 20 | const String DynamicParametersAudioProcessor::getName() const 21 | { 22 | return JucePlugin_Name; 23 | } 24 | 25 | bool DynamicParametersAudioProcessor::acceptsMidi() const 26 | { 27 | #if JucePlugin_WantsMidiInput 28 | return true; 29 | #else 30 | return false; 31 | #endif 32 | } 33 | 34 | bool DynamicParametersAudioProcessor::producesMidi() const 35 | { 36 | #if JucePlugin_ProducesMidiOutput 37 | return true; 38 | #else 39 | return false; 40 | #endif 41 | } 42 | 43 | bool DynamicParametersAudioProcessor::isMidiEffect() const 44 | { 45 | #if JucePlugin_IsMidiEffect 46 | return true; 47 | #else 48 | return false; 49 | #endif 50 | } 51 | 52 | double DynamicParametersAudioProcessor::getTailLengthSeconds() const 53 | { 54 | return 0.0; 55 | } 56 | 57 | int DynamicParametersAudioProcessor::getNumPrograms() 58 | { 59 | return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs, 60 | // so this should be at least 1, even if you're not really implementing programs. 61 | } 62 | 63 | int DynamicParametersAudioProcessor::getCurrentProgram() 64 | { 65 | return 0; 66 | } 67 | 68 | void DynamicParametersAudioProcessor::setCurrentProgram(int index) 69 | { 70 | } 71 | 72 | const String DynamicParametersAudioProcessor::getProgramName(int index) 73 | { 74 | return {}; 75 | } 76 | 77 | void DynamicParametersAudioProcessor::changeProgramName(int index, 78 | const String& newName) 79 | { 80 | } 81 | 82 | //============================================================================== 83 | void DynamicParametersAudioProcessor::prepareToPlay(double sampleRate, 84 | int samplesPerBlock) 85 | { 86 | // Use this method as the place to do any pre-playback 87 | // initialisation that you need.. 88 | } 89 | 90 | void DynamicParametersAudioProcessor::releaseResources() 91 | { 92 | // When playback stops, you can use this as an opportunity to free up any 93 | // spare memory, etc. 94 | } 95 | 96 | #ifndef JucePlugin_PreferredChannelConfigurations 97 | bool DynamicParametersAudioProcessor::isBusesLayoutSupported( 98 | const BusesLayout& layouts) const 99 | { 100 | #if JucePlugin_IsMidiEffect 101 | ignoreUnused(layouts); 102 | return true; 103 | #else 104 | // This is the place where you check if the layout is supported. 105 | // In this template code we only support mono or stereo. 106 | if (layouts.getMainOutputChannelSet() != AudioChannelSet::mono() 107 | && layouts.getMainOutputChannelSet() != AudioChannelSet::stereo()) 108 | return false; 109 | 110 | // This checks if the input layout matches the output layout 111 | #if !JucePlugin_IsSynth 112 | if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet()) 113 | return false; 114 | #endif 115 | 116 | return true; 117 | #endif 118 | } 119 | #endif 120 | 121 | void DynamicParametersAudioProcessor::processBlock(AudioBuffer& buffer, 122 | MidiBuffer& midiMessages) 123 | { 124 | processors.process(buffer); 125 | } 126 | 127 | //============================================================================== 128 | bool DynamicParametersAudioProcessor::hasEditor() const 129 | { 130 | return true; // (change this to false if you choose to not supply an editor) 131 | } 132 | 133 | AudioProcessorEditor* DynamicParametersAudioProcessor::createEditor() 134 | { 135 | return new GenericAudioProcessorEditor(*this); 136 | } 137 | 138 | //============================================================================== 139 | void DynamicParametersAudioProcessor::getStateInformation(MemoryBlock& destData) 140 | { 141 | // You should use this method to store your parameters in the memory block. 142 | // You could do that either as raw data, or use the XML or ValueTree classes 143 | // as intermediaries to make it easy to save and load complex data. 144 | } 145 | 146 | void DynamicParametersAudioProcessor::setStateInformation(const void* data, 147 | int sizeInBytes) 148 | { 149 | // You should use this method to restore your parameters from this memory block, 150 | // whose contents will have been created by the getStateInformation() call. 151 | } 152 | 153 | //============================================================================== 154 | // This creates new instances of the plugin.. 155 | AudioProcessor* JUCE_CALLTYPE createPluginFilter() 156 | { 157 | return new DynamicParametersAudioProcessor(); 158 | } 159 | -------------------------------------------------------------------------------- /Plugins/DynamicParameters/Source/PluginProcessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "JuceHeader.h" 4 | #include "CustomProcessor.h" 5 | 6 | 7 | //This process class does very little. 8 | //All it does is initialize the Processors class, and the 9 | //AudioProcessorValueTreeState class, which grabs the parameters from the Processors. 10 | // 11 | //Later, it's forwarding the processBlock call to the Processors class 12 | // 13 | //Look at CustomProcessor.h for more info: 14 | //============================================================================== 15 | /** 16 | */ 17 | class DynamicParametersAudioProcessor : public AudioProcessor 18 | { 19 | public: 20 | //============================================================================== 21 | DynamicParametersAudioProcessor(); 22 | 23 | //============================================================================== 24 | void prepareToPlay(double sampleRate, int samplesPerBlock) override; 25 | void releaseResources() override; 26 | 27 | #ifndef JucePlugin_PreferredChannelConfigurations 28 | bool isBusesLayoutSupported(const BusesLayout& layouts) const override; 29 | #endif 30 | 31 | void processBlock(AudioBuffer&, MidiBuffer&) override; 32 | 33 | //============================================================================== 34 | AudioProcessorEditor* createEditor() override; 35 | bool hasEditor() const override; 36 | 37 | //============================================================================== 38 | const String getName() const override; 39 | 40 | bool acceptsMidi() const override; 41 | bool producesMidi() const override; 42 | bool isMidiEffect() const override; 43 | double getTailLengthSeconds() const override; 44 | 45 | //============================================================================== 46 | int getNumPrograms() override; 47 | int getCurrentProgram() override; 48 | void setCurrentProgram(int index) override; 49 | const String getProgramName(int index) override; 50 | void changeProgramName(int index, const String& newName) override; 51 | 52 | //============================================================================== 53 | void getStateInformation(MemoryBlock& destData) override; 54 | void setStateInformation(const void* data, int sizeInBytes) override; 55 | 56 | private: 57 | 58 | Processors processors; 59 | AudioProcessorValueTreeState state { 60 | *this, nullptr, "GainProcessors", processors.getLayout()}; 61 | 62 | //============================================================================== 63 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DynamicParametersAudioProcessor) 64 | }; 65 | -------------------------------------------------------------------------------- /Standalone/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(LoadingSVG) 2 | add_subdirectory(ConsoleToot) -------------------------------------------------------------------------------- /Standalone/ConsoleToot/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(ConsoleToot VERSION 0.1) 2 | 3 | set (TargetName ${PROJECT_NAME}) 4 | 5 | juce_add_console_app(${TargetName} PRODUCT_NAME "Console Toot") 6 | juce_generate_juce_header(${TargetName}) 7 | 8 | target_sources(${TargetName} PRIVATE Source/Main.cpp) 9 | 10 | target_compile_definitions(${TargetName} PRIVATE 11 | JUCE_WEB_BROWSER=0 12 | JUCE_USE_CURL=0) 13 | 14 | target_link_libraries(${TargetName} PRIVATE juce::juce_audio_utils) 15 | -------------------------------------------------------------------------------- /Standalone/ConsoleToot/ConsoleToot.jucer: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Standalone/ConsoleToot/README.md: -------------------------------------------------------------------------------- 1 | Very minimal Juce command line program example that plays audio. 2 | -------------------------------------------------------------------------------- /Standalone/ConsoleToot/Source/Main.cpp: -------------------------------------------------------------------------------- 1 | #include "JuceHeader.h" 2 | 3 | class MyCallback : public AudioIODeviceCallback 4 | { 5 | public: 6 | void audioDeviceIOCallback(const float** inputChannelData, 7 | int numInputChannels, 8 | float** outputChannelData, 9 | int numOutputChannels, 10 | int numSamples) override 11 | { 12 | for (int i = 0; i < numSamples; ++i) 13 | { 14 | float s = gain * sin(phase); 15 | 16 | for (int j = 0; j < numOutputChannels; ++j) 17 | { 18 | outputChannelData[j][i] = s; 19 | } 20 | 21 | phase += (freq / sampleRate) * juce::MathConstants::twoPi; 22 | } 23 | } 24 | 25 | void audioDeviceAboutToStart(AudioIODevice* device) override 26 | { 27 | phase = 0.f; 28 | sampleRate = (float) device->getCurrentSampleRate(); 29 | } 30 | 31 | void audioDeviceStopped() override {} 32 | 33 | private: 34 | float freq = 440.f; 35 | float gain = 0.1f; 36 | float phase = 0.f; 37 | float sampleRate = 0.f; 38 | }; 39 | 40 | int main(int argc, char* argv[]) 41 | { 42 | // not used for "GUI" in this case, 43 | // just for initing and shutting down the MessageManager 44 | ScopedJuceInitialiser_GUI gui_init; 45 | AudioDeviceManager aman; 46 | 47 | String err = aman.initialiseWithDefaultDevices(0, 2); 48 | 49 | if (err.isEmpty()) 50 | { 51 | std::cout << "device opened : " << aman.getCurrentAudioDevice()->getName() 52 | << "\n"; 53 | MyCallback cb; 54 | aman.addAudioCallback(&cb); 55 | 56 | // keep the program running so the audio has a chance to play: 57 | Thread::sleep(2000); 58 | std::cout << "closing device...\n"; 59 | } 60 | else 61 | std::cout << "could not open device : " << err << "\n"; 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /Standalone/LoadingSVG/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(LoadingSVG VERSION 0.0.1) 2 | 3 | set (TargetName ${PROJECT_NAME}) 4 | 5 | juce_add_gui_app(${TargetName} PRODUCT_NAME "Loading SVG") 6 | juce_generate_juce_header(${TargetName}) 7 | 8 | target_sources(${TargetName} PRIVATE 9 | Source/Main.cpp) 10 | 11 | target_compile_definitions(${TargetName} PRIVATE 12 | JUCE_WEB_BROWSER=0 13 | JUCE_USE_CURL=0 14 | JUCE_APPLICATION_NAME_STRING="$" 15 | JUCE_APPLICATION_VERSION_STRING="$") 16 | 17 | target_link_libraries(${TargetName} PRIVATE juce::juce_gui_extra) 18 | -------------------------------------------------------------------------------- /Standalone/LoadingSVG/LoadingSVG.jucer: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Standalone/LoadingSVG/Source/Main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================== 3 | 4 | This file was auto-generated! 5 | 6 | It contains the basic startup code for a JUCE application. 7 | 8 | ============================================================================== 9 | */ 10 | 11 | #include "../JuceLibraryCode/JuceHeader.h" 12 | #include "MainComponent.h" 13 | 14 | //============================================================================== 15 | class LoadingSVGApplication : public JUCEApplication 16 | { 17 | public: 18 | //============================================================================== 19 | LoadingSVGApplication() {} 20 | 21 | const String getApplicationName() override { return ProjectInfo::projectName; } 22 | const String getApplicationVersion() override { return ProjectInfo::versionString; } 23 | bool moreThanOneInstanceAllowed() override { return true; } 24 | 25 | //============================================================================== 26 | void initialise (const String& commandLine) override 27 | { 28 | // This method is where you should put your application's initialisation code.. 29 | 30 | mainWindow.reset (new MainWindow (getApplicationName())); 31 | } 32 | 33 | void shutdown() override 34 | { 35 | // Add your application's shutdown code here.. 36 | 37 | mainWindow = nullptr; // (deletes our window) 38 | } 39 | 40 | //============================================================================== 41 | void systemRequestedQuit() override 42 | { 43 | // This is called when the app is being asked to quit: you can ignore this 44 | // request and let the app carry on running, or call quit() to allow the app to close. 45 | quit(); 46 | } 47 | 48 | void anotherInstanceStarted (const String& commandLine) override 49 | { 50 | // When another instance of the app is launched while this one is running, 51 | // this method is invoked, and the commandLine parameter tells you what 52 | // the other instance's command-line arguments were. 53 | } 54 | 55 | //============================================================================== 56 | /* 57 | This class implements the desktop window that contains an instance of 58 | our MainComponent class. 59 | */ 60 | class MainWindow : public DocumentWindow 61 | { 62 | public: 63 | MainWindow (String name) : DocumentWindow (name, 64 | Desktop::getInstance().getDefaultLookAndFeel() 65 | .findColour (ResizableWindow::backgroundColourId), 66 | DocumentWindow::allButtons) 67 | { 68 | setUsingNativeTitleBar (true); 69 | setContentOwned (new MainComponent(), true); 70 | 71 | #if JUCE_IOS || JUCE_ANDROID 72 | setFullScreen (true); 73 | #else 74 | setResizable (true, true); 75 | centreWithSize (getWidth(), getHeight()); 76 | #endif 77 | 78 | setVisible (true); 79 | } 80 | 81 | void closeButtonPressed() override 82 | { 83 | // This is called when the user tries to close this window. Here, we'll just 84 | // ask the app to quit when this happens, but you can change this to do 85 | // whatever you need. 86 | JUCEApplication::getInstance()->systemRequestedQuit(); 87 | } 88 | 89 | /* Note: Be careful if you override any DocumentWindow methods - the base 90 | class uses a lot of them, so by overriding you might break its functionality. 91 | It's best to do all your work in your content component instead, but if 92 | you really have to override any DocumentWindow methods, make sure your 93 | subclass also calls the superclass's method. 94 | */ 95 | 96 | private: 97 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow) 98 | }; 99 | 100 | private: 101 | std::unique_ptr mainWindow; 102 | }; 103 | 104 | //============================================================================== 105 | // This macro generates the main() routine that launches the app. 106 | START_JUCE_APPLICATION (LoadingSVGApplication) 107 | -------------------------------------------------------------------------------- /Standalone/LoadingSVG/Source/MainComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "JuceHeader.h" 4 | #include "SVGDisplay.h" 5 | 6 | constexpr int loadButtonHeight = 50; 7 | 8 | class MainComponent 9 | : public Component 10 | , public FileDragAndDropTarget 11 | { 12 | public: 13 | MainComponent() 14 | { 15 | addAndMakeVisible(loadButton); 16 | addAndMakeVisible(stretchButton); 17 | 18 | loadButton.onClick = [&] { buttonClicked();}; 19 | stretchButton.onClick = [&] { stretchButtonClicked();}; 20 | 21 | setSize(600, 400); 22 | } 23 | 24 | bool isInterestedInFileDrag(const StringArray&) override { return true; } 25 | void filesDropped(const StringArray& files, int, int) override 26 | { 27 | loadImageFromFile(files[0]); 28 | } 29 | 30 | void resized() override 31 | { 32 | loadButton.setBounds(0, 0, 80, loadButtonHeight); 33 | stretchButton.setBounds(100, 0, 80, loadButtonHeight); 34 | 35 | if (svg != nullptr) 36 | { 37 | svg->setBounds(getLocalBounds() 38 | .withY(loadButtonHeight) 39 | .reduced(0, loadButtonHeight)); 40 | } 41 | } 42 | 43 | void stretchButtonClicked() 44 | { 45 | if (stretchButton.getToggleState()) 46 | placement = RectanglePlacement::stretchToFit; 47 | else 48 | placement = RectanglePlacement::doNotResize; 49 | 50 | repaint(); 51 | } 52 | 53 | void buttonClicked() 54 | { 55 | fc = std::make_unique("Load image file"); 56 | 57 | auto flags = 58 | FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles; 59 | 60 | auto callback = [this](const FileChooser& chooser) 61 | { 62 | auto result = chooser.getResult(); 63 | 64 | if (result.existsAsFile()) 65 | loadImageFromFile(result); 66 | }; 67 | 68 | fc->launchAsync(flags, callback); 69 | 70 | auto result = fc->getResult(); 71 | } 72 | 73 | private: 74 | void loadImageFromFile(const File& fileToLoad) 75 | { 76 | svg = std::make_unique(fileToLoad, placement); 77 | addAndMakeVisible(*svg); 78 | resized(); 79 | } 80 | 81 | TextButton loadButton {"Load File"}; 82 | ToggleButton stretchButton {"Stretch"}; 83 | RectanglePlacement placement = RectanglePlacement::doNotResize; 84 | std::unique_ptr svg; 85 | std::unique_ptr fc; 86 | 87 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainComponent) 88 | }; 89 | -------------------------------------------------------------------------------- /Standalone/LoadingSVG/Source/SVGDisplay.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "JuceHeader.h" 4 | 5 | class InvalidImageLabel : public Label 6 | { 7 | public: 8 | InvalidImageLabel() 9 | { 10 | setText("Invalid Image", dontSendNotification); 11 | setJustificationType(Justification::centred); 12 | } 13 | }; 14 | 15 | class SVGDisplayer : public Component 16 | { 17 | public: 18 | explicit SVGDisplayer(const File& fileToLoad, RectanglePlacement& placementToUse) 19 | : placement(placementToUse) 20 | { 21 | image = Drawable::createFromImageFile(fileToLoad); 22 | 23 | if (image == nullptr) 24 | addAndMakeVisible(invalidImageLabel); 25 | } 26 | 27 | void paint(Graphics& g) override 28 | { 29 | if (image != nullptr) 30 | image->drawWithin(g, getLocalBounds().toFloat(), placement, 1.f); 31 | } 32 | 33 | void resized() override 34 | { 35 | if (image == nullptr) 36 | invalidImageLabel.setBounds(getLocalBounds()); 37 | } 38 | 39 | InvalidImageLabel invalidImageLabel; 40 | std::unique_ptr image; 41 | RectanglePlacement& placement; 42 | }; -------------------------------------------------------------------------------- /_clang-format: -------------------------------------------------------------------------------- 1 | AccessModifierOffset: -4 2 | AlignAfterOpenBracket: Align 3 | AlignConsecutiveAssignments: false 4 | AlignConsecutiveDeclarations: false 5 | AlignOperands: true 6 | AlignTrailingComments: false 7 | AllowAllParametersOfDeclarationOnNextLine: true 8 | AllowShortBlocksOnASingleLine: true 9 | AllowShortCaseLabelsOnASingleLine: false 10 | AllowShortFunctionsOnASingleLine: InlineOnly 11 | AllowShortIfStatementsOnASingleLine: Never 12 | AllowShortLoopsOnASingleLine: false 13 | AlwaysBreakAfterDefinitionReturnType: None 14 | AlwaysBreakAfterReturnType: None 15 | AlwaysBreakBeforeMultilineStrings: false 16 | AlwaysBreakTemplateDeclarations: Yes 17 | BinPackArguments: false 18 | BinPackParameters: false 19 | BreakAfterJavaFieldAnnotations: false 20 | BreakBeforeBinaryOperators: NonAssignment 21 | BreakBeforeBraces: Allman 22 | BreakBeforeTernaryOperators: true 23 | BreakConstructorInitializers: BeforeComma 24 | BreakStringLiterals: false 25 | ColumnLimit: 85 26 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 27 | ConstructorInitializerIndentWidth: 4 28 | ContinuationIndentWidth: 4 29 | ExperimentalAutoDetectBinPacking: false 30 | IndentCaseLabels: true 31 | IndentWidth: 4 32 | IndentWrappedFunctionNames: true 33 | KeepEmptyLinesAtTheStartOfBlocks: false 34 | Language: Cpp 35 | MaxEmptyLinesToKeep: 1 36 | NamespaceIndentation: Inner 37 | PointerAlignment: Left 38 | ReflowComments: false 39 | SortIncludes: false 40 | SpaceAfterCStyleCast: true 41 | SpaceBeforeAssignmentOperators: true 42 | SpaceInEmptyParentheses: false 43 | SpacesInAngles: false 44 | SpacesInCStyleCastParentheses: false 45 | SpacesInContainerLiterals: true 46 | SpacesInParentheses: false 47 | SpacesInSquareBrackets: false 48 | Standard: Cpp11 49 | TabWidth: 4 50 | UseTab: Never 51 | SpaceBeforeCpp11BracedList: true 52 | Cpp11BracedListStyle: true 53 | BreakInheritanceList: BeforeComma 54 | SpaceBeforeRangeBasedForLoopColon: false 55 | BreakConstructorInitializersBeforeComma: true 56 | 57 | --------------------------------------------------------------------------------