gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

commit 49c40c14640130bce5a00d7b7ba31e43f0ed2984
parent 729dbcfa6a3683aeb317d1329219393009d2d4bd
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Thu, 30 May 2024 22:34:33 +0200

implement parameter overlays and use them to indicate if a parameter is locked

Diffstat:
Msource/jucePluginData/lock.png | 0
Msource/jucePluginData/lock.psd | 0
Msource/jucePluginEditorLib/CMakeLists.txt | 2++
Asource/jucePluginEditorLib/parameterOverlay.cpp | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asource/jucePluginEditorLib/parameterOverlay.h | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Asource/jucePluginEditorLib/parameterOverlays.cpp | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asource/jucePluginEditorLib/parameterOverlays.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Msource/jucePluginEditorLib/pluginEditor.cpp | 3++-
Msource/jucePluginEditorLib/pluginEditor.h | 5+++--
Msource/jucePluginLib/parameterbinding.cpp | 4++++
Msource/jucePluginLib/parameterbinding.h | 5+++++
Msource/juceUiLib/editor.h | 2++
12 files changed, 311 insertions(+), 3 deletions(-)

diff --git a/source/jucePluginData/lock.png b/source/jucePluginData/lock.png Binary files differ. diff --git a/source/jucePluginData/lock.psd b/source/jucePluginData/lock.psd Binary files differ. diff --git a/source/jucePluginEditorLib/CMakeLists.txt b/source/jucePluginEditorLib/CMakeLists.txt @@ -8,6 +8,8 @@ set(SOURCES lcd.cpp lcd.h led.cpp led.h midiPorts.cpp midiPorts.h + parameterOverlay.cpp parameterOverlay.h + parameterOverlays.cpp parameterOverlays.h partbutton.cpp partbutton.h pluginEditor.cpp pluginEditor.h pluginEditorWindow.cpp pluginEditorWindow.h diff --git a/source/jucePluginEditorLib/parameterOverlay.cpp b/source/jucePluginEditorLib/parameterOverlay.cpp @@ -0,0 +1,127 @@ +#include "parameterOverlay.h" +#include "parameterOverlays.h" +#include "pluginEditor.h" +#include "imagePool.h" + +#include "../jucePluginLib/parameter.h" +#include "../juceUiLib/uiObjectStyle.h" + +namespace jucePluginEditorLib +{ + ParameterOverlay::ParameterOverlay(ParameterOverlays& _overlays, juce::Component* _component) : m_overlays(_overlays), m_component(_component) + { + } + + ParameterOverlay::~ParameterOverlay() + { + delete m_imageLock; + setParameter(nullptr); + } + + void ParameterOverlay::onBind(const pluginLib::ParameterBinding::BoundParameter& _parameter) + { + setParameter(_parameter.parameter); + } + + void ParameterOverlay::onUnbind(const pluginLib::ParameterBinding::BoundParameter&) + { + setParameter(nullptr); + } + + ParameterOverlay::OverlayProperties ParameterOverlay::getOverlayProperties() const + { + OverlayProperties result; + + const auto& editor = m_overlays.getEditor(); + + auto& root = editor.getRootObject(); + const auto& props = m_component->getProperties(); + + result.scale = root.getPropertyFloat("overlayScale", 0.2f); + result.scale = props.getWithDefault("overlayScale", result.scale); + + std::string color = root.getProperty("overlayColor", "ffffffff"); + color = props.getWithDefault("overlayColor", juce::String(color)).toString().toStdString(); + genericUI::UiObjectStyle::parseColor(result.color, color); + + result.position.x = root.getPropertyFloat("overlayPosX", 0.0f); + result.position.y = root.getPropertyFloat("overlayPosY", 0.0f); + + result.position.x = props.getWithDefault("overlayPosX", result.position.x); + result.position.y = props.getWithDefault("overlayPosY", result.position.y); + + return result; + } + + void ParameterOverlay::toggleOverlay(juce::DrawableImage*& _image, ImagePool::Type _type, bool _enable) const + { + if(_enable) + { + const auto props = getOverlayProperties(); + + auto updatePosition = [&]() + { + _image->setCentrePosition(static_cast<int>(props.position.x) + m_component->getPosition().x, static_cast<int>(props.position.y) + m_component->getPosition().y); + }; + + if(!_image) + { + auto& editor = m_overlays.getEditor(); + + auto* image = editor.getImagePool().getImage(_type, props.scale); + + if(image) + { + _image = new juce::DrawableImage(*image); + +// _image->setOverlayColour(props.color); // juce cannot do it, it does not multiply but replaced the color entirely + _image->setInterceptsMouseClicks(false, false); + _image->setAlwaysOnTop(true); + + m_component->getParentComponent()->addAndMakeVisible(_image); + } + } + else + { + _image->setVisible(true); + } + + updatePosition(); + } + else if(_image) + { + _image->setVisible(false); + } + } + + void ParameterOverlay::updateOverlays() + { + const auto isLocked = m_parameter != nullptr && m_parameter->isLocked(); + + toggleOverlay(m_imageLock, ImagePool::Type::Lock, isLocked); + } + + void ParameterOverlay::setParameter(pluginLib::Parameter* _parameter) + { + if(m_parameter == _parameter) + return; + + if(m_parameter) + { + m_parameter->onLockedChanged.removeListener(m_parameterLockChangedListener); + m_parameterLockChangedListener = InvalidListenerId; + } + + m_parameter = _parameter; + + if(m_parameter) + { + m_parameterLockChangedListener = m_parameter->onLockedChanged.addListener([this](pluginLib::Parameter*, const bool&) + { + updateOverlays(); + }); + } + + updateOverlays(); + } +} diff --git a/source/jucePluginEditorLib/parameterOverlay.h b/source/jucePluginEditorLib/parameterOverlay.h @@ -0,0 +1,49 @@ +#pragma once + +#include "imagePool.h" +#include "../jucePluginLib/parameterbinding.h" + +namespace juce +{ + class Component; +} + +namespace jucePluginEditorLib +{ + class ParameterOverlays; + + class ParameterOverlay + { + public: + static constexpr size_t InvalidListenerId = pluginLib::Event<int>::InvalidListenerId; + + explicit ParameterOverlay(ParameterOverlays& _overlays, juce::Component* _component); + ~ParameterOverlay(); + + void onBind(const pluginLib::ParameterBinding::BoundParameter& _parameter); + void onUnbind(const pluginLib::ParameterBinding::BoundParameter& _parameter); + + private: + struct OverlayProperties + { + juce::Colour color = juce::Colour(0xffffffff); + float scale = 0.2f; + juce::Point<float> position = juce::Point<float>(0,0);; + }; + + OverlayProperties getOverlayProperties() const; + + void toggleOverlay(juce::DrawableImage*& _image, ImagePool::Type _type, bool _enable) const; + + void updateOverlays(); + void setParameter(pluginLib::Parameter* _parameter); + + ParameterOverlays& m_overlays; + juce::Component* const m_component; + pluginLib::Parameter* m_parameter = nullptr; + + size_t m_parameterLockChangedListener = InvalidListenerId; + + juce::DrawableImage* m_imageLock = nullptr; + }; +} diff --git a/source/jucePluginEditorLib/parameterOverlays.cpp b/source/jucePluginEditorLib/parameterOverlays.cpp @@ -0,0 +1,69 @@ +#include "parameterOverlays.h" + +#include "../jucePluginLib/parameterbinding.h" + +namespace jucePluginEditorLib +{ + ParameterOverlays::ParameterOverlays(Editor& _editor, pluginLib::ParameterBinding& _binding) : m_editor(_editor), m_binding(_binding) + { + m_onBindListenerId = m_binding.onBind.addListener([this](const pluginLib::ParameterBinding::BoundParameter& _param) + { + onBind(_param); + }); + + m_onUnbindListenerId = m_binding.onUnbind.addListener([this](const pluginLib::ParameterBinding::BoundParameter& _param) + { + onUnbind(_param); + }); + } + + ParameterOverlays::~ParameterOverlays() + { + m_binding.onBind.removeListener(m_onBindListenerId); + m_binding.onUnbind.removeListener(m_onUnbindListenerId); + } + + bool ParameterOverlays::registerComponent(juce::Component* _component) + { + if(m_overlays.find(_component) != m_overlays.end()) + return false; + + m_overlays.insert({_component, std::make_unique<ParameterOverlay>(*this, _component)}); + + return true; + } + + void ParameterOverlays::onBind(const pluginLib::ParameterBinding::BoundParameter& _parameter) + { + registerComponent(_parameter.component); + + auto* o = getOverlay(_parameter); + if(!o) + return; + + o->onBind(_parameter); + } + + void ParameterOverlays::onUnbind(const pluginLib::ParameterBinding::BoundParameter& _parameter) + { + auto* o = getOverlay(_parameter); + + if(!o) + return; + + o->onUnbind(_parameter); + } + + ParameterOverlay* ParameterOverlays::getOverlay(const juce::Component* _comp) + { + const auto it = m_overlays.find(_comp); + if(it == m_overlays.end()) + return nullptr; + return it->second.get(); + } + + ParameterOverlay* ParameterOverlays::getOverlay(const pluginLib::ParameterBinding::BoundParameter& _parameter) + { + return getOverlay(_parameter.component); + } +} diff --git a/source/jucePluginEditorLib/parameterOverlays.h b/source/jucePluginEditorLib/parameterOverlays.h @@ -0,0 +1,48 @@ +#pragma once + +#include <map> +#include <memory> + +#include "parameterOverlay.h" + +#include "../jucePluginLib/parameterbinding.h" + +namespace pluginLib +{ + class ParameterBinding; +} + +namespace juce +{ + class Component; +} + +namespace jucePluginEditorLib +{ + class Editor; + + class ParameterOverlays + { + public: + explicit ParameterOverlays(Editor& _editor, pluginLib::ParameterBinding& _binding); + ~ParameterOverlays(); + + bool registerComponent(juce::Component* _component); + + Editor& getEditor() const { return m_editor; } + + private: + void onBind(const pluginLib::ParameterBinding::BoundParameter& _parameter); + void onUnbind(const pluginLib::ParameterBinding::BoundParameter& _parameter); + + ParameterOverlay* getOverlay(const juce::Component* _comp); + ParameterOverlay* getOverlay(const pluginLib::ParameterBinding::BoundParameter& _parameter); + + Editor& m_editor; + pluginLib::ParameterBinding& m_binding; + + std::map<const juce::Component*, std::unique_ptr<ParameterOverlay>> m_overlays; + size_t m_onBindListenerId; + size_t m_onUnbindListenerId; + }; +} diff --git a/source/jucePluginEditorLib/pluginEditor.cpp b/source/jucePluginEditorLib/pluginEditor.cpp @@ -18,6 +18,7 @@ namespace jucePluginEditorLib , m_processor(_processor) , m_binding(_binding) , m_skinFolder(std::move(_skinFolder)) + , m_overlays(*this, _binding) { showDisclaimer(); } @@ -261,7 +262,7 @@ namespace jucePluginEditorLib if(!param) return false; - const auto& controller = m_processor.getController(); + auto& controller = m_processor.getController(); const auto& regions = controller.getParameterDescriptions().getRegions(); const auto paramRegionIds = controller.getRegionIdsForParameter(param); diff --git a/source/jucePluginEditorLib/pluginEditor.h b/source/jucePluginEditorLib/pluginEditor.h @@ -1,6 +1,8 @@ #pragma once #include "imagePool.h" +#include "parameterOverlays.h" +#include "types.h" #include "../juceUiLib/editor.h" @@ -8,8 +10,6 @@ #include "../jucePluginLib/event.h" -#include "types.h" - namespace pluginLib { class ParameterBinding; @@ -105,5 +105,6 @@ namespace jucePluginEditorLib std::vector<std::shared_ptr<juce::TemporaryFile>> m_dragAndDropTempFiles; std::vector<juce::File> m_dragAndDropFiles; ImagePool m_imagePool; + ParameterOverlays m_overlays; }; } diff --git a/source/jucePluginLib/parameterbinding.cpp b/source/jucePluginLib/parameterbinding.cpp @@ -264,10 +264,14 @@ namespace pluginLib m_boundParameters.insert(std::make_pair(_boundParameter.parameter, _boundParameter.component)); m_boundComponents.insert(std::make_pair(_boundParameter.component, _boundParameter.parameter)); + + onBind(_boundParameter); } void ParameterBinding::disableBinding(const BoundParameter& _b) { + onUnbind(_b); + m_boundParameters.erase(_b.parameter); m_boundComponents.erase(_b.component); diff --git a/source/jucePluginLib/parameterbinding.h b/source/jucePluginLib/parameterbinding.h @@ -2,6 +2,8 @@ #include "juce_gui_basics/juce_gui_basics.h" +#include "event.h" + namespace juce { class Button; @@ -44,6 +46,9 @@ namespace pluginLib uint32_t onChangeListenerId = 0; }; + Event<const BoundParameter&> onBind; + Event<const BoundParameter&> onUnbind; + ParameterBinding(Controller& _controller) : m_controller(_controller) { } diff --git a/source/juceUiLib/editor.h b/source/juceUiLib/editor.h @@ -97,6 +97,8 @@ namespace genericUI virtual Button<juce::DrawableButton>* createJuceComponent(Button<juce::DrawableButton>*, UiObject& _object, const std::string& _name, juce::DrawableButton::ButtonStyle) { return nullptr; } virtual Button<juce::TextButton>* createJuceComponent(Button<juce::TextButton>*, UiObject& _object) { return nullptr; } + const UiObject& getRootObject() const { return *(m_rootObject.get()); } + private: EditorInterface& m_interface;