From 3340d9dd4513a67be808bfdbfeb3d8fb6e534a70 Mon Sep 17 00:00:00 2001 From: James H Ball Date: Mon, 6 Jan 2025 09:14:34 +0000 Subject: [PATCH] Add output volume control to sosci --- Source/CommonPluginEditor.h | 3 +++ Source/CommonPluginProcessor.cpp | 5 +++++ Source/CommonPluginProcessor.h | 27 +++++++++++++++++++++++ Source/PluginEditor.h | 2 -- Source/PluginProcessor.cpp | 2 -- Source/PluginProcessor.h | 26 ---------------------- Source/SosciPluginEditor.cpp | 14 +++++++----- Source/SosciPluginProcessor.cpp | 10 +++++++++ Source/components/VolumeComponent.cpp | 2 +- Source/components/VolumeComponent.h | 6 ++--- Source/visualiser/VisualiserComponent.cpp | 2 +- sosci.jucer | 4 ++++ 12 files changed, 63 insertions(+), 40 deletions(-) diff --git a/Source/CommonPluginEditor.h b/Source/CommonPluginEditor.h index 72ff095..267189c 100644 --- a/Source/CommonPluginEditor.h +++ b/Source/CommonPluginEditor.h @@ -7,6 +7,7 @@ #include "visualiser/VisualiserSettings.h" #include "components/SosciMainMenuBarModel.h" #include "components/SvgButton.h" +#include "components/VolumeComponent.h" class CommonPluginEditor : public juce::AudioProcessorEditor { public: @@ -66,6 +67,8 @@ public: appName == "sosci" }; + VolumeComponent volume{audioProcessor}; + std::unique_ptr chooser; juce::MenuBarComponent menuBar; diff --git a/Source/CommonPluginProcessor.cpp b/Source/CommonPluginProcessor.cpp index fc76c64..bceac62 100644 --- a/Source/CommonPluginProcessor.cpp +++ b/Source/CommonPluginProcessor.cpp @@ -33,6 +33,11 @@ CommonAudioProcessor::CommonAudioProcessor() for (auto parameter : visualiserParameters.integers) { intParameters.push_back(parameter); } + + permanentEffects.push_back(volumeEffect); + permanentEffects.push_back(thresholdEffect); + effects.push_back(volumeEffect); + effects.push_back(thresholdEffect); } void CommonAudioProcessor::addAllParameters() { diff --git a/Source/CommonPluginProcessor.h b/Source/CommonPluginProcessor.h index f1b1e52..86685c2 100644 --- a/Source/CommonPluginProcessor.h +++ b/Source/CommonPluginProcessor.h @@ -55,6 +55,33 @@ public: void changeProgramName(int index, const juce::String& newName) override; double getSampleRate() override; + std::atomic volume = 1.0; + std::atomic threshold = 1.0; + + std::shared_ptr volumeEffect = std::make_shared( + [this](int index, OsciPoint input, const std::vector>& values, double sampleRate) { + volume = values[0].load(); + return input; + }, new EffectParameter( + "Volume", + "Controls the volume of the output audio.", + "volume", + VERSION_HINT, 1.0, 0.0, 3.0 + ) + ); + + std::shared_ptr thresholdEffect = std::make_shared( + [this](int index, OsciPoint input, const std::vector>& values, double sampleRate) { + threshold = values[0].load(); + return input; + }, new EffectParameter( + "Threshold", + "Clips the audio to a maximum value. Applying a harsher threshold results in a more distorted sound.", + "threshold", + VERSION_HINT, 1.0, 0.0, 1.0 + ) + ); + std::atomic currentSampleRate = 0.0; juce::SpinLock effectsLock; VisualiserParameters visualiserParameters; diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index 553bed4..de00f94 100644 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -4,7 +4,6 @@ #include "PluginProcessor.h" #include "SettingsComponent.h" #include "MidiComponent.h" -#include "components/VolumeComponent.h" #include "components/OsciMainMenuBarModel.h" #include "LookAndFeel.h" #include "components/ErrorCodeEditorComponent.h" @@ -48,7 +47,6 @@ public: juce::ComponentAnimator codeEditorAnimator; LuaComponent lua{audioProcessor, *this}; - VolumeComponent volume{audioProcessor}; LuaConsole console; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 4da71df..4ed2db7 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -135,8 +135,6 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() { std::vector> osciPermanentEffects; osciPermanentEffects.push_back(perspective); osciPermanentEffects.push_back(frequencyEffect); - osciPermanentEffects.push_back(volumeEffect); - osciPermanentEffects.push_back(thresholdEffect); osciPermanentEffects.push_back(imageThreshold); osciPermanentEffects.push_back(imageStride); diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 4d6f10d..d4a5e21 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -71,30 +71,6 @@ public: VERSION_HINT, 220.0, 0.0, 12000.0, 0.1 ) ); - - std::shared_ptr volumeEffect = std::make_shared( - [this](int index, OsciPoint input, const std::vector>& values, double sampleRate) { - volume = values[0].load(); - return input; - }, new EffectParameter( - "Volume", - "Controls the volume of the sound. Works by scaling the image and sound by a factor.", - "volume", - VERSION_HINT, 1.0, 0.0, 3.0 - ) - ); - - std::shared_ptr thresholdEffect = std::make_shared( - [this](int index, OsciPoint input, const std::vector>& values, double sampleRate) { - threshold = values[0].load(); - return input; - }, new EffectParameter( - "Threshold", - "Clips the sound and image to a maximum value. Applying a harsher threshold results in a more distorted sound.", - "threshold", - VERSION_HINT, 1.0, 0.0, 1.0 - ) - ); std::shared_ptr traceMax = std::make_shared( new EffectParameter( @@ -232,8 +208,6 @@ public: void removeErrorListener(ErrorListener* listener); void notifyErrorListeners(int lineNumber, juce::String id, juce::String error); private: - std::atomic volume = 1.0; - std::atomic threshold = 1.0; bool prevMidiEnabled = !midiEnabled->getBoolValue(); diff --git a/Source/SosciPluginEditor.cpp b/Source/SosciPluginEditor.cpp index 6863dd0..8984d29 100644 --- a/Source/SosciPluginEditor.cpp +++ b/Source/SosciPluginEditor.cpp @@ -4,6 +4,7 @@ SosciPluginEditor::SosciPluginEditor(SosciAudioProcessor& p) : CommonPluginEditor(p, "sosci", "sosci", 700, 750), audioProcessor(p) { initialiseMenuBar(model); + addAndMakeVisible(volume); resized(); } @@ -16,9 +17,12 @@ void SosciPluginEditor::paint(juce::Graphics& g) { } void SosciPluginEditor::resized() { - auto topBar = getLocalBounds().removeFromTop(25); - menuBar.setBounds(topBar); - auto visualiserArea = getLocalBounds(); - visualiserArea.removeFromTop(25); - visualiser.setBounds(visualiserArea); + auto area = getLocalBounds(); + + menuBar.setBounds(area.removeFromTop(25)); + + auto volumeArea = area.removeFromLeft(30); + volume.setBounds(volumeArea.withSizeKeepingCentre(volumeArea.getWidth(), juce::jmin(volumeArea.getHeight(), 300))); + + visualiser.setBounds(area); } diff --git a/Source/SosciPluginProcessor.cpp b/Source/SosciPluginProcessor.cpp index 8dfe33e..2da4fb6 100644 --- a/Source/SosciPluginProcessor.cpp +++ b/Source/SosciPluginProcessor.cpp @@ -51,7 +51,17 @@ void SosciAudioProcessor::processBlock(juce::AudioBuffer& buffer, juce::M point = effect->apply(sample, point); } + // no negative brightness + point.z = juce::jmax(0.0, juce::jmin(1.0, point.z)); + + // this is the point that the visualiser will draw threadManager.write(point); + + point.scale(volume, volume, volume); + + // clip + point.x = juce::jmax(-threshold, juce::jmin(threshold.load(), point.x)); + point.y = juce::jmax(-threshold, juce::jmin(threshold.load(), point.y)); if (output.getNumChannels() > 0) { outputArray[0][sample] = point.x; diff --git a/Source/components/VolumeComponent.cpp b/Source/components/VolumeComponent.cpp index 104154b..40270db 100644 --- a/Source/components/VolumeComponent.cpp +++ b/Source/components/VolumeComponent.cpp @@ -1,6 +1,6 @@ #include "VolumeComponent.h" -VolumeComponent::VolumeComponent(OscirenderAudioProcessor& p) : AudioBackgroundThread("VolumeComponent", p.threadManager), audioProcessor(p) { +VolumeComponent::VolumeComponent(CommonAudioProcessor& p) : AudioBackgroundThread("VolumeComponent", p.threadManager), audioProcessor(p) { setOpaque(false); setShouldBeRunning(true); diff --git a/Source/components/VolumeComponent.h b/Source/components/VolumeComponent.h index 00f267c..f2bcbd9 100644 --- a/Source/components/VolumeComponent.h +++ b/Source/components/VolumeComponent.h @@ -1,7 +1,7 @@ #pragma once #include -#include "../PluginProcessor.h" +#include "../CommonPluginProcessor.h" #include "../LookAndFeel.h" #include "../concurrency/AudioBackgroundThread.h" @@ -61,7 +61,7 @@ public: class VolumeComponent : public juce::Component, public juce::AsyncUpdater, public AudioBackgroundThread { public: - VolumeComponent(OscirenderAudioProcessor& p); + VolumeComponent(CommonAudioProcessor& p); void paint(juce::Graphics&) override; void handleAsyncUpdate() override; @@ -71,7 +71,7 @@ public: void resized() override; private: - OscirenderAudioProcessor& audioProcessor; + CommonAudioProcessor& audioProcessor; const int DEFAULT_SAMPLE_RATE = 192000; const double BUFFER_DURATION_SECS = 0.02; diff --git a/Source/visualiser/VisualiserComponent.cpp b/Source/visualiser/VisualiserComponent.cpp index 0100e07..3f915d7 100644 --- a/Source/visualiser/VisualiserComponent.cpp +++ b/Source/visualiser/VisualiserComponent.cpp @@ -603,7 +603,7 @@ void VisualiserComponent::renderOpenGL() { using namespace juce::gl; if (openGLContext.isActive()) { - juce::OpenGLHelpers::clear(Colours::veryDark); + juce::OpenGLHelpers::clear(juce::Colours::black); // we have a new buffer to render if (sampleBufferCount != prevSampleBufferCount) { diff --git a/sosci.jucer b/sosci.jucer index c3dfdd7..ea37db3 100644 --- a/sosci.jucer +++ b/sosci.jucer @@ -122,6 +122,10 @@ file="Source/components/StopwatchComponent.h"/> + +