From afc16fc0441c7a94e77460e90382aa2058ca6eee Mon Sep 17 00:00:00 2001 From: James Ball Date: Fri, 14 Jul 2023 15:34:24 +0100 Subject: [PATCH] Most effects now change smoothly between values, making the visuals MUCH smoother when using sliders --- Source/EffectsComponent.cpp | 7 +- Source/EffectsComponent.h | 2 +- Source/ObjComponent.cpp | 40 +++--- Source/ObjComponent.h | 10 +- Source/PluginProcessor.cpp | 52 ++++--- Source/PluginProcessor.h | 165 ++++++++++++---------- Source/audio/BitCrushEffect.cpp | 4 +- Source/audio/BitCrushEffect.h | 2 +- Source/audio/BulgeEffect.cpp | 4 +- Source/audio/BulgeEffect.h | 2 +- Source/audio/DelayEffect.cpp | 6 +- Source/audio/DelayEffect.h | 2 +- Source/audio/DistortEffect.cpp | 4 +- Source/audio/DistortEffect.h | 2 +- Source/audio/Effect.cpp | 28 ++-- Source/audio/Effect.h | 16 ++- Source/audio/EffectApplication.h | 2 +- Source/audio/LuaEffect.cpp | 4 +- Source/audio/LuaEffect.h | 2 +- Source/audio/RotateEffect.cpp | 4 +- Source/audio/RotateEffect.h | 2 +- Source/audio/SmoothEffect.cpp | 6 +- Source/audio/SmoothEffect.h | 2 +- Source/audio/VectorCancellingEffect.cpp | 4 +- Source/audio/VectorCancellingEffect.h | 2 +- Source/audio/WobbleEffect.cpp | 4 +- Source/audio/WobbleEffect.h | 2 +- Source/components/LuaListComponent.cpp | 2 +- Source/components/VisualiserComponent.cpp | 8 +- Source/components/VolumeComponent.cpp | 4 +- Source/concurrency/BufferProducer.h | 40 +++++- Source/obj/WorldObject.cpp | 12 +- Source/obj/WorldObject.h | 4 +- 33 files changed, 262 insertions(+), 188 deletions(-) diff --git a/Source/EffectsComponent.cpp b/Source/EffectsComponent.cpp index 99e3a56..6834c65 100644 --- a/Source/EffectsComponent.cpp +++ b/Source/EffectsComponent.cpp @@ -10,13 +10,10 @@ EffectsComponent::EffectsComponent(OscirenderAudioProcessor& p) : audioProcessor frequency.slider.setSkewFactorFromMidPoint(500.0); frequency.slider.setTextValueSuffix("Hz"); - frequency.slider.setValue(audioProcessor.frequency, juce::dontSendNotification); + frequency.slider.setValue(audioProcessor.frequencyEffect->getValue(), juce::dontSendNotification); frequency.slider.onValueChange = [this] { - audioProcessor.frequency = frequency.slider.getValue(); - if (audioProcessor.currentSampleRate > 0.0) { - audioProcessor.updateAngleDelta(); - } + audioProcessor.frequencyEffect->setValue(frequency.slider.getValue()); }; { diff --git a/Source/EffectsComponent.h b/Source/EffectsComponent.h index 213acd5..1765536 100644 --- a/Source/EffectsComponent.h +++ b/Source/EffectsComponent.h @@ -23,7 +23,7 @@ private: EffectsListBoxModel listBoxModel; DraggableListBox listBox; - EffectComponent frequency = EffectComponent(0.0, 12000.0, 0.1, 400, "Frequency", "frequency"); + EffectComponent frequency = EffectComponent(0.0, 12000.0, 0.1, *audioProcessor.frequencyEffect, false); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(EffectsComponent) }; \ No newline at end of file diff --git a/Source/ObjComponent.cpp b/Source/ObjComponent.cpp index 446881a..c852bf5 100644 --- a/Source/ObjComponent.cpp +++ b/Source/ObjComponent.cpp @@ -16,8 +16,8 @@ ObjComponent::ObjComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessor focalLength.slider.onValueChange = [this] { juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock); - audioProcessor.focalLength.setValue(focalLength.slider.getValue()); - audioProcessor.focalLength.apply(); + audioProcessor.focalLength->setValue(focalLength.slider.getValue()); + audioProcessor.focalLength->apply(); }; auto onRotationChange = [this]() { @@ -25,23 +25,21 @@ ObjComponent::ObjComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessor double x = fixedRotateX->getToggleState() ? 0 : rotateX.slider.getValue(); double y = fixedRotateY->getToggleState() ? 0 : rotateY.slider.getValue(); double z = fixedRotateZ->getToggleState() ? 0 : rotateZ.slider.getValue(); - audioProcessor.rotateX.setValue(x); - audioProcessor.rotateY.setValue(y); - audioProcessor.rotateZ.setValue(z); - // all the rotate apply functions are the same - audioProcessor.rotateX.apply(); + audioProcessor.rotateX->setValue(x); + audioProcessor.rotateY->setValue(y); + audioProcessor.rotateZ->setValue(z); if (fixedRotateX->getToggleState()) { - audioProcessor.currentRotateX.setValue(rotateX.slider.getValue()); - audioProcessor.currentRotateX.apply(); + audioProcessor.currentRotateX->setValue(rotateX.slider.getValue()); + audioProcessor.currentRotateX->apply(); } if (fixedRotateY->getToggleState()) { - audioProcessor.currentRotateY.setValue(rotateY.slider.getValue()); - audioProcessor.currentRotateY.apply(); + audioProcessor.currentRotateY->setValue(rotateY.slider.getValue()); + audioProcessor.currentRotateY->apply(); } if (fixedRotateZ->getToggleState()) { - audioProcessor.currentRotateZ.setValue(rotateZ.slider.getValue()); - audioProcessor.currentRotateZ.apply(); + audioProcessor.currentRotateZ->setValue(rotateZ.slider.getValue()); + audioProcessor.currentRotateZ->apply(); } audioProcessor.fixedRotateX = fixedRotateX->getToggleState(); @@ -55,8 +53,8 @@ ObjComponent::ObjComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessor rotateSpeed.slider.onValueChange = [this] { juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock); - audioProcessor.rotateSpeed.setValue(rotateSpeed.slider.getValue()); - audioProcessor.rotateSpeed.apply(); + audioProcessor.rotateSpeed->setValue(rotateSpeed.slider.getValue()); + audioProcessor.rotateSpeed->apply(); }; addAndMakeVisible(resetRotation); @@ -75,12 +73,12 @@ ObjComponent::ObjComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessor mouseRotate.setToggleState(false, juce::NotificationType::dontSendNotification); juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock); - audioProcessor.currentRotateX.setValue(0); - audioProcessor.currentRotateY.setValue(0); - audioProcessor.currentRotateZ.setValue(0); - audioProcessor.currentRotateX.apply(); - audioProcessor.currentRotateY.apply(); - audioProcessor.currentRotateZ.apply(); + audioProcessor.currentRotateX->setValue(0); + audioProcessor.currentRotateY->setValue(0); + audioProcessor.currentRotateZ->setValue(0); + audioProcessor.currentRotateX->apply(); + audioProcessor.currentRotateY->apply(); + audioProcessor.currentRotateZ->apply(); }; auto doc = juce::XmlDocument::parse(BinaryData::fixed_rotate_svg); diff --git a/Source/ObjComponent.h b/Source/ObjComponent.h index a8c2412..1919d72 100644 --- a/Source/ObjComponent.h +++ b/Source/ObjComponent.h @@ -17,11 +17,11 @@ private: OscirenderAudioProcessor& audioProcessor; OscirenderAudioProcessorEditor& pluginEditor; - EffectComponent focalLength{0, 2, 0.01, audioProcessor.focalLength, false}; - EffectComponent rotateX{-1, 1, 0.01, audioProcessor.rotateX, false}; - EffectComponent rotateY{-1, 1, 0.01, audioProcessor.rotateY, false}; - EffectComponent rotateZ{-1, 1, 0.01, audioProcessor.rotateZ, false}; - EffectComponent rotateSpeed{-1, 1, 0.01, audioProcessor.rotateSpeed, false}; + EffectComponent focalLength{0, 2, 0.001, *audioProcessor.focalLength, false}; + EffectComponent rotateX{-1, 1, 0.001, *audioProcessor.rotateX, false}; + EffectComponent rotateY{-1, 1, 0.001, *audioProcessor.rotateY, false}; + EffectComponent rotateZ{-1, 1, 0.001, *audioProcessor.rotateZ, false}; + EffectComponent rotateSpeed{-1, 1, 0.001, *audioProcessor.rotateSpeed, false}; juce::TextButton resetRotation{"Reset Rotation"}; juce::ToggleButton mouseRotate{"Rotate with Mouse (Esc to disable)"}; diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index c4047ae..d0587c9 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -35,24 +35,33 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() juce::SpinLock::ScopedLockType lock(effectsLock); - allEffects.push_back(std::make_shared(std::make_shared(), "Bit Crush", "bitCrush")); - allEffects.push_back(std::make_shared(std::make_shared(), "Bulge", "bulge")); - allEffects.push_back(std::make_shared(std::make_shared(), "2D Rotate Speed", "rotateSpeed")); - allEffects.push_back(std::make_shared(std::make_shared(), "Vector cancelling", "vectorCancelling")); - allEffects.push_back(std::make_shared(std::make_shared(true), "Vertical shift", "verticalDistort")); - allEffects.push_back(std::make_shared(std::make_shared(false), "Horizontal shift", "horizontalDistort")); - allEffects.push_back(std::make_shared(std::make_shared(), "Smoothing", "smoothing")); - allEffects.push_back(std::make_shared(wobbleEffect, "Wobble", "wobble")); + allEffects.push_back(std::make_shared(std::make_shared(), "Bit Crush", "bitCrush", true)); + allEffects.push_back(std::make_shared(std::make_shared(), "Bulge", "bulge", true)); + allEffects.push_back(std::make_shared(std::make_shared(), "2D Rotate Speed", "rotateSpeed", true)); + allEffects.push_back(std::make_shared(std::make_shared(), "Vector cancelling", "vectorCancelling", true)); + allEffects.push_back(std::make_shared(std::make_shared(true), "Vertical shift", "verticalDistort", true)); + allEffects.push_back(std::make_shared(std::make_shared(false), "Horizontal shift", "horizontalDistort", true)); + allEffects.push_back(std::make_shared(std::make_shared(), "Smoothing", "smoothing", true)); + allEffects.push_back(std::make_shared(wobbleEffect, "Wobble", "wobble", true)); allEffects.push_back(std::make_shared( delayEffect, std::vector{ EffectDetails{ "Delay Decay", "delayDecay", 0 }, EffectDetails{ "Delay Length", "delayEchoLength", 0.5 } - } + }, true )); allEffects.push_back(traceMax); allEffects.push_back(traceMin); + permanentEffects.push_back(frequencyEffect); + permanentEffects.push_back(volumeEffect); + permanentEffects.push_back(thresholdEffect); + permanentEffects.push_back(rotateSpeed); + permanentEffects.push_back(rotateX); + permanentEffects.push_back(rotateY); + permanentEffects.push_back(rotateZ); + permanentEffects.push_back(focalLength); + for (int i = 0; i < 5; i++) { addLuaSlider(); } @@ -113,7 +122,6 @@ void OscirenderAudioProcessor::changeProgramName(int index, const juce::String& void OscirenderAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) { currentSampleRate = sampleRate; pitchDetector.setSampleRate(sampleRate); - updateAngleDelta(); } void OscirenderAudioProcessor::releaseResources() { @@ -158,7 +166,7 @@ void OscirenderAudioProcessor::addLuaSlider() { sliderNum = (sliderNum - mod) / 26; } - luaEffects.push_back(std::make_shared(std::make_shared(sliderName, *this), "Lua " + sliderName, "lua" + sliderName)); + luaEffects.push_back(std::make_shared(std::make_shared(sliderName, *this), "Lua " + sliderName, "lua" + sliderName, false)); } // effectsLock should be held when calling this @@ -170,14 +178,11 @@ void OscirenderAudioProcessor::updateLuaValues() { // parsersLock should be held when calling this void OscirenderAudioProcessor::updateObjValues() { - focalLength.apply(); - rotateX.apply(); - rotateSpeed.apply(); -} - -void OscirenderAudioProcessor::updateAngleDelta() { - auto cyclesPerSample = frequency / currentSampleRate; - thetaDelta = cyclesPerSample * 2.0 * juce::MathConstants::pi; + focalLength->apply(); + rotateX->apply(); + rotateY->apply(); + rotateZ->apply(); + rotateSpeed->apply(); } // effectsLock MUST be held when calling this @@ -365,7 +370,7 @@ void OscirenderAudioProcessor::updateLengthIncrement() { lengthIncrement = juce::jmax(proportionalLength / (currentSampleRate / frequency), MIN_LENGTH_INCREMENT); } -void OscirenderAudioProcessor::processBlock (juce::AudioBuffer& buffer, juce::MidiBuffer& midiMessages) +void OscirenderAudioProcessor::processBlock(juce::AudioBuffer& buffer, juce::MidiBuffer& midiMessages) { juce::ScopedNoDenormals noDenormals; auto totalNumInputChannels = getTotalNumInputChannels(); @@ -429,6 +434,9 @@ void OscirenderAudioProcessor::processBlock (juce::AudioBuffer& buffer, j for (auto& effect : enabledEffects) { channels = effect->apply(sample, channels); } + for (auto& effect : permanentEffects) { + channels = effect->apply(sample, channels); + } } x = channels.x; @@ -450,8 +458,8 @@ void OscirenderAudioProcessor::processBlock (juce::AudioBuffer& buffer, j audioProducer.write(x, y); - actualTraceMax = juce::jmax(actualTraceMin + MIN_TRACE, juce::jmin(traceMax->getValue(), 1.0)); - actualTraceMin = juce::jmax(MIN_TRACE, juce::jmin(traceMin->getValue(), actualTraceMax - MIN_TRACE)); + actualTraceMax = juce::jmax(actualTraceMin + MIN_TRACE, juce::jmin(traceMaxValue, 1.0)); + actualTraceMin = juce::jmax(MIN_TRACE, juce::jmin(traceMinValue, actualTraceMax - MIN_TRACE)); if (!renderingSample) { incrementShapeDrawing(); diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 49f735b..b38c8df 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -68,10 +68,6 @@ public: void getStateInformation (juce::MemoryBlock& destData) override; void setStateInformation (const void* data, int sizeInBytes) override; - std::atomic frequency = 440.0f; - std::atomic volume = 1.0; - std::atomic threshold = 1.0; - std::atomic currentSampleRate = 0.0; juce::SpinLock effectsLock; @@ -79,88 +75,107 @@ public: std::vector> enabledEffects; std::vector> luaEffects; - // TODO see if there is a way to move this code to .cpp - std::function, double)> onRotationChange = [this](int index, Vector2 input, std::vector details, double sampleRate) { - if (getCurrentFileIndex() != -1) { - auto obj = getCurrentFileParser()->getObject(); - if (obj == nullptr) return input; - obj->setBaseRotation( - rotateX.getValue() * std::numbers::pi, - rotateY.getValue() * std::numbers::pi, - rotateZ.getValue() * std::numbers::pi - ); - } - return input; - }; + std::shared_ptr frequencyEffect = std::make_shared( + [this](int index, Vector2 input, const std::vector& values, double sampleRate) { + frequency = values[0]; + return input; + }, "Frequency", "frequency", 440 + ); + + std::shared_ptr volumeEffect = std::make_shared( + [this](int index, Vector2 input, const std::vector& values, double sampleRate) { + volume = values[0]; + return input; + }, "Volume", "volume", 1 + ); + + std::shared_ptr thresholdEffect = std::make_shared( + [this](int index, Vector2 input, const std::vector& values, double sampleRate) { + threshold = values[0]; + return input; + }, "Threshold", "threshold", 3 + ); - Effect focalLength{ - [this](int index, Vector2 input, std::vector details, double sampleRate) { + std::shared_ptr focalLength = std::make_shared( + [this](int index, Vector2 input, const std::vector& values, double sampleRate) { if (getCurrentFileIndex() != -1) { auto camera = getCurrentFileParser()->getCamera(); if (camera == nullptr) return input; - camera->setFocalLength(details[0].value); + camera->setFocalLength(values[0]); } return input; - }, - "Focal length", - "focalLength", - 1 - }; - Effect rotateX{onRotationChange, "Rotate x", "rotateX", 1}; - Effect rotateY{onRotationChange, "Rotate y", "rotateY", 1}; - Effect rotateZ{onRotationChange, "Rotate z", "rotateZ", 0}; - Effect currentRotateX{ - [this](int index, Vector2 input, std::vector details, double sampleRate) { + }, "Focal length", "focalLength", 1 + ); + std::shared_ptr rotateX = std::make_shared( + [this](int index, Vector2 input, const std::vector& values, double sampleRate) { if (getCurrentFileIndex() != -1) { auto obj = getCurrentFileParser()->getObject(); if (obj == nullptr) return input; - obj->setCurrentRotationX(details[0].value * std::numbers::pi); + obj->setBaseRotationX(values[0] * std::numbers::pi); } return input; - }, - "Current Rotate x", - "currentRotateX", - 0 - }; - Effect currentRotateY{ - [this](int index, Vector2 input, std::vector details, double sampleRate) { + }, "Rotate x", "rotateX", 1 + ); + std::shared_ptr rotateY = std::make_shared( + [this](int index, Vector2 input, const std::vector& values, double sampleRate) { if (getCurrentFileIndex() != -1) { auto obj = getCurrentFileParser()->getObject(); if (obj == nullptr) return input; - obj->setCurrentRotationY(details[0].value * std::numbers::pi); + obj->setBaseRotationY(values[0] * std::numbers::pi); } return input; - }, - "Current Rotate y", - "currentRotateY", - 0 - }; - Effect currentRotateZ{ - [this](int index, Vector2 input, std::vector details, double sampleRate) { + }, "Rotate y", "rotateY", 1 + ); + std::shared_ptr rotateZ = std::make_shared( + [this](int index, Vector2 input, const std::vector& values, double sampleRate) { if (getCurrentFileIndex() != -1) { auto obj = getCurrentFileParser()->getObject(); if (obj == nullptr) return input; - obj->setCurrentRotationZ(details[0].value * std::numbers::pi); + obj->setBaseRotationZ(values[0] * std::numbers::pi); } return input; - }, - "Current Rotate z", - "currentRotateZ", - 0 - }; - Effect rotateSpeed{ - [this](int index, Vector2 input, std::vector details, double sampleRate) { + }, "Rotate z", "rotateZ", 0 + ); + std::shared_ptr currentRotateX = std::make_shared( + [this](int index, Vector2 input, const std::vector& values, double sampleRate) { if (getCurrentFileIndex() != -1) { auto obj = getCurrentFileParser()->getObject(); if (obj == nullptr) return input; - obj->setRotationSpeed(details[0].value); + obj->setCurrentRotationX(values[0] * std::numbers::pi); } return input; - }, - "Rotate speed", - "rotateSpeed", - 0 - }; + }, "Current Rotate x", "currentRotateX", 0, false + ); + std::shared_ptr currentRotateY = std::make_shared( + [this](int index, Vector2 input, const std::vector& values, double sampleRate) { + if (getCurrentFileIndex() != -1) { + auto obj = getCurrentFileParser()->getObject(); + if (obj == nullptr) return input; + obj->setCurrentRotationY(values[0] * std::numbers::pi); + } + return input; + }, "Current Rotate y", "currentRotateY", 0, false + ); + std::shared_ptr currentRotateZ = std::make_shared( + [this](int index, Vector2 input, const std::vector& values, double sampleRate) { + if (getCurrentFileIndex() != -1) { + auto obj = getCurrentFileParser()->getObject(); + if (obj == nullptr) return input; + obj->setCurrentRotationZ(values[0] * std::numbers::pi); + } + return input; + }, "Current Rotate z", "currentRotateZ", 0, false + ); + std::shared_ptr rotateSpeed = std::make_shared( + [this](int index, Vector2 input, const std::vector& values, double sampleRate) { + if (getCurrentFileIndex() != -1) { + auto obj = getCurrentFileParser()->getObject(); + if (obj == nullptr) return input; + obj->setRotationSpeed(values[0]); + } + return input; + }, "Rotate speed", "rotateSpeed", 0 + ); std::atomic fixedRotateX = false; std::atomic fixedRotateY = false; std::atomic fixedRotateZ = false; @@ -181,7 +196,6 @@ public: std::shared_ptr wobbleEffect = std::make_shared(pitchDetector); void addLuaSlider(); - void updateAngleDelta(); void addFrame(std::vector> frame, int fileIndex) override; void enableEffect(std::shared_ptr effect); void disableEffect(std::shared_ptr effect); @@ -198,8 +212,9 @@ public: juce::String getFileName(int index); std::shared_ptr getFileBlock(int index); private: - double theta = 0.0; - double thetaDelta = 0.0; + std::atomic frequency = 440.0f; + std::atomic volume = 1.0; + std::atomic threshold = 1.0; juce::AbstractFifo frameFifo{ 10 }; std::vector> frameBuffer[10]; @@ -214,27 +229,27 @@ private: double lengthIncrement = 0.0; bool invalidateFrameBuffer = false; + std::vector> permanentEffects; + std::shared_ptr traceMax = std::make_shared( - [this](int index, Vector2 input, std::vector details, double sampleRate) { + [this](int index, Vector2 input, const std::vector& values, double sampleRate) { + traceMaxValue = values[0]; traceMaxEnabled = true; return input; - }, - "Trace max", - "traceMax", - 1 + }, "Trace max", "traceMax", 1, true ); std::shared_ptr traceMin = std::make_shared( - [this](int index, Vector2 input, std::vector details, double sampleRate) { + [this](int index, Vector2 input, const std::vector& values, double sampleRate) { + traceMinValue = values[0]; traceMinEnabled = true; return input; - }, - "Trace min", - "traceMin", - 0 + }, "Trace min", "traceMin", 0, true ); const double MIN_TRACE = 0.005; - double actualTraceMax = traceMax->getValue(); - double actualTraceMin = traceMin->getValue(); + double traceMaxValue = traceMax->getValue(); + double traceMinValue = traceMin->getValue(); + double actualTraceMax = traceMaxValue; + double actualTraceMin = traceMinValue; bool traceMaxEnabled = false; bool traceMinEnabled = false; diff --git a/Source/audio/BitCrushEffect.cpp b/Source/audio/BitCrushEffect.cpp index 39f62dc..9efdb15 100644 --- a/Source/audio/BitCrushEffect.cpp +++ b/Source/audio/BitCrushEffect.cpp @@ -5,8 +5,8 @@ BitCrushEffect::BitCrushEffect() {} BitCrushEffect::~BitCrushEffect() {} // algorithm from https://www.kvraudio.com/forum/viewtopic.php?t=163880 -Vector2 BitCrushEffect::apply(int index, Vector2 input, std::vector details, double sampleRate) { - double value = details[0].value; +Vector2 BitCrushEffect::apply(int index, Vector2 input, const std::vector& values, double sampleRate) { + double value = values[0]; // change rage of value from 0-1 to 0.0-0.78 double rangedValue = value * 0.78; double powValue = pow(2.0f, 1.0 - rangedValue) - 1.0; diff --git a/Source/audio/BitCrushEffect.h b/Source/audio/BitCrushEffect.h index 4747a7e..9b93e54 100644 --- a/Source/audio/BitCrushEffect.h +++ b/Source/audio/BitCrushEffect.h @@ -7,5 +7,5 @@ public: BitCrushEffect(); ~BitCrushEffect(); - Vector2 apply(int index, Vector2 input, std::vector details, double sampleRate) override; + Vector2 apply(int index, Vector2 input, const std::vector& values, double sampleRate) override; }; \ No newline at end of file diff --git a/Source/audio/BulgeEffect.cpp b/Source/audio/BulgeEffect.cpp index 0db8fa5..af2e649 100644 --- a/Source/audio/BulgeEffect.cpp +++ b/Source/audio/BulgeEffect.cpp @@ -4,8 +4,8 @@ BulgeEffect::BulgeEffect() {} BulgeEffect::~BulgeEffect() {} -Vector2 BulgeEffect::apply(int index, Vector2 input, std::vector details, double sampleRate) { - double value = details[0].value; +Vector2 BulgeEffect::apply(int index, Vector2 input, const std::vector& values, double sampleRate) { + double value = values[0]; double translatedBulge = -value + 1; double r = input.magnitude(); diff --git a/Source/audio/BulgeEffect.h b/Source/audio/BulgeEffect.h index fef9cbe..c9803d0 100644 --- a/Source/audio/BulgeEffect.h +++ b/Source/audio/BulgeEffect.h @@ -7,5 +7,5 @@ public: BulgeEffect(); ~BulgeEffect(); - Vector2 apply(int index, Vector2 input, std::vector details, double sampleRate) override; + Vector2 apply(int index, Vector2 input, const std::vector&, double sampleRate) override; }; \ No newline at end of file diff --git a/Source/audio/DelayEffect.cpp b/Source/audio/DelayEffect.cpp index 2234c47..ea77eb6 100644 --- a/Source/audio/DelayEffect.cpp +++ b/Source/audio/DelayEffect.cpp @@ -4,9 +4,9 @@ DelayEffect::DelayEffect() {} DelayEffect::~DelayEffect() {} -Vector2 DelayEffect::apply(int index, Vector2 vector, std::vector details, double sampleRate) { - double decay = details[0].value; - double decayLength = details[1].value; +Vector2 DelayEffect::apply(int index, Vector2 vector, const std::vector& values, double sampleRate) { + double decay = values[0]; + double decayLength = values[1]; int delayBufferLength = (int)(sampleRate * decayLength); if (head >= delayBuffer.size()){ head = 0; diff --git a/Source/audio/DelayEffect.h b/Source/audio/DelayEffect.h index 72a74cf..e8921d4 100644 --- a/Source/audio/DelayEffect.h +++ b/Source/audio/DelayEffect.h @@ -7,7 +7,7 @@ public: DelayEffect(); ~DelayEffect(); - Vector2 apply(int index, Vector2 input, std::vector details, double sampleRate) override; + Vector2 apply(int index, Vector2 input, const std::vector& values, double sampleRate) override; private: const static int MAX_DELAY = 192000 * 10; diff --git a/Source/audio/DistortEffect.cpp b/Source/audio/DistortEffect.cpp index 2bbb9fa..38e48be 100644 --- a/Source/audio/DistortEffect.cpp +++ b/Source/audio/DistortEffect.cpp @@ -4,8 +4,8 @@ DistortEffect::DistortEffect(bool vertical) : vertical(vertical) {} DistortEffect::~DistortEffect() {} -Vector2 DistortEffect::apply(int index, Vector2 input, std::vector details, double sampleRate) { - double value = details[0].value; +Vector2 DistortEffect::apply(int index, Vector2 input, const std::vector& values, double sampleRate) { + double value = values[0]; int vertical = (int)this->vertical; if (index % 2 == 0) { input.translate((1 - vertical) * value, vertical * value); diff --git a/Source/audio/DistortEffect.h b/Source/audio/DistortEffect.h index cd9e851..f92e658 100644 --- a/Source/audio/DistortEffect.h +++ b/Source/audio/DistortEffect.h @@ -7,7 +7,7 @@ public: DistortEffect(bool vertical); ~DistortEffect(); - Vector2 apply(int index, Vector2 input, std::vector details, double sampleRate) override; + Vector2 apply(int index, Vector2 input, const std::vector& values, double sampleRate) override; private: bool vertical; }; \ No newline at end of file diff --git a/Source/audio/Effect.cpp b/Source/audio/Effect.cpp index 85a1d0e..f202a55 100644 --- a/Source/audio/Effect.cpp +++ b/Source/audio/Effect.cpp @@ -1,32 +1,44 @@ #include "Effect.h" -Effect::Effect(std::shared_ptr effectApplication, std::vector details) : effectApplication(effectApplication), details(details) {} +Effect::Effect(std::shared_ptr effectApplication, std::vector details, bool smoothValueChange) : effectApplication(effectApplication), details(details), smoothValueChange(smoothValueChange) { + smoothValues = std::vector(details.size(), 0.0); +} -Effect::Effect(std::function, double)> application, std::vector details) : application(application), details(details) {} +Effect::Effect(std::function&, double)> application, std::vector details, bool smoothValueChange) : application(application), details(details), smoothValueChange(smoothValueChange) { + smoothValues = std::vector(details.size(), 0.0); +} -Effect::Effect(std::shared_ptr effectApplication, juce::String name, juce::String id) { +Effect::Effect(std::shared_ptr effectApplication, juce::String name, juce::String id, bool smoothValueChange) : smoothValueChange(smoothValueChange) { this->effectApplication = effectApplication; details = std::vector(1, EffectDetails{name, id, 0.0}); + smoothValues = std::vector(details.size(), 0.0); } -Effect::Effect(juce::String name, juce::String id, double value) { +Effect::Effect(juce::String name, juce::String id, double value, bool smoothValueChange) : smoothValueChange(smoothValueChange) { details = std::vector(1, EffectDetails{name, id, value}); + smoothValues = std::vector(details.size(), 0.0); } -Effect::Effect(juce::String name, juce::String id) { +Effect::Effect(juce::String name, juce::String id, bool smoothValueChange) : smoothValueChange(smoothValueChange) { details = std::vector(1, EffectDetails{name, id, 0.0}); + smoothValues = std::vector(details.size(), 0.0); } -Effect::Effect(std::function values, double)> application, juce::String name, juce::String id, double value) { +Effect::Effect(std::function& values, double)> application, juce::String name, juce::String id, double value, bool smoothValueChange) : smoothValueChange(smoothValueChange) { details = std::vector(1, EffectDetails{name, id, value}); + smoothValues = std::vector(details.size(), 0.0); this->application = application; }; Vector2 Effect::apply(int index, Vector2 input) { + double weight = smoothValueChange ? 0.0005 : 1.0; + for (int i = 0; i < details.size(); i++) { + smoothValues[i] = (1.0 - weight) * smoothValues[i] + weight * details[i].value; + } if (application) { - return application(index, input, details, sampleRate); + return application(index, input, smoothValues, sampleRate); } else if (effectApplication != nullptr) { - return effectApplication->apply(index, input, details, sampleRate); + return effectApplication->apply(index, input, smoothValues, sampleRate); } return input; } diff --git a/Source/audio/Effect.h b/Source/audio/Effect.h index 2ed969b..dc3b80b 100644 --- a/Source/audio/Effect.h +++ b/Source/audio/Effect.h @@ -5,12 +5,12 @@ class Effect { public: - Effect(std::shared_ptr effectApplication, std::vector details); - Effect(std::function, double)> application, std::vector details); - Effect(std::shared_ptr effectApplication, juce::String name, juce::String id); - Effect(juce::String name, juce::String id, double value); - Effect(juce::String name, juce::String id); - Effect(std::function, double)> application, juce::String name, juce::String id, double value); + Effect(std::shared_ptr effectApplication, std::vector details, bool smoothValueChange = true); + Effect(std::function&, double)> application, std::vector details, bool smoothValueChange = true); + Effect(std::shared_ptr effectApplication, juce::String name, juce::String id, bool smoothValueChange = true); + Effect(juce::String name, juce::String id, double value, bool smoothValueChange = true); + Effect(juce::String name, juce::String id, bool smoothValueChange = true); + Effect(std::function&, double)> application, juce::String name, juce::String id, double value, bool smoothValueChange = true); Vector2 apply(int index, Vector2 input); void apply(); @@ -26,10 +26,12 @@ public: private: std::vector details; + std::vector smoothValues; + bool smoothValueChange = true; double frequency = 1.0; int precedence = -1; int sampleRate = 192000; - std::function, double)> application; + std::function&, double)> application; std::shared_ptr effectApplication; }; \ No newline at end of file diff --git a/Source/audio/EffectApplication.h b/Source/audio/EffectApplication.h index 3ef913c..50b7a3e 100644 --- a/Source/audio/EffectApplication.h +++ b/Source/audio/EffectApplication.h @@ -12,7 +12,7 @@ class EffectApplication { public: EffectApplication() {}; - virtual Vector2 apply(int index, Vector2 input, std::vector details, double sampleRate) = 0; + virtual Vector2 apply(int index, Vector2 input, const std::vector& values, double sampleRate) = 0; void resetPhase(); double nextPhase(double frequency, double sampleRate); diff --git a/Source/audio/LuaEffect.cpp b/Source/audio/LuaEffect.cpp index 5c71d2a..8213cab 100644 --- a/Source/audio/LuaEffect.cpp +++ b/Source/audio/LuaEffect.cpp @@ -1,14 +1,14 @@ #include "LuaEffect.h" #include "../lua/LuaParser.h" -Vector2 LuaEffect::apply(int index, Vector2 input, std::vector details, double sampleRate) { +Vector2 LuaEffect::apply(int index, Vector2 input, const std::vector& values, double sampleRate) { int fileIndex = audioProcessor.getCurrentFileIndex(); if (fileIndex == -1) { return input; } std::shared_ptr parser = audioProcessor.getCurrentFileParser()->getLua(); if (parser != nullptr) { - parser->setVariable("slider_" + name.toLowerCase(), details[0].value); + parser->setVariable("slider_" + name.toLowerCase(), values[0]); } return input; } diff --git a/Source/audio/LuaEffect.h b/Source/audio/LuaEffect.h index 2dfdb1d..ae5e480 100644 --- a/Source/audio/LuaEffect.h +++ b/Source/audio/LuaEffect.h @@ -8,7 +8,7 @@ class LuaEffect : public EffectApplication { public: LuaEffect(juce::String name, OscirenderAudioProcessor& p) : audioProcessor(p), name(name) {}; - Vector2 apply(int index, Vector2 input, std::vector details, double sampleRate) override; + Vector2 apply(int index, Vector2 input, const std::vector& values, double sampleRate) override; private: OscirenderAudioProcessor& audioProcessor; juce::String name; diff --git a/Source/audio/RotateEffect.cpp b/Source/audio/RotateEffect.cpp index 2a16dba..876c1c8 100644 --- a/Source/audio/RotateEffect.cpp +++ b/Source/audio/RotateEffect.cpp @@ -4,7 +4,7 @@ RotateEffect::RotateEffect() {} RotateEffect::~RotateEffect() {} -Vector2 RotateEffect::apply(int index, Vector2 input, std::vector details, double sampleRate) { - input.rotate(nextPhase(details[0].value, sampleRate)); +Vector2 RotateEffect::apply(int index, Vector2 input, const std::vector& values, double sampleRate) { + input.rotate(nextPhase(values[0], sampleRate)); return input; } diff --git a/Source/audio/RotateEffect.h b/Source/audio/RotateEffect.h index 0b32cfe..282e64e 100644 --- a/Source/audio/RotateEffect.h +++ b/Source/audio/RotateEffect.h @@ -7,5 +7,5 @@ public: RotateEffect(); ~RotateEffect(); - Vector2 apply(int index, Vector2 input, std::vector details, double sampleRate) override; + Vector2 apply(int index, Vector2 input, const std::vector& values, double sampleRate) override; }; \ No newline at end of file diff --git a/Source/audio/SmoothEffect.cpp b/Source/audio/SmoothEffect.cpp index a85cff7..c3ad000 100644 --- a/Source/audio/SmoothEffect.cpp +++ b/Source/audio/SmoothEffect.cpp @@ -4,10 +4,10 @@ SmoothEffect::SmoothEffect() {} SmoothEffect::~SmoothEffect() {} -Vector2 SmoothEffect::apply(int index, Vector2 input, std::vector details, double sampleRate) { - double weight = details[0].value; +Vector2 SmoothEffect::apply(int index, Vector2 input, const std::vector& values, double sampleRate) { + double weight = values[0]; weight *= 0.95; - double strength = 1000000; + double strength = 10; weight = std::log(strength * weight + 1) / std::log(strength + 1); // TODO: This doesn't consider the sample rate! leftAvg = weight * leftAvg + (1 - weight) * input.x; diff --git a/Source/audio/SmoothEffect.h b/Source/audio/SmoothEffect.h index 092b855..9992d35 100644 --- a/Source/audio/SmoothEffect.h +++ b/Source/audio/SmoothEffect.h @@ -7,7 +7,7 @@ public: SmoothEffect(); ~SmoothEffect(); - Vector2 apply(int index, Vector2 input, std::vector details, double sampleRate) override; + Vector2 apply(int index, Vector2 input, const std::vector& values, double sampleRate) override; private: double leftAvg = 0; double rightAvg = 0; diff --git a/Source/audio/VectorCancellingEffect.cpp b/Source/audio/VectorCancellingEffect.cpp index b0cab87..561e80b 100644 --- a/Source/audio/VectorCancellingEffect.cpp +++ b/Source/audio/VectorCancellingEffect.cpp @@ -4,8 +4,8 @@ VectorCancellingEffect::VectorCancellingEffect() {} VectorCancellingEffect::~VectorCancellingEffect() {} -Vector2 VectorCancellingEffect::apply(int index, Vector2 input, std::vector details, double sampleRate) { - double value = details[0].value; +Vector2 VectorCancellingEffect::apply(int index, Vector2 input, const std::vector& values, double sampleRate) { + double value = values[0]; if (value < 0.001) { return input; } diff --git a/Source/audio/VectorCancellingEffect.h b/Source/audio/VectorCancellingEffect.h index 4b3dbe1..6c94161 100644 --- a/Source/audio/VectorCancellingEffect.h +++ b/Source/audio/VectorCancellingEffect.h @@ -7,7 +7,7 @@ public: VectorCancellingEffect(); ~VectorCancellingEffect(); - Vector2 apply(int index, Vector2 input, std::vector details, double sampleRate) override; + Vector2 apply(int index, Vector2 input, const std::vector& values, double sampleRate) override; private: int lastIndex = 0; double nextInvert = 0; diff --git a/Source/audio/WobbleEffect.cpp b/Source/audio/WobbleEffect.cpp index 0fddce7..938a126 100644 --- a/Source/audio/WobbleEffect.cpp +++ b/Source/audio/WobbleEffect.cpp @@ -4,11 +4,11 @@ WobbleEffect::WobbleEffect(PitchDetector& pitchDetector) : pitchDetector(pitchDe WobbleEffect::~WobbleEffect() {} -Vector2 WobbleEffect::apply(int index, Vector2 input, std::vector details, double sampleRate) { +Vector2 WobbleEffect::apply(int index, Vector2 input, const std::vector& values, double sampleRate) { // TODO: this doesn't consider sample rate smoothedFrequency = smoothedFrequency * 0.99995 + pitchDetector.frequency * 0.00005; double theta = nextPhase(smoothedFrequency, sampleRate); - double delta = details[0].value * std::sin(theta); + double delta = values[0] * std::sin(theta); double x = input.x + delta; double y = input.y + delta; diff --git a/Source/audio/WobbleEffect.h b/Source/audio/WobbleEffect.h index cc5dcc3..dd8ba80 100644 --- a/Source/audio/WobbleEffect.h +++ b/Source/audio/WobbleEffect.h @@ -8,7 +8,7 @@ public: WobbleEffect(PitchDetector& pitchDetector); ~WobbleEffect(); - Vector2 apply(int index, Vector2 input, std::vector details, double sampleRate) override; + Vector2 apply(int index, Vector2 input, const std::vector& values, double sampleRate) override; private: PitchDetector& pitchDetector; diff --git a/Source/components/LuaListComponent.cpp b/Source/components/LuaListComponent.cpp index 7b52e92..90c42a0 100644 --- a/Source/components/LuaListComponent.cpp +++ b/Source/components/LuaListComponent.cpp @@ -1,7 +1,7 @@ #include "LuaListComponent.h" LuaListComponent::LuaListComponent(OscirenderAudioProcessor& p, Effect& effect) { - effectComponent = std::make_shared(0.0, 1.0, 0.01, effect); + effectComponent = std::make_shared(0.0, 1.0, 0.001, effect); effectComponent->setCheckboxVisible(false); effectComponent->slider.onValueChange = [this, &effect, &p] { diff --git a/Source/components/VisualiserComponent.cpp b/Source/components/VisualiserComponent.cpp index f6d3924..fb3734c 100644 --- a/Source/components/VisualiserComponent.cpp +++ b/Source/components/VisualiserComponent.cpp @@ -33,10 +33,12 @@ void VisualiserComponent::paint(juce::Graphics& g) { g.setColour(waveformColour); juce::SpinLock::ScopedLockType scope(lock); - paintXY(g, r.removeFromRight(r.getHeight())); + if (buffer.size() > 0) { + paintXY(g, r.removeFromRight(r.getHeight())); - for (int i = 0; i < numChannels; ++i) { - paintChannel(g, r.removeFromTop(channelHeight), i); + for (int i = 0; i < numChannels; ++i) { + paintChannel(g, r.removeFromTop(channelHeight), i); + } } } diff --git a/Source/components/VolumeComponent.cpp b/Source/components/VolumeComponent.cpp index f20ec0f..bb7a119 100644 --- a/Source/components/VolumeComponent.cpp +++ b/Source/components/VolumeComponent.cpp @@ -28,11 +28,11 @@ VolumeComponent::VolumeComponent(OscirenderAudioProcessor& p) : audioProcessor(p thresholdSlider.setColour(juce::Slider::ColourIds::thumbColourId, juce::Colours::black); volumeSlider.onValueChange = [this]() { - audioProcessor.volume = volumeSlider.getValue(); + audioProcessor.volumeEffect->setValue(volumeSlider.getValue()); }; thresholdSlider.onValueChange = [this]() { - audioProcessor.threshold = thresholdSlider.getValue(); + audioProcessor.thresholdEffect->setValue(thresholdSlider.getValue()); }; auto doc = juce::XmlDocument::parse(BinaryData::volume_svg); diff --git a/Source/concurrency/BufferProducer.h b/Source/concurrency/BufferProducer.h index 2ac95bc..4ea60c2 100644 --- a/Source/concurrency/BufferProducer.h +++ b/Source/concurrency/BufferProducer.h @@ -3,6 +3,35 @@ #include #include "BufferConsumer.h" +// This is needed over juce::SpinLock because juce::SpinLock yeilds, which +// leads to some consumers never holding the lock. +// TODO: verify that this is a legitimate solution. +struct crude_spinlock { + std::atomic lock_ = {0}; + + void lock() noexcept { + for (;;) { + // Optimistically assume the lock is free on the first try + if (!lock_.exchange(true, std::memory_order_acquire)) { + return; + } + // Wait for lock to be released without generating cache misses + while (lock_.load(std::memory_order_relaxed)) {} + } + } + + bool try_lock() noexcept { + // First do a relaxed load to check if lock is free in order to prevent + // unnecessary cache misses if someone does while(!try_lock()) + return !lock_.load(std::memory_order_relaxed) && + !lock_.exchange(true, std::memory_order_acquire); + } + + void unlock() noexcept { + lock_.store(false, std::memory_order_release); + } +}; + class BufferProducer { public: BufferProducer() {} @@ -13,16 +42,17 @@ public: // being written to. // This is only called by the thread that owns the consumer thread. void registerConsumer(std::shared_ptr consumer) { - juce::SpinLock::ScopedLockType scope(lock); + lock.lock(); consumers.push_back(consumer); bufferPositions.push_back(0); consumer->getBuffer(true); + lock.unlock(); } // This is only called by the thread that owns the consumer thread. // This can't happen at the same time as write() it locks the producer lock. void unregisterConsumer(std::shared_ptr consumer) { - juce::SpinLock::ScopedLockType scope(lock); + lock.lock(); for (int i = 0; i < consumers.size(); i++) { if (consumers[i] == consumer) { consumer->releaseLock(); @@ -31,11 +61,12 @@ public: break; } } + lock.unlock(); } // Writes a sample to the current buffer for all consumers. void write(float left, float right) { - juce::SpinLock::ScopedLockType scope(lock); + lock.lock(); for (int i = 0; i < consumers.size(); i++) { std::shared_ptr> buffer = consumers[i]->getBuffer(false); if (buffer == nullptr) { @@ -54,10 +85,11 @@ public: consumers[i]->finishedWriting(); } } + lock.unlock(); } private: - juce::SpinLock lock; + crude_spinlock lock; std::vector> consumers; std::vector bufferPositions; }; \ No newline at end of file diff --git a/Source/obj/WorldObject.cpp b/Source/obj/WorldObject.cpp index cf6c6c8..3981a18 100644 --- a/Source/obj/WorldObject.cpp +++ b/Source/obj/WorldObject.cpp @@ -207,10 +207,16 @@ WorldObject::WorldObject(std::string obj_string) { } } -void WorldObject::setBaseRotation(double x, double y, double z) { +void WorldObject::setBaseRotationX(double x) { baseRotateX = x; - baseRotateY = y; - baseRotateZ = z; +} + +void WorldObject::setBaseRotationY(double y) { + baseRotateY = y; +} + +void WorldObject::setBaseRotationZ(double z) { + baseRotateZ = z; } void WorldObject::setCurrentRotationX(double x) { diff --git a/Source/obj/WorldObject.h b/Source/obj/WorldObject.h index 1f3e15f..e41a9c0 100644 --- a/Source/obj/WorldObject.h +++ b/Source/obj/WorldObject.h @@ -6,7 +6,9 @@ class WorldObject { public: WorldObject(std::string); - void setBaseRotation(double x, double y, double z); + void setBaseRotationX(double x); + void setBaseRotationY(double y); + void setBaseRotationZ(double z); void setCurrentRotationX(double x); void setCurrentRotationY(double y); void setCurrentRotationZ(double z);