diff --git a/.gitignore b/.gitignore index dfcfd56..30e79dc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,10 @@ ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore +# ignore JUCE +**/Builds +**/JuceLibraryCode + # User-specific files *.rsuser *.suo diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp new file mode 100644 index 0000000..179e98a --- /dev/null +++ b/Source/PluginEditor.cpp @@ -0,0 +1,56 @@ +/* + ============================================================================== + + This file contains the basic framework code for a JUCE plugin editor. + + ============================================================================== +*/ + +#include "PluginProcessor.h" +#include "PluginEditor.h" + +//============================================================================== +OscirenderAudioProcessorEditor::OscirenderAudioProcessorEditor (OscirenderAudioProcessor& p) + : AudioProcessorEditor (&p), audioProcessor (p) +{ + // Make sure that before the constructor has finished, you've set the + // editor's size to whatever you need it to be. + setSize (200, 200); + + midiVolume.setSliderStyle(juce::Slider::LinearBarVertical); + midiVolume.setRange(0.0, 127.0, 1.0); + midiVolume.setTextBoxStyle(juce::Slider::NoTextBox, false, 90, 0); + midiVolume.setPopupDisplayEnabled(true, false, this); + midiVolume.setTextValueSuffix(" Volume"); + midiVolume.setValue(1.0); + + addAndMakeVisible(midiVolume); + midiVolume.addListener(this); +} + +OscirenderAudioProcessorEditor::~OscirenderAudioProcessorEditor() +{ +} + +//============================================================================== +void OscirenderAudioProcessorEditor::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 ("Midi Volume", getLocalBounds(), juce::Justification::centred, 1); +} + +void OscirenderAudioProcessorEditor::resized() +{ + // This is generally where you'll want to lay out the positions of any + // subcomponents in your editor.. + + midiVolume.setBounds(40, 30, 20, getHeight() - 60); +} + +void OscirenderAudioProcessorEditor::sliderValueChanged(juce::Slider* slider) { + audioProcessor.noteOnVel = midiVolume.getValue(); +} diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h new file mode 100644 index 0000000..cf397ef --- /dev/null +++ b/Source/PluginEditor.h @@ -0,0 +1,38 @@ +/* + ============================================================================== + + This file contains the basic framework code for a JUCE plugin editor. + + ============================================================================== +*/ + +#pragma once + +#include +#include "PluginProcessor.h" + +//============================================================================== +/** +*/ +class OscirenderAudioProcessorEditor : public juce::AudioProcessorEditor, + public juce::Slider::Listener +{ +public: + OscirenderAudioProcessorEditor (OscirenderAudioProcessor&); + ~OscirenderAudioProcessorEditor() override; + + //============================================================================== + void paint (juce::Graphics&) override; + void resized() override; + +private: + void sliderValueChanged(juce::Slider* slider) override; + + // This reference is provided as a quick way for your editor to + // access the processor object that created it. + OscirenderAudioProcessor& audioProcessor; + + juce::Slider midiVolume; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OscirenderAudioProcessorEditor) +}; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp new file mode 100644 index 0000000..95523e2 --- /dev/null +++ b/Source/PluginProcessor.cpp @@ -0,0 +1,204 @@ +/* + ============================================================================== + + This file contains the basic framework code for a JUCE plugin processor. + + ============================================================================== +*/ + +#include "PluginProcessor.h" +#include "PluginEditor.h" + +//============================================================================== +OscirenderAudioProcessor::OscirenderAudioProcessor() +#ifndef JucePlugin_PreferredChannelConfigurations + : AudioProcessor (BusesProperties() + #if ! JucePlugin_IsMidiEffect + #if ! JucePlugin_IsSynth + .withInput ("Input", juce::AudioChannelSet::stereo(), true) + #endif + .withOutput ("Output", juce::AudioChannelSet::stereo(), true) + #endif + ) +#endif +{ +} + +OscirenderAudioProcessor::~OscirenderAudioProcessor() +{ +} + +//============================================================================== +const juce::String OscirenderAudioProcessor::getName() const +{ + return JucePlugin_Name; +} + +bool OscirenderAudioProcessor::acceptsMidi() const +{ + #if JucePlugin_WantsMidiInput + return true; + #else + return false; + #endif +} + +bool OscirenderAudioProcessor::producesMidi() const +{ + #if JucePlugin_ProducesMidiOutput + return true; + #else + return false; + #endif +} + +bool OscirenderAudioProcessor::isMidiEffect() const +{ + #if JucePlugin_IsMidiEffect + return true; + #else + return false; + #endif +} + +double OscirenderAudioProcessor::getTailLengthSeconds() const +{ + return 0.0; +} + +int OscirenderAudioProcessor::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 OscirenderAudioProcessor::getCurrentProgram() +{ + return 0; +} + +void OscirenderAudioProcessor::setCurrentProgram (int index) +{ +} + +const juce::String OscirenderAudioProcessor::getProgramName (int index) +{ + return {}; +} + +void OscirenderAudioProcessor::changeProgramName (int index, const juce::String& newName) +{ +} + +//============================================================================== +void OscirenderAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) +{ + // Use this method as the place to do any pre-playback + // initialisation that you need.. +} + +void OscirenderAudioProcessor::releaseResources() +{ + // When playback stops, you can use this as an opportunity to free up any + // spare memory, etc. +} + +#ifndef JucePlugin_PreferredChannelConfigurations +bool OscirenderAudioProcessor::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 +} +#endif + +void OscirenderAudioProcessor::processBlock (juce::AudioBuffer& buffer, juce::MidiBuffer& 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); + + // ..do something to the data... + } + + juce::MidiBuffer processedMidi; + + for (const auto metadata : midiMessages) { + auto message = metadata.getMessage(); + const auto time = metadata.samplePosition; + + if (message.isNoteOn()) { + message = juce::MidiMessage::noteOn(message.getChannel(), message.getNoteNumber(), (juce::uint8)noteOnVel); + } + processedMidi.addEvent(message, time); + } + midiMessages.swapWith(processedMidi); +} + +//============================================================================== +bool OscirenderAudioProcessor::hasEditor() const +{ + return true; // (change this to false if you choose to not supply an editor) +} + +juce::AudioProcessorEditor* OscirenderAudioProcessor::createEditor() +{ + return new OscirenderAudioProcessorEditor (*this); +} + +//============================================================================== +void OscirenderAudioProcessor::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. +} + +void OscirenderAudioProcessor::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. +} + +//============================================================================== +// This creates new instances of the plugin.. +juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter() +{ + return new OscirenderAudioProcessor(); +} diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h new file mode 100644 index 0000000..bc92170 --- /dev/null +++ b/Source/PluginProcessor.h @@ -0,0 +1,64 @@ +/* + ============================================================================== + + This file contains the basic framework code for a JUCE plugin processor. + + ============================================================================== +*/ + +#pragma once + +#include + +//============================================================================== +/** +*/ +class OscirenderAudioProcessor : public juce::AudioProcessor + #if JucePlugin_Enable_ARA + , public juce::AudioProcessorARAExtension + #endif +{ +public: + //============================================================================== + OscirenderAudioProcessor(); + ~OscirenderAudioProcessor() override; + + //============================================================================== + void prepareToPlay (double sampleRate, int samplesPerBlock) override; + void releaseResources() override; + + #ifndef JucePlugin_PreferredChannelConfigurations + bool isBusesLayoutSupported (const BusesLayout& layouts) const override; + #endif + + void processBlock (juce::AudioBuffer&, juce::MidiBuffer&) override; + + //============================================================================== + 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; + + float noteOnVel; + +private: + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OscirenderAudioProcessor) +}; diff --git a/osci-render.jucer b/osci-render.jucer new file mode 100644 index 0000000..0e7dc6a --- /dev/null +++ b/osci-render.jucer @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +