diff --git a/Resources/svg/microphone.svg b/Resources/svg/microphone.svg new file mode 100644 index 0000000..33084ec --- /dev/null +++ b/Resources/svg/microphone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Source/MainComponent.cpp b/Source/MainComponent.cpp index 03ce1d9..ea85c74 100644 --- a/Source/MainComponent.cpp +++ b/Source/MainComponent.cpp @@ -45,6 +45,10 @@ MainComponent::MainComponent(OscirenderAudioProcessor& p, OscirenderAudioProcess pluginEditor.fileUpdated(audioProcessor.getCurrentFileName()); }; + addAndMakeVisible(inputEnabled); + inputEnabled.onClick = [this] { + audioProcessor.inputEnabled->setBoolValueNotifyingHost(!audioProcessor.inputEnabled->getBoolValue()); + }; addAndMakeVisible(fileLabel); updateFileLabel(); @@ -125,6 +129,8 @@ void MainComponent::resized() { auto row = bounds.removeFromTop(buttonHeight); fileButton.setBounds(row.removeFromLeft(buttonWidth)); + row.removeFromLeft(rowPadding); + inputEnabled.setBounds(row.removeFromLeft(20)); row.removeFromLeft(rowPadding); fileLabel.setBounds(row); bounds.removeFromTop(padding); diff --git a/Source/MainComponent.h b/Source/MainComponent.h index 955648d..57f0f05 100644 --- a/Source/MainComponent.h +++ b/Source/MainComponent.h @@ -7,6 +7,7 @@ #include "components/VisualiserComponent.h" #include "audio/PitchDetector.h" #include "UGen/ugen_JuceEnvelopeComponent.h" +#include "components/SvgButton.h" class OscirenderAudioProcessorEditor; class MainComponent : public juce::GroupComponent { @@ -24,6 +25,7 @@ private: std::unique_ptr chooser; juce::TextButton fileButton; juce::TextButton closeFileButton; + SvgButton inputEnabled{"inputEnabled", juce::String(BinaryData::microphone_svg), "white", "red", audioProcessor.inputEnabled}; juce::Label fileLabel; juce::TextEditor fileName; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 105a204..d367041 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -147,6 +147,7 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() booleanParameters.push_back(perspectiveEffect->fixedRotateY); booleanParameters.push_back(perspectiveEffect->fixedRotateZ); booleanParameters.push_back(midiEnabled); + booleanParameters.push_back(inputEnabled); for (auto parameter : booleanParameters) { addParameter(parameter); @@ -474,7 +475,13 @@ void OscirenderAudioProcessor::processBlock(juce::AudioBuffer& buffer, ju auto totalNumInputChannels = getTotalNumInputChannels(); auto totalNumOutputChannels = getTotalNumOutputChannels(); - buffer.clear(); + // clear output channels + for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i) { + buffer.clear(i, 0, buffer.getNumSamples()); + } + + bool usingInput = inputEnabled->getBoolValue(); + bool usingMidi = midiEnabled->getBoolValue(); if (!usingMidi) { midiMessages.clear(); @@ -495,13 +502,26 @@ void OscirenderAudioProcessor::processBlock(juce::AudioBuffer& buffer, ju prevMidiEnabled = usingMidi; const double EPSILON = 0.00001; - - - if (volume > EPSILON) { - juce::SpinLock::ScopedLockType lock1(parsersLock); - juce::SpinLock::ScopedLockType lock2(effectsLock); - synth.renderNextBlock(buffer, midiMessages, 0, buffer.getNumSamples()); + + if (usingInput && totalNumInputChannels >= 2) { + // handle all midi messages + auto midiIterator = midiMessages.cbegin(); + std::for_each(midiIterator, + midiMessages.cend(), + [&] (const juce::MidiMessageMetadata& meta) { synth.publicHandleMidiEvent(meta.getMessage()); } + ); + } else { + for (auto i = 0; i < totalNumInputChannels; ++i) { + buffer.clear(i, 0, buffer.getNumSamples()); + } + if (volume > EPSILON) { + juce::SpinLock::ScopedLockType lock1(parsersLock); + juce::SpinLock::ScopedLockType lock2(effectsLock); + synth.renderNextBlock(buffer, midiMessages, 0, buffer.getNumSamples()); + } } + + midiMessages.clear(); auto* channelData = buffer.getArrayOfWritePointers(); diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index c87e977..9a3936f 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -14,6 +14,7 @@ #include "audio/Effect.h" #include "audio/ShapeSound.h" #include "audio/ShapeVoice.h" +#include "audio/PublicSynthesiser.h" #include #include "audio/AudioWebSocketServer.h" #include "audio/DelayEffect.h" @@ -192,6 +193,7 @@ public: std::shared_ptr perspectiveEffect = std::make_shared(VERSION_HINT); BooleanParameter* midiEnabled = new BooleanParameter("MIDI Enabled", "midiEnabled", VERSION_HINT, !juce::JUCEApplicationBase::isStandaloneApp()); + BooleanParameter* inputEnabled = new BooleanParameter("Audio Input Enabled", "inputEnabled", VERSION_HINT, false); std::atomic frequency = 440.0f; juce::SpinLock parsersLock; @@ -268,7 +270,7 @@ private: std::vector> permanentEffects; ShapeSound::Ptr defaultSound = new ShapeSound(std::make_shared()); - juce::Synthesiser synth; + PublicSynthesiser synth; AudioWebSocketServer softwareOscilloscopeServer{*this}; ObjectServer objectServer{*this}; diff --git a/Source/audio/PublicSynthesiser.h b/Source/audio/PublicSynthesiser.h new file mode 100644 index 0000000..b3e0a76 --- /dev/null +++ b/Source/audio/PublicSynthesiser.h @@ -0,0 +1,9 @@ +#pragma once +#include + +class PublicSynthesiser : public juce::Synthesiser { +public: + void publicHandleMidiEvent(const juce::MidiMessage& m) { + handleMidiEvent(m); + } +}; \ No newline at end of file diff --git a/osci-render.jucer b/osci-render.jucer index 6482fb5..91fdc1d 100644 --- a/osci-render.jucer +++ b/osci-render.jucer @@ -18,6 +18,7 @@ + @@ -64,6 +65,8 @@ +