commit f93946b61bce31ac83c94dfc0c559771628740c8 Author: LunarAkai Date: Fri Apr 24 00:33:52 2026 +0200 hello juce diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a46b0c8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +justfile +push_to_git.sh +/build \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9537e5b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,131 @@ +# Example Audio Plugin CMakeLists.txt + +# To get started on a new plugin, copy this entire folder (containing this file and C++ sources) to +# a convenient location, and then start making modifications. + +# The first line of any CMake project should be a call to `cmake_minimum_required`, which checks +# that the installed CMake will be able to understand the following CMakeLists, and ensures that +# CMake's behaviour is compatible with the named version. This is a standard CMake command, so more +# information can be found in the CMake docs. + +cmake_minimum_required(VERSION 3.22) + +# The top-level CMakeLists.txt file for a project must contain a literal, direct call to the +# `project()` command. `project()` sets up some helpful variables that describe source/binary +# directories, and the current project version. This is a standard CMake command. + +# We're going to use CPM as our package manager to bring in JUCE +# Check to see if we have CPM installed already. Bring it in if we don't. +set(CPM_DOWNLOAD_VERSION 0.34.0) +set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") + +if (NOT EXISTS ${CPM_DOWNLOAD_LOCATION}) + message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}") + file(DOWNLOAD https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake ${CPM_DOWNLOAD_LOCATION}) +endif () + +include(${CPM_DOWNLOAD_LOCATION}) + +# Bring in JUCE locally +CPMAddPackage( + NAME juce + GIT_REPOSITORY https://github.com/juce-framework/JUCE.git + GIT_TAG origin/master +) + + +project(RUMBLE_VST VERSION 0.0.1) + +# If you've installed JUCE somehow (via a package manager, or directly using the CMake install +# target), you'll need to tell this project that it depends on the installed copy of JUCE. If you've +# included JUCE directly in your source tree (perhaps as a submodule), you'll need to tell CMake to +# include that subdirectory as part of the build. + +# find_package(JUCE CONFIG REQUIRED) # If you've installed JUCE to your system +# or +# add_subdirectory(JUCE) # If you've put JUCE in a subdirectory called JUCE + +# If you are building a VST2 or AAX plugin, CMake needs to be told where to find these SDKs on your +# system. This setup should be done before calling `juce_add_plugin`. + +# juce_set_vst2_sdk_path(...) +# juce_set_aax_sdk_path(...) + +# `juce_add_plugin` adds a static library target with the name passed as the first argument +# (AudioPluginExample here). This target is a normal CMake target, but has a lot of extra properties set +# up by default. As well as this shared code static library, this function adds targets for each of +# the formats specified by the FORMATS arguments. This function accepts many optional arguments. +# Check the readme at `docs/CMake API.md` in the JUCE repo for the full list. + +juce_add_plugin(RumbleVST + # VERSION ... # Set this if the plugin version is different to the project version + # ICON_BIG ... # ICON_* arguments specify a path to an image file to use as an icon for the Standalone + # ICON_SMALL ... + # COMPANY_NAME ... # Specify the name of the plugin's author + # IS_SYNTH TRUE/FALSE # Is this a synth or an effect? + # NEEDS_MIDI_INPUT TRUE/FALSE # Does the plugin need midi input? + # NEEDS_MIDI_OUTPUT TRUE/FALSE # Does the plugin need midi output? + # IS_MIDI_EFFECT TRUE/FALSE # Is this plugin a MIDI effect? + # EDITOR_WANTS_KEYBOARD_FOCUS TRUE/FALSE # Does the editor need keyboard focus? + # COPY_PLUGIN_AFTER_BUILD TRUE/FALSE # Should the plugin be installed to a default location after building? + PLUGIN_MANUFACTURER_CODE Juce # A four-character manufacturer id with at least one upper-case character + PLUGIN_CODE Dem0 # A unique four-character plugin id with exactly one upper-case character + # GarageBand 10.3 requires the first letter to be upper-case, and the remaining letters to be lower-case + FORMATS AU VST3 Standalone # The formats to build. Other valid formats are: AAX Unity VST AU AUv3 + PRODUCT_NAME "RumbleVST") # The name of the final executable, which can differ from the target name + +# `juce_generate_juce_header` will create a JuceHeader.h for a given target, which will be generated +# into your build tree. This should be included with `#include `. The include path for +# this header will be automatically added to the target. The main function of the JuceHeader is to +# include all your JUCE module headers; if you're happy to include module headers directly, you +# probably don't need to call this. + +# juce_generate_juce_header(AudioPluginExample) + +# `target_sources` adds source files to a target. We pass the target that needs the sources as the +# first argument, then a visibility parameter for the sources which should normally be PRIVATE. +# Finally, we supply a list of source files that will be built into the target. This is a standard +# CMake command. + +target_sources(RumbleVST + PRIVATE + PluginEditor.cpp + PluginProcessor.cpp) + +# `target_compile_definitions` adds some preprocessor definitions to our target. In a Projucer +# project, these might be passed in the 'Preprocessor Definitions' field. JUCE modules also make use +# of compile definitions to switch certain features on/off, so if there's a particular feature you +# need that's not on by default, check the module header for the correct flag to set here. These +# definitions will be visible both to your code, and also the JUCE module code, so for new +# definitions, pick unique names that are unlikely to collide! This is a standard CMake command. + +target_compile_definitions(RumbleVST + PUBLIC + # JUCE_WEB_BROWSER and JUCE_USE_CURL would be on by default, but you might not need them. + JUCE_WEB_BROWSER=0 # If you remove this, add `NEEDS_WEB_BROWSER TRUE` to the `juce_add_plugin` call + JUCE_USE_CURL=0 # If you remove this, add `NEEDS_CURL TRUE` to the `juce_add_plugin` call + JUCE_VST3_CAN_REPLACE_VST2=0) + +# If your target needs extra binary assets, you can add them here. The first argument is the name of +# a new static library target that will include all the binary resources. There is an optional +# `NAMESPACE` argument that can specify the namespace of the generated binary data class. Finally, +# the SOURCES argument should be followed by a list of source files that should be built into the +# static library. These source files can be of any kind (wav data, images, fonts, icons etc.). +# Conversion to binary-data will happen when your target is built. + +# juce_add_binary_data(AudioPluginData SOURCES ...) + +# `target_link_libraries` links libraries and JUCE modules to other libraries or executables. Here, +# we're linking our executable target to the `juce::juce_audio_utils` module. Inter-module +# dependencies are resolved automatically, so `juce_core`, `juce_events` and so on will also be +# linked automatically. If we'd generated a binary data target above, we would need to link to it +# here too. This is a standard CMake command. + +target_link_libraries(RumbleVST + PRIVATE + # AudioPluginData # If we'd created a binary data target, we'd link to it here + juce::juce_audio_utils + PUBLIC + juce::juce_recommended_config_flags + juce::juce_recommended_lto_flags + juce::juce_recommended_warning_flags) \ No newline at end of file diff --git a/PluginEditor.cpp b/PluginEditor.cpp new file mode 100644 index 0000000..964c6d7 --- /dev/null +++ b/PluginEditor.cpp @@ -0,0 +1,33 @@ +#include "PluginProcessor.h" +#include "PluginEditor.h" + +//============================================================================== +AudioPluginAudioProcessorEditor::AudioPluginAudioProcessorEditor (AudioPluginAudioProcessor& p) + : AudioProcessorEditor (&p), processorRef (p) +{ + juce::ignoreUnused (processorRef); + // Make sure that before the constructor has finished, you've set the + // editor's size to whatever you need it to be. + setSize (400, 300); +} + +AudioPluginAudioProcessorEditor::~AudioPluginAudioProcessorEditor() +{ +} + +//============================================================================== +void AudioPluginAudioProcessorEditor::paint (juce::Graphics& g) +{ + // (Our component is opaque, so we must completely fill the background with a solid colour) + g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId)); + + g.setColour (juce::Colours::white); + g.setFont (15.0f); + g.drawFittedText ("Hello World!", getLocalBounds(), juce::Justification::centred, 1); +} + +void AudioPluginAudioProcessorEditor::resized() +{ + // This is generally where you'll want to lay out the positions of any + // subcomponents in your editor.. +} \ No newline at end of file diff --git a/PluginEditor.h b/PluginEditor.h new file mode 100644 index 0000000..354b020 --- /dev/null +++ b/PluginEditor.h @@ -0,0 +1,22 @@ +#pragma once + +#include "PluginProcessor.h" + +//============================================================================== +class AudioPluginAudioProcessorEditor final : public juce::AudioProcessorEditor +{ +public: + explicit AudioPluginAudioProcessorEditor (AudioPluginAudioProcessor&); + ~AudioPluginAudioProcessorEditor() override; + + //============================================================================== + void paint (juce::Graphics&) override; + void resized() override; + +private: + // This reference is provided as a quick way for your editor to + // access the processor object that created it. + AudioPluginAudioProcessor& processorRef; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginAudioProcessorEditor) +}; \ No newline at end of file diff --git a/PluginProcessor.cpp b/PluginProcessor.cpp new file mode 100644 index 0000000..777f2c1 --- /dev/null +++ b/PluginProcessor.cpp @@ -0,0 +1,188 @@ +#include "PluginProcessor.h" +#include "PluginEditor.h" + +//============================================================================== +AudioPluginAudioProcessor::AudioPluginAudioProcessor() + : AudioProcessor (BusesProperties() + #if ! JucePlugin_IsMidiEffect + #if ! JucePlugin_IsSynth + .withInput ("Input", juce::AudioChannelSet::stereo(), true) + #endif + .withOutput ("Output", juce::AudioChannelSet::stereo(), true) + #endif + ) +{ +} + +AudioPluginAudioProcessor::~AudioPluginAudioProcessor() +{ +} + +//============================================================================== +const juce::String AudioPluginAudioProcessor::getName() const +{ + return JucePlugin_Name; +} + +bool AudioPluginAudioProcessor::acceptsMidi() const +{ + #if JucePlugin_WantsMidiInput + return true; + #else + return false; + #endif +} + +bool AudioPluginAudioProcessor::producesMidi() const +{ + #if JucePlugin_ProducesMidiOutput + return true; + #else + return false; + #endif +} + +bool AudioPluginAudioProcessor::isMidiEffect() const +{ + #if JucePlugin_IsMidiEffect + return true; + #else + return false; + #endif +} + +double AudioPluginAudioProcessor::getTailLengthSeconds() const +{ + return 0.0; +} + +int AudioPluginAudioProcessor::getNumPrograms() +{ + return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs, + // so this should be at least 1, even if you're not really implementing programs. +} + +int AudioPluginAudioProcessor::getCurrentProgram() +{ + return 0; +} + +void AudioPluginAudioProcessor::setCurrentProgram (int index) +{ + juce::ignoreUnused (index); +} + +const juce::String AudioPluginAudioProcessor::getProgramName (int index) +{ + juce::ignoreUnused (index); + return {}; +} + +void AudioPluginAudioProcessor::changeProgramName (int index, const juce::String& newName) +{ + juce::ignoreUnused (index, newName); +} + +//============================================================================== +void AudioPluginAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) +{ + // Use this method as the place to do any pre-playback + // initialisation that you need.. + juce::ignoreUnused (sampleRate, samplesPerBlock); +} + +void AudioPluginAudioProcessor::releaseResources() +{ + // When playback stops, you can use this as an opportunity to free up any + // spare memory, etc. +} + +bool AudioPluginAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const +{ + #if JucePlugin_IsMidiEffect + juce::ignoreUnused (layouts); + return true; + #else + // This is the place where you check if the layout is supported. + // In this template code we only support mono or stereo. + // Some plugin hosts, such as certain GarageBand versions, will only + // load plugins that support stereo bus layouts. + if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::mono() + && layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo()) + return false; + + // This checks if the input layout matches the output layout + #if ! JucePlugin_IsSynth + if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet()) + return false; + #endif + + return true; + #endif +} + +void AudioPluginAudioProcessor::processBlock (juce::AudioBuffer& buffer, + juce::MidiBuffer& midiMessages) +{ + juce::ignoreUnused (midiMessages); + + juce::ScopedNoDenormals noDenormals; + auto totalNumInputChannels = getTotalNumInputChannels(); + auto totalNumOutputChannels = getTotalNumOutputChannels(); + + // In case we have more outputs than inputs, this code clears any output + // channels that didn't contain input data, (because these aren't + // guaranteed to be empty - they may contain garbage). + // This is here to avoid people getting screaming feedback + // when they first compile a plugin, but obviously you don't need to keep + // this code if your algorithm always overwrites all the output channels. + for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) + buffer.clear (i, 0, buffer.getNumSamples()); + + // This is the place where you'd normally do the guts of your plugin's + // audio processing... + // Make sure to reset the state if your inner loop is processing + // the samples and the outer loop is handling the channels. + // Alternatively, you can process the samples with the channels + // interleaved by keeping the same state. + for (int channel = 0; channel < totalNumInputChannels; ++channel) + { + auto* channelData = buffer.getWritePointer (channel); + juce::ignoreUnused (channelData); + // ..do something to the data... + } +} + +//============================================================================== +bool AudioPluginAudioProcessor::hasEditor() const +{ + return true; // (change this to false if you choose to not supply an editor) +} + +juce::AudioProcessorEditor* AudioPluginAudioProcessor::createEditor() +{ + return new AudioPluginAudioProcessorEditor (*this); +} + +//============================================================================== +void AudioPluginAudioProcessor::getStateInformation (juce::MemoryBlock& destData) +{ + // You should use this method to store your parameters in the memory block. + // You could do that either as raw data, or use the XML or ValueTree classes + // as intermediaries to make it easy to save and load complex data. + juce::ignoreUnused (destData); +} + +void AudioPluginAudioProcessor::setStateInformation (const void* data, int sizeInBytes) +{ + // You should use this method to restore your parameters from this memory block, + // whose contents will have been created by the getStateInformation() call. + juce::ignoreUnused (data, sizeInBytes); +} + +//============================================================================== +// This creates new instances of the plugin.. +juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter() +{ + return new AudioPluginAudioProcessor(); +} \ No newline at end of file diff --git a/PluginProcessor.h b/PluginProcessor.h new file mode 100644 index 0000000..04c6fcb --- /dev/null +++ b/PluginProcessor.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +//============================================================================== +class AudioPluginAudioProcessor final : public juce::AudioProcessor +{ +public: + //============================================================================== + AudioPluginAudioProcessor(); + ~AudioPluginAudioProcessor() override; + + //============================================================================== + void prepareToPlay (double sampleRate, int samplesPerBlock) override; + void releaseResources() override; + + bool isBusesLayoutSupported (const BusesLayout& layouts) const override; + + void processBlock (juce::AudioBuffer&, juce::MidiBuffer&) override; + using AudioProcessor::processBlock; + + //============================================================================== + juce::AudioProcessorEditor* createEditor() override; + bool hasEditor() const override; + + //============================================================================== + const juce::String getName() const override; + + bool acceptsMidi() const override; + bool producesMidi() const override; + bool isMidiEffect() const override; + double getTailLengthSeconds() const override; + + //============================================================================== + int getNumPrograms() override; + int getCurrentProgram() override; + void setCurrentProgram (int index) override; + const juce::String getProgramName (int index) override; + void changeProgramName (int index, const juce::String& newName) override; + + //============================================================================== + void getStateInformation (juce::MemoryBlock& destData) override; + void setStateInformation (const void* data, int sizeInBytes) override; + +private: + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginAudioProcessor) +}; \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c2006fb --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +this might turn into a useable audio plugin, fingers crossed :D +currently just experimenting with juce :) \ No newline at end of file