├── .gitignore ├── CMakeLists.txt ├── README.md └── Source ├── PluginEditor.cpp ├── PluginEditor.h ├── PluginProcessor.cpp └── PluginProcessor.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | .DS_Store 35 | .idea/ 36 | Build/ 37 | build/ 38 | Builds/ 39 | builds/ 40 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.24) 2 | 3 | # Change to your project name 4 | project(SimpleJucePluginTemplate VERSION 0.0.1) 5 | 6 | 7 | set(CMAKE_CXX_STANDARD 17) 8 | set(CMAKE_XCODE_GENERATE_SCHEME OFF) 9 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 10 | 11 | # We're going to use CPM as our package manager to bring in JUCE 12 | # Check to see if we have CPM installed already. Bring it in if we don't. 13 | set(CPM_DOWNLOAD_VERSION 0.34.0) 14 | set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") 15 | 16 | if (NOT EXISTS ${CPM_DOWNLOAD_LOCATION}) 17 | message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}") 18 | file(DOWNLOAD https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake ${CPM_DOWNLOAD_LOCATION}) 19 | endif () 20 | 21 | include(${CPM_DOWNLOAD_LOCATION}) 22 | 23 | # Bring in JUCE locally 24 | CPMAddPackage( 25 | NAME juce 26 | GIT_REPOSITORY https://github.com/juce-framework/JUCE.git 27 | GIT_TAG origin/master 28 | ) 29 | 30 | # Make sure you include any new source files here 31 | set(SourceFiles 32 | Source/PluginEditor.cpp 33 | Source/PluginEditor.h 34 | Source/PluginProcessor.cpp 35 | Source/PluginProcessor.h 36 | ) 37 | 38 | # Change these to your own preferences 39 | juce_add_plugin(${PROJECT_NAME} 40 | COMPANY_NAME theaudioprogrammer 41 | IS_SYNTH FALSE 42 | NEEDS_MIDI_INPUT FALSE 43 | NEEDS_MIDI_OUTPUT FALSE 44 | IS_MIDI_EFFECT FALSE 45 | EDITOR_WANTS_KEYBOARD_FOCUS FALSE 46 | JUCE_VST3_CAN_REPLACE_VST2 FALSE 47 | COPY_PLUGIN_AFTER_BUILD TRUE 48 | PLUGIN_MANUFACTURER_CODE Tap1 49 | PLUGIN_CODE Reg0 50 | FORMATS VST3 AU Standalone 51 | PRODUCT_NAME "TapPluginTemplate" 52 | ) 53 | 54 | # How we want our SourceFiles to appear in our IDE 55 | source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SourceFiles}) 56 | 57 | # Make the SourceFiles buildable 58 | target_sources(${PROJECT_NAME} PRIVATE ${SourceFiles}) 59 | 60 | # These are some toggleable options from the JUCE CMake API 61 | target_compile_definitions(${PROJECT_NAME} 62 | PUBLIC 63 | JUCE_WEB_BROWSER=0 64 | JUCE_USE_CURL=0 65 | JUCE_VST3_CAN_REPLACE_VST2=0 66 | ) 67 | 68 | # JUCE libraries to bring into our project 69 | target_link_libraries(${PROJECT_NAME} 70 | PUBLIC 71 | juce::juce_analytics 72 | juce::juce_audio_basics 73 | juce::juce_audio_devices 74 | juce::juce_core 75 | juce::juce_data_structures 76 | juce::juce_graphics 77 | juce::juce_gui_basics 78 | juce::juce_gui_extra 79 | juce::juce_audio_utils 80 | juce::juce_dsp 81 | juce::juce_recommended_config_flags 82 | juce::juce_recommended_lto_flags 83 | juce::juce_recommended_warning_flags 84 | ) 85 | 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SimpleJucePluginTemplate -------------------------------------------------------------------------------- /Source/PluginEditor.cpp: -------------------------------------------------------------------------------- 1 | #include "PluginProcessor.h" 2 | #include "PluginEditor.h" 3 | 4 | //============================================================================== 5 | AudioPluginAudioProcessorEditor::AudioPluginAudioProcessorEditor (AudioPluginAudioProcessor& p) 6 | : AudioProcessorEditor (&p), processorRef (p) 7 | { 8 | juce::ignoreUnused (processorRef); 9 | // Make sure that before the constructor has finished, you've set the 10 | // editor's size to whatever you need it to be. 11 | setSize (400, 300); 12 | } 13 | 14 | AudioPluginAudioProcessorEditor::~AudioPluginAudioProcessorEditor() 15 | { 16 | } 17 | 18 | //============================================================================== 19 | void AudioPluginAudioProcessorEditor::paint (juce::Graphics& g) 20 | { 21 | // (Our component is opaque, so we must completely fill the background with a solid colour) 22 | g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId)); 23 | 24 | g.setColour (juce::Colours::white); 25 | g.setFont (15.0f); 26 | g.drawFittedText ("Hello World!", getLocalBounds(), juce::Justification::centred, 1); 27 | } 28 | 29 | void AudioPluginAudioProcessorEditor::resized() 30 | { 31 | // This is generally where you'll want to lay out the positions of any 32 | // subcomponents in your editor.. 33 | } 34 | -------------------------------------------------------------------------------- /Source/PluginEditor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PluginProcessor.h" 4 | 5 | //============================================================================== 6 | class AudioPluginAudioProcessorEditor final : public juce::AudioProcessorEditor 7 | { 8 | public: 9 | explicit AudioPluginAudioProcessorEditor (AudioPluginAudioProcessor&); 10 | ~AudioPluginAudioProcessorEditor() override; 11 | 12 | //============================================================================== 13 | void paint (juce::Graphics&) override; 14 | void resized() override; 15 | 16 | private: 17 | // This reference is provided as a quick way for your editor to 18 | // access the processor object that created it. 19 | AudioPluginAudioProcessor& processorRef; 20 | 21 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginAudioProcessorEditor) 22 | }; 23 | -------------------------------------------------------------------------------- /Source/PluginProcessor.cpp: -------------------------------------------------------------------------------- 1 | #include "PluginProcessor.h" 2 | #include "PluginEditor.h" 3 | 4 | //============================================================================== 5 | AudioPluginAudioProcessor::AudioPluginAudioProcessor() 6 | : AudioProcessor (BusesProperties() 7 | #if ! JucePlugin_IsMidiEffect 8 | #if ! JucePlugin_IsSynth 9 | .withInput ("Input", juce::AudioChannelSet::stereo(), true) 10 | #endif 11 | .withOutput ("Output", juce::AudioChannelSet::stereo(), true) 12 | #endif 13 | ) 14 | { 15 | } 16 | 17 | AudioPluginAudioProcessor::~AudioPluginAudioProcessor() 18 | { 19 | } 20 | 21 | //============================================================================== 22 | const juce::String AudioPluginAudioProcessor::getName() const 23 | { 24 | return JucePlugin_Name; 25 | } 26 | 27 | bool AudioPluginAudioProcessor::acceptsMidi() const 28 | { 29 | #if JucePlugin_WantsMidiInput 30 | return true; 31 | #else 32 | return false; 33 | #endif 34 | } 35 | 36 | bool AudioPluginAudioProcessor::producesMidi() const 37 | { 38 | #if JucePlugin_ProducesMidiOutput 39 | return true; 40 | #else 41 | return false; 42 | #endif 43 | } 44 | 45 | bool AudioPluginAudioProcessor::isMidiEffect() const 46 | { 47 | #if JucePlugin_IsMidiEffect 48 | return true; 49 | #else 50 | return false; 51 | #endif 52 | } 53 | 54 | double AudioPluginAudioProcessor::getTailLengthSeconds() const 55 | { 56 | return 0.0; 57 | } 58 | 59 | int AudioPluginAudioProcessor::getNumPrograms() 60 | { 61 | return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs, 62 | // so this should be at least 1, even if you're not really implementing programs. 63 | } 64 | 65 | int AudioPluginAudioProcessor::getCurrentProgram() 66 | { 67 | return 0; 68 | } 69 | 70 | void AudioPluginAudioProcessor::setCurrentProgram (int index) 71 | { 72 | juce::ignoreUnused (index); 73 | } 74 | 75 | const juce::String AudioPluginAudioProcessor::getProgramName (int index) 76 | { 77 | juce::ignoreUnused (index); 78 | return {}; 79 | } 80 | 81 | void AudioPluginAudioProcessor::changeProgramName (int index, const juce::String& newName) 82 | { 83 | juce::ignoreUnused (index, newName); 84 | } 85 | 86 | //============================================================================== 87 | void AudioPluginAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) 88 | { 89 | // Use this method as the place to do any pre-playback 90 | // initialisation that you need.. 91 | juce::ignoreUnused (sampleRate, samplesPerBlock); 92 | } 93 | 94 | void AudioPluginAudioProcessor::releaseResources() 95 | { 96 | // When playback stops, you can use this as an opportunity to free up any 97 | // spare memory, etc. 98 | } 99 | 100 | bool AudioPluginAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const 101 | { 102 | #if JucePlugin_IsMidiEffect 103 | juce::ignoreUnused (layouts); 104 | return true; 105 | #else 106 | // This is the place where you check if the layout is supported. 107 | // In this template code we only support mono or stereo. 108 | // Some plugin hosts, such as certain GarageBand versions, will only 109 | // load plugins that support stereo bus layouts. 110 | if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::mono() 111 | && layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo()) 112 | return false; 113 | 114 | // This checks if the input layout matches the output layout 115 | #if ! JucePlugin_IsSynth 116 | if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet()) 117 | return false; 118 | #endif 119 | 120 | return true; 121 | #endif 122 | } 123 | 124 | void AudioPluginAudioProcessor::processBlock (juce::AudioBuffer& buffer, 125 | juce::MidiBuffer& midiMessages) 126 | { 127 | juce::ignoreUnused (midiMessages); 128 | 129 | juce::ScopedNoDenormals noDenormals; 130 | auto totalNumInputChannels = getTotalNumInputChannels(); 131 | auto totalNumOutputChannels = getTotalNumOutputChannels(); 132 | 133 | // In case we have more outputs than inputs, this code clears any output 134 | // channels that didn't contain input data, (because these aren't 135 | // guaranteed to be empty - they may contain garbage). 136 | // This is here to avoid people getting screaming feedback 137 | // when they first compile a plugin, but obviously you don't need to keep 138 | // this code if your algorithm always overwrites all the output channels. 139 | for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) 140 | buffer.clear (i, 0, buffer.getNumSamples()); 141 | 142 | // This is the place where you'd normally do the guts of your plugin's 143 | // audio processing... 144 | // Make sure to reset the state if your inner loop is processing 145 | // the samples and the outer loop is handling the channels. 146 | // Alternatively, you can process the samples with the channels 147 | // interleaved by keeping the same state. 148 | for (int channel = 0; channel < totalNumInputChannels; ++channel) 149 | { 150 | auto* channelData = buffer.getWritePointer (channel); 151 | juce::ignoreUnused (channelData); 152 | // ..do something to the data... 153 | } 154 | } 155 | 156 | //============================================================================== 157 | bool AudioPluginAudioProcessor::hasEditor() const 158 | { 159 | return true; // (change this to false if you choose to not supply an editor) 160 | } 161 | 162 | juce::AudioProcessorEditor* AudioPluginAudioProcessor::createEditor() 163 | { 164 | return new AudioPluginAudioProcessorEditor (*this); 165 | } 166 | 167 | //============================================================================== 168 | void AudioPluginAudioProcessor::getStateInformation (juce::MemoryBlock& destData) 169 | { 170 | // You should use this method to store your parameters in the memory block. 171 | // You could do that either as raw data, or use the XML or ValueTree classes 172 | // as intermediaries to make it easy to save and load complex data. 173 | juce::ignoreUnused (destData); 174 | } 175 | 176 | void AudioPluginAudioProcessor::setStateInformation (const void* data, int sizeInBytes) 177 | { 178 | // You should use this method to restore your parameters from this memory block, 179 | // whose contents will have been created by the getStateInformation() call. 180 | juce::ignoreUnused (data, sizeInBytes); 181 | } 182 | 183 | //============================================================================== 184 | // This creates new instances of the plugin.. 185 | juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter() 186 | { 187 | return new AudioPluginAudioProcessor(); 188 | } 189 | -------------------------------------------------------------------------------- /Source/PluginProcessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | //============================================================================== 6 | class AudioPluginAudioProcessor final : public juce::AudioProcessor 7 | { 8 | public: 9 | //============================================================================== 10 | AudioPluginAudioProcessor(); 11 | ~AudioPluginAudioProcessor() override; 12 | 13 | //============================================================================== 14 | void prepareToPlay (double sampleRate, int samplesPerBlock) override; 15 | void releaseResources() override; 16 | 17 | bool isBusesLayoutSupported (const BusesLayout& layouts) const override; 18 | 19 | void processBlock (juce::AudioBuffer&, juce::MidiBuffer&) override; 20 | using AudioProcessor::processBlock; 21 | 22 | //============================================================================== 23 | juce::AudioProcessorEditor* createEditor() override; 24 | bool hasEditor() const override; 25 | 26 | //============================================================================== 27 | const juce::String getName() const override; 28 | 29 | bool acceptsMidi() const override; 30 | bool producesMidi() const override; 31 | bool isMidiEffect() const override; 32 | double getTailLengthSeconds() const override; 33 | 34 | //============================================================================== 35 | int getNumPrograms() override; 36 | int getCurrentProgram() override; 37 | void setCurrentProgram (int index) override; 38 | const juce::String getProgramName (int index) override; 39 | void changeProgramName (int index, const juce::String& newName) override; 40 | 41 | //============================================================================== 42 | void getStateInformation (juce::MemoryBlock& destData) override; 43 | void setStateInformation (const void* data, int sizeInBytes) override; 44 | 45 | private: 46 | //============================================================================== 47 | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginAudioProcessor) 48 | }; 49 | --------------------------------------------------------------------------------