diff --git a/Source/EffectsComponent.h b/Source/EffectsComponent.h index 581008a..64522e4 100644 --- a/Source/EffectsComponent.h +++ b/Source/EffectsComponent.h @@ -23,7 +23,7 @@ private: EffectsListBoxModel listBoxModel; DraggableListBox listBox; - EffectComponent frequency = EffectComponent(*audioProcessor.frequencyEffect, false); + EffectComponent frequency = EffectComponent(audioProcessor, *audioProcessor.frequencyEffect, false); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(EffectsComponent) }; \ No newline at end of file diff --git a/Source/ObjComponent.h b/Source/ObjComponent.h index 72f8c0f..f25418a 100644 --- a/Source/ObjComponent.h +++ b/Source/ObjComponent.h @@ -17,11 +17,11 @@ private: OscirenderAudioProcessor& audioProcessor; OscirenderAudioProcessorEditor& pluginEditor; - EffectComponent focalLength{*audioProcessor.focalLength, false}; - EffectComponent rotateX{*audioProcessor.rotateX, false}; - EffectComponent rotateY{*audioProcessor.rotateY, false}; - EffectComponent rotateZ{*audioProcessor.rotateZ, false}; - EffectComponent rotateSpeed{*audioProcessor.rotateSpeed, false}; + EffectComponent focalLength{audioProcessor, *audioProcessor.focalLength, false}; + EffectComponent rotateX{audioProcessor, *audioProcessor.rotateX, false}; + EffectComponent rotateY{audioProcessor, *audioProcessor.rotateY, false}; + EffectComponent rotateZ{audioProcessor, *audioProcessor.rotateZ, false}; + EffectComponent rotateSpeed{audioProcessor, *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 39241fa..5ea915c 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -97,7 +97,7 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() permanentEffects.push_back(rotateZ); permanentEffects.push_back(focalLength); - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 26; i++) { addLuaSlider(); } @@ -218,6 +218,9 @@ void OscirenderAudioProcessor::addLuaSlider() { std::make_shared(sliderName, *this), new EffectParameter("Lua " + sliderName, "lua" + sliderName, 0.0, 0.0, 1.0, 0.001, false) )); + + auto& effect = luaEffects.back(); + effect->parameters[0]->disableLfo(); } // effectsLock should be held when calling this diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 35b184e..e96312b 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -162,7 +162,7 @@ public: obj->setRotationSpeed(values[0]); } return input; - }, new EffectParameter("Rotate Speed", "rotateSpeed", 0.0, -1.0, 1.0) + }, new EffectParameter("Rotate Speed", "rotateSpeed3D", 0.0, -1.0, 1.0) ); std::shared_ptr delayEffect = std::make_shared(); diff --git a/Source/audio/Effect.cpp b/Source/audio/Effect.cpp index 190917c..7475c78 100644 --- a/Source/audio/Effect.cpp +++ b/Source/audio/Effect.cpp @@ -28,10 +28,11 @@ void Effect::animateValues() { auto parameter = parameters[i]; float minValue = parameter->min; float maxValue = parameter->max; - float phase = nextPhase(parameter); + float phase = parameter->lfo != nullptr ? nextPhase(parameter) : 0.0; float percentage = phase / (2 * std::numbers::pi); + LfoType type = parameter->lfo != nullptr ? (LfoType)(int)parameter->lfo->getValueUnnormalised() : LfoType::Static; - switch ((LfoType)(int) parameter->lfo->getValueUnnormalised()) { + switch (type) { case LfoType::Sine: actualValues[i] = std::sin(phase) * 0.5 + 0.5; actualValues[i] = actualValues[i] * (maxValue - minValue) + minValue; @@ -56,11 +57,8 @@ void Effect::animateValues() { actualValues[i] = (1 - percentage) * (maxValue - minValue) + minValue; break; case LfoType::Noise: - { - float noise = (float)rand() / RAND_MAX; - actualValues[i] = noise * (maxValue - minValue) + minValue; + actualValues[i] = ((float)rand() / RAND_MAX) * (maxValue - minValue) + minValue; break; - } default: double weight = parameter->smoothValueChange ? 0.0005 : 1.0; actualValues[i] = (1.0 - weight) * actualValues[i] + weight * parameter->getValueUnnormalised(); @@ -110,8 +108,12 @@ void Effect::setPrecedence(int precedence) { void Effect::addListener(int index, juce::AudioProcessorParameter::Listener* listener) { parameters[index]->addListener(listener); - parameters[index]->lfo->addListener(listener); - parameters[index]->lfoRate->addListener(listener); + if (parameters[index]->lfo != nullptr) { + parameters[index]->lfo->addListener(listener); + } + if (parameters[index]->lfoRate != nullptr) { + parameters[index]->lfoRate->addListener(listener); + } if (enabled != nullptr) { enabled->addListener(listener); } @@ -121,8 +123,12 @@ void Effect::removeListener(int index, juce::AudioProcessorParameter::Listener* if (enabled != nullptr) { enabled->removeListener(listener); } - parameters[index]->lfoRate->removeListener(listener); - parameters[index]->lfo->removeListener(listener); + if (parameters[index]->lfoRate != nullptr) { + parameters[index]->lfoRate->removeListener(listener); + } + if (parameters[index]->lfo != nullptr) { + parameters[index]->lfo->removeListener(listener); + } parameters[index]->removeListener(listener); } @@ -135,7 +141,7 @@ void Effect::markEnableable(bool enable) { } juce::String Effect::getId() { - return parameters[0]->id; + return parameters[0]->paramID; } juce::String Effect::getName() { diff --git a/Source/audio/EffectParameter.h b/Source/audio/EffectParameter.h index caa4068..a8f6392 100644 --- a/Source/audio/EffectParameter.h +++ b/Source/audio/EffectParameter.h @@ -2,16 +2,13 @@ #include "../shape/Vector2.h" #include -class FloatParameter : public juce::AudioProcessorParameter { +class FloatParameter : public juce::AudioProcessorParameterWithID { public: - juce::String name; - juce::String id; - std::atomic min = 0.0; std::atomic max = 1.0; std::atomic step = 0.001; - FloatParameter(juce::String name, juce::String id, float value, float min, float max, float step = 0.001, juce::String label = "") : name(name), id(id), value(value), min(min), max(max), step(step), label(label) {} + FloatParameter(juce::String name, juce::String id, float value, float min, float max, float step = 0.001, juce::String label = "") : juce::AudioProcessorParameterWithID(id, name), value(value), min(min), max(max), step(step), label(label) {} juce::String getName(int maximumStringLength) const override { return name.substring(0, maximumStringLength); @@ -105,15 +102,12 @@ private: juce::String label; }; -class IntParameter : public juce::AudioProcessorParameter { +class IntParameter : public juce::AudioProcessorParameterWithID { public: - juce::String name; - juce::String id; - std::atomic min = 0; std::atomic max = 10; - IntParameter(juce::String name, juce::String id, int value, int min, int max) : name(name), id(id), value(value), min(min), max(max) {} + IntParameter(juce::String name, juce::String id, int value, int min, int max) : AudioProcessorParameterWithID(name, id), value(value), min(min), max(max) {} juce::String getName(int maximumStringLength) const override { return name.substring(0, maximumStringLength); @@ -270,13 +264,28 @@ public: class EffectParameter : public FloatParameter { public: std::atomic smoothValueChange = true; - LfoTypeParameter* lfo = new LfoTypeParameter(name + " LFO", id + "Lfo", 1); - FloatParameter* lfoRate = new FloatParameter(name + " LFO Rate", id + "LfoRate", 1.0f, 0.0f, 100.0f, 0.1f, "Hz"); + LfoTypeParameter* lfo = new LfoTypeParameter(name + " LFO", paramID + "Lfo", 1); + FloatParameter* lfoRate = new FloatParameter(name + " LFO Rate", paramID + "LfoRate", 1.0f, 0.0f, 100.0f, 0.1f, "Hz"); std::atomic phase = 0.0f; std::vector getParameters() { - return { this, lfo, lfoRate }; + std::vector parameters; + parameters.push_back(this); + if (lfo != nullptr) { + parameters.push_back(lfo); + } + if (lfoRate != nullptr) { + parameters.push_back(lfoRate); + } + return parameters; } + void disableLfo() { + delete lfo; + delete lfoRate; + lfo = nullptr; + lfoRate = nullptr; + } + EffectParameter(juce::String name, juce::String id, float value, float min, float max, float step = 0.001, bool smoothValueChange = true) : FloatParameter(name, id, value, min, max, step), smoothValueChange(smoothValueChange) {} }; \ No newline at end of file diff --git a/Source/components/EffectComponent.cpp b/Source/components/EffectComponent.cpp index cad5e23..c4cdff5 100644 --- a/Source/components/EffectComponent.cpp +++ b/Source/components/EffectComponent.cpp @@ -1,6 +1,6 @@ #include "EffectComponent.h" -EffectComponent::EffectComponent(Effect& effect, int index) : effect(effect), index(index) { +EffectComponent::EffectComponent(OscirenderAudioProcessor& p, Effect& effect, int index) : effect(effect), index(index), audioProcessor(p) { addAndMakeVisible(slider); addAndMakeVisible(selected); addAndMakeVisible(lfo); @@ -20,13 +20,13 @@ EffectComponent::EffectComponent(Effect& effect, int index) : effect(effect), in setupComponent(); } -EffectComponent::EffectComponent(Effect& effect, int index, bool checkboxVisible) : EffectComponent(effect, index) { +EffectComponent::EffectComponent(OscirenderAudioProcessor& p, Effect& effect, int index, bool checkboxVisible) : EffectComponent(p, effect, index) { setCheckboxVisible(checkboxVisible); } -EffectComponent::EffectComponent(Effect& effect) : EffectComponent(effect, 0) {} +EffectComponent::EffectComponent(OscirenderAudioProcessor& p, Effect& effect) : EffectComponent(p, effect, 0) {} -EffectComponent::EffectComponent(Effect& effect, bool checkboxVisible) : EffectComponent(effect) { +EffectComponent::EffectComponent(OscirenderAudioProcessor& p, Effect& effect, bool checkboxVisible) : EffectComponent(p, effect) { setCheckboxVisible(checkboxVisible); } @@ -42,14 +42,17 @@ void EffectComponent::setupComponent() { bool enabled = effect.enabled == nullptr || effect.enabled->getValue(); selected.setToggleState(enabled, juce::dontSendNotification); - lfo.setSelectedId(parameter->lfo->getValueUnnormalised(), juce::dontSendNotification); - - lfo.onChange = [this]() { - if (lfo.getSelectedId() != 0) { - effect.parameters[index]->lfo->setUnnormalisedValueNotifyingHost(lfo.getSelectedId()); - } - }; + lfoEnabled = parameter->lfo != nullptr && parameter->lfoRate != nullptr; + if (lfoEnabled) { + lfo.setSelectedId(parameter->lfo->getValueUnnormalised(), juce::dontSendNotification); + lfo.onChange = [this]() { + if (lfo.getSelectedId() != 0) { + effect.parameters[index]->lfo->setUnnormalisedValueNotifyingHost(lfo.getSelectedId()); + } + }; + } + min.textBox.setValue(parameter->min, juce::dontSendNotification); max.textBox.setValue(parameter->max, juce::dontSendNotification); @@ -92,7 +95,9 @@ void EffectComponent::resized() { component->setBounds(componentBounds); } - lfo.setBounds(bounds.removeFromRight(100).reduced(5)); + if (lfoEnabled) { + lfo.setBounds(bounds.removeFromRight(100).reduced(5)); + } auto checkboxLabel = bounds.removeFromLeft(110); @@ -132,6 +137,11 @@ void EffectComponent::parameterGestureChanged(int parameterIndex, bool gestureIs void EffectComponent::handleAsyncUpdate() { setupComponent(); + juce::SpinLock::ScopedLockType lock1(audioProcessor.parsersLock); + juce::SpinLock::ScopedLockType lock2(audioProcessor.effectsLock); + if (effect.getId().contains("lua")) { + effect.apply(); + } } void EffectComponent::setComponent(std::shared_ptr component) { diff --git a/Source/components/EffectComponent.h b/Source/components/EffectComponent.h index 30acc0a..d02b1dd 100644 --- a/Source/components/EffectComponent.h +++ b/Source/components/EffectComponent.h @@ -34,10 +34,10 @@ class SmallComboBoxArrow : public juce::LookAndFeel_V4 { class EffectComponent : public juce::Component, public juce::AudioProcessorParameter::Listener, juce::AsyncUpdater { public: - EffectComponent(Effect& effect, int index); - EffectComponent(Effect& effect, int index, bool checkboxVisible); - EffectComponent(Effect& effect); - EffectComponent(Effect& effect, bool checkboxVisible); + EffectComponent(OscirenderAudioProcessor& p, Effect& effect, int index); + EffectComponent(OscirenderAudioProcessor& p, Effect& effect, int index, bool checkboxVisible); + EffectComponent(OscirenderAudioProcessor& p, Effect& effect); + EffectComponent(OscirenderAudioProcessor& p, Effect& effect, bool checkboxVisible); ~EffectComponent(); void resized() override; @@ -60,8 +60,10 @@ public: private: void setupComponent(); bool checkboxVisible = true; + bool lfoEnabled = true; juce::Rectangle textBounds; std::shared_ptr component; + OscirenderAudioProcessor& audioProcessor; juce::Label popupLabel; LabelledTextBox min{"Min"}; diff --git a/Source/components/EffectsListComponent.cpp b/Source/components/EffectsListComponent.cpp index 6929b92..df69b41 100644 --- a/Source/components/EffectsListComponent.cpp +++ b/Source/components/EffectsListComponent.cpp @@ -3,7 +3,7 @@ EffectsListComponent::EffectsListComponent(DraggableListBox& lb, AudioEffectListBoxItemData& data, int rn, std::shared_ptr effect) : DraggableListBoxItem(lb, data, rn), effect(effect) { auto parameters = effect->parameters; for (int i = 0; i < parameters.size(); i++) { - std::shared_ptr effectComponent = std::make_shared(*effect, i, i == 0); + std::shared_ptr effectComponent = std::make_shared(data.audioProcessor, *effect, i, i == 0); // using weak_ptr to avoid circular reference and memory leak std::weak_ptr weakEffectComponent = effectComponent; effectComponent->slider.setValue(parameters[i]->getValueUnnormalised(), juce::dontSendNotification); diff --git a/Source/components/LuaListComponent.cpp b/Source/components/LuaListComponent.cpp index 1ba4aa3..85995a5 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(effect); + effectComponent = std::make_shared(p, effect); effectComponent->setCheckboxVisible(false); effectComponent->slider.onValueChange = [this, &effect, &p] { @@ -21,27 +21,16 @@ void LuaListComponent::resized() { void paintListBoxItem(int sliderNum, juce::Graphics& g, int width, int height, bool rowIsSelected) {} int LuaListBoxModel::getNumRows() { - return audioProcessor.luaEffects.size() + 1; + return audioProcessor.luaEffects.size(); } void LuaListBoxModel::paintListBoxItem(int rowNumber, juce::Graphics& g, int width, int height, bool rowIsSelected) {} juce::Component* LuaListBoxModel::refreshComponentForRow(int rowNum, bool isRowSelected, juce::Component *existingComponentToUpdate) { - if (rowNum < getNumRows() - 1) { - juce::SpinLock::ScopedLockType lock(audioProcessor.effectsLock); - std::unique_ptr item(dynamic_cast(existingComponentToUpdate)); - if (juce::isPositiveAndBelow(rowNum, getNumRows())) { - item = std::make_unique(audioProcessor, *audioProcessor.luaEffects[rowNum]); - } - return item.release(); - } else { - juce::SpinLock::ScopedLockType lock(audioProcessor.effectsLock); - std::unique_ptr item(dynamic_cast(existingComponentToUpdate)); - item = std::make_unique("+"); - item->onClick = [this]() { - audioProcessor.addLuaSlider(); - listBox.updateContent(); - }; - return item.release(); + juce::SpinLock::ScopedLockType lock(audioProcessor.effectsLock); + std::unique_ptr item(dynamic_cast(existingComponentToUpdate)); + if (juce::isPositiveAndBelow(rowNum, getNumRows())) { + item = std::make_unique(audioProcessor, *audioProcessor.luaEffects[rowNum]); } + return item.release(); } diff --git a/Source/components/LuaListComponent.h b/Source/components/LuaListComponent.h index 8a1a7e2..eb2bfbc 100644 --- a/Source/components/LuaListComponent.h +++ b/Source/components/LuaListComponent.h @@ -28,7 +28,7 @@ public: juce::Component* refreshComponentForRow(int sliderNum, bool isRowSelected, juce::Component *existingComponentToUpdate) override; private: - int numSliders = 5; + int numSliders = 26; juce::ListBox& listBox; OscirenderAudioProcessor& audioProcessor; };