├── .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 |
--------------------------------------------------------------------------------