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 247ff16bae7789dbb271d0d20e66c8a477c94913
parent 20e99c40b7af834e4a4b9b968550fc76b6e04a9d
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Sat, 10 Aug 2024 13:21:51 +0200

implement new part select buttons & part active LEDs

Diffstat:
Msource/nord/n2x/n2xJucePlugin/n2xEditor.cpp | 5++++-
Msource/nord/n2x/n2xJucePlugin/n2xParameterDrivenLed.cpp | 7++++---
Msource/nord/n2x/n2xJucePlugin/n2xParameterDrivenLed.h | 5++++-
Msource/nord/n2x/n2xJucePlugin/n2xPart.cpp | 13++++++++-----
Asource/nord/n2x/n2xJucePlugin/n2xPartLed.cpp | 26++++++++++++++++++++++++++
Asource/nord/n2x/n2xJucePlugin/n2xPartLed.h | 18++++++++++++++++++
Msource/nord/n2x/n2xJucePlugin/n2xParts.cpp | 13+++++++++----
Msource/nord/n2x/n2xJucePlugin/n2xParts.h | 2++
Msource/nord/n2x/n2xJucePlugin/parameterDescriptions_n2x.json | 8++++----
9 files changed, 79 insertions(+), 18 deletions(-)

diff --git a/source/nord/n2x/n2xJucePlugin/n2xEditor.cpp b/source/nord/n2x/n2xJucePlugin/n2xEditor.cpp @@ -153,7 +153,10 @@ namespace n2xJucePlugin genericUI::Button<juce::DrawableButton>* Editor::createJuceComponent(genericUI::Button<juce::DrawableButton>* _button, genericUI::UiObject& _object, const std::string& _name, const juce::DrawableButton::ButtonStyle _buttonStyle) { - if(_name == "PerfMidiChannelA" || _name == "PerfMidiChannelB" || _name == "PerfMidiChannelC" || _name == "PerfMidiChannelD") + if( _name == "PerfSlotActiveA" || + _name == "PerfSlotActiveB" || + _name == "PerfSlotActiveC" || + _name == "PerfSlotActiveD") return new Part(*this, _name, _buttonStyle); return jucePluginEditorLib::Editor::createJuceComponent(_button, _object, _name, _buttonStyle); diff --git a/source/nord/n2x/n2xJucePlugin/n2xParameterDrivenLed.cpp b/source/nord/n2x/n2xJucePlugin/n2xParameterDrivenLed.cpp @@ -7,10 +7,11 @@ namespace n2xJucePlugin { - ParameterDrivenLed::ParameterDrivenLed(Editor& _editor, const std::string& _component, const std::string& _parameter) + ParameterDrivenLed::ParameterDrivenLed(Editor& _editor, const std::string& _component, std::string _parameter, uint8_t _part/* = CurrentPart*/) : m_editor(_editor) - , m_parameterName(_parameter) + , m_parameterName(std::move(_parameter)) , m_led(_editor.findComponentT<juce::Button>(_component)) + , m_part(_part) { auto& c = _editor.getN2xController(); @@ -31,7 +32,7 @@ namespace n2xJucePlugin { const auto& c = m_editor.getN2xController(); - m_param = c.getParameter(m_parameterName, c.getCurrentPart()); + m_param = c.getParameter(m_parameterName, m_part == CurrentPart ? c.getCurrentPart() : m_part); m_onParamChanged.set(m_param, [this](const pluginLib::Parameter* _parameter) { diff --git a/source/nord/n2x/n2xJucePlugin/n2xParameterDrivenLed.h b/source/nord/n2x/n2xJucePlugin/n2xParameterDrivenLed.h @@ -16,7 +16,9 @@ namespace n2xJucePlugin class ParameterDrivenLed { public: - explicit ParameterDrivenLed(Editor& _editor, const std::string& _component, const std::string& _parameter); + static constexpr uint8_t CurrentPart = 0xff; + + explicit ParameterDrivenLed(Editor& _editor, const std::string& _component, std::string _parameter, uint8_t _part = CurrentPart); virtual ~ParameterDrivenLed() = default; protected: @@ -32,6 +34,7 @@ namespace n2xJucePlugin Editor& m_editor; const std::string m_parameterName; juce::Button* m_led; + const uint8_t m_part; pluginLib::ParameterListener m_onParamChanged; pluginLib::EventListener<uint8_t> m_onCurrentPartChanged; diff --git a/source/nord/n2x/n2xJucePlugin/n2xPart.cpp b/source/nord/n2x/n2xJucePlugin/n2xPart.cpp @@ -30,19 +30,22 @@ namespace n2xJucePlugin juce::PopupMenu menuChannel; const auto mp = static_cast<n2x::MultiParam>(n2x::MultiParam::SlotAMidiChannel + getPart()); - const auto ch = controller.getMultiParameter(mp); + const auto name = std::string("PerfMidiChannel") + static_cast<char>('A' + getPart()); + auto* param = controller.getParameter(name, 0); + const auto ch = param->getUnnormalizedValue(); + for(uint8_t c=0; c<16; ++c) { - menuChannel.addItem((std::string("Channel ") + std::to_string(c+1)).c_str(), true, c == ch, [&controller, c, mp] + menuChannel.addItem((std::string("Channel ") + std::to_string(c+1)).c_str(), true, c == ch, [param, c] { - controller.setMultiParameter(mp, c); + param->setUnnormalizedValueNotifyingHost(c, pluginLib::Parameter::Origin::Ui); }); } menuChannel.addSeparator(); - menuChannel.addItem("Off", true, ch == 16, [&controller, mp] + menuChannel.addItem("Off", true, ch >= 16, [param] { - controller.setMultiParameter(mp, 16); + param->setUnnormalizedValueNotifyingHost(16, pluginLib::Parameter::Origin::Ui); }); menu.addSubMenu("Midi Channel", menuChannel); diff --git a/source/nord/n2x/n2xJucePlugin/n2xPartLed.cpp b/source/nord/n2x/n2xJucePlugin/n2xPartLed.cpp @@ -0,0 +1,26 @@ +#include "n2xPartLed.h" + +#include "jucePluginLib/parameter.h" + +namespace n2xJucePlugin +{ + namespace + { + std::string getName(const uint8_t _slot) + { + return std::string("PerfMidiChannel") + static_cast<char>('A' + _slot); + } + } + + PartLed::PartLed(Editor& _editor, const uint8_t _slot) : ParameterDrivenLed(_editor, getName(_slot), getName(_slot), 0) + , m_slot(_slot) + { + bind(); + disableClick(); + } + + bool PartLed::updateToggleState(const pluginLib::Parameter* _parameter) const + { + return _parameter->getUnnormalizedValue() <= 15; + } +} diff --git a/source/nord/n2x/n2xJucePlugin/n2xPartLed.h b/source/nord/n2x/n2xJucePlugin/n2xPartLed.h @@ -0,0 +1,18 @@ +#pragma once + +#include "n2xParameterDrivenLed.h" + +namespace n2xJucePlugin +{ + class PartLed : ParameterDrivenLed + { + public: + PartLed(Editor& _editor, uint8_t _slot); + + protected: + bool updateToggleState(const pluginLib::Parameter* _parameter) const override; + + private: + const uint8_t m_slot; + }; +} diff --git a/source/nord/n2x/n2xJucePlugin/n2xParts.cpp b/source/nord/n2x/n2xJucePlugin/n2xParts.cpp @@ -7,10 +7,15 @@ namespace n2xJucePlugin { Parts::Parts(Editor& _editor): m_editor(_editor) { - m_parts[0] = _editor.findComponentT<Part>("PerfMidiChannelA"); - m_parts[1] = _editor.findComponentT<Part>("PerfMidiChannelB"); - m_parts[2] = _editor.findComponentT<Part>("PerfMidiChannelC"); - m_parts[3] = _editor.findComponentT<Part>("PerfMidiChannelD"); + m_parts[0] = _editor.findComponentT<Part>("PerfSlotActiveA"); + m_parts[1] = _editor.findComponentT<Part>("PerfSlotActiveB"); + m_parts[2] = _editor.findComponentT<Part>("PerfSlotActiveC"); + m_parts[3] = _editor.findComponentT<Part>("PerfSlotActiveD"); + + m_partLeds[0].reset(new PartLed(_editor, 0)); + m_partLeds[1].reset(new PartLed(_editor, 1)); + m_partLeds[2].reset(new PartLed(_editor, 2)); + m_partLeds[3].reset(new PartLed(_editor, 3)); for(uint8_t p=0; p<static_cast<uint8_t>(m_parts.size()); ++p) { diff --git a/source/nord/n2x/n2xJucePlugin/n2xParts.h b/source/nord/n2x/n2xJucePlugin/n2xParts.h @@ -1,6 +1,7 @@ #pragma once #include "n2xPart.h" +#include "n2xPartLed.h" #include "jucePluginLib/event.h" @@ -19,6 +20,7 @@ namespace n2xJucePlugin Editor& m_editor; std::array<Part*,4> m_parts; + std::array<std::unique_ptr<PartLed>,4> m_partLeds; pluginLib::EventListener<uint8_t> onCurrentPartChanged; }; diff --git a/source/nord/n2x/n2xJucePlugin/parameterDescriptions_n2x.json b/source/nord/n2x/n2xJucePlugin/parameterDescriptions_n2x.json @@ -88,10 +88,10 @@ {"index":65, "name":"Lfo2Dest", "min":0, "max":8, "isDiscrete":true}, // MULTI aka Performance - {"class":"NonPartSensitive", "page":10, "index":264, "name":"PerfMidiChannelA", "min":0, "max":15, "isDiscrete":true}, - {"class":"NonPartSensitive", "page":10, "index":265, "name":"PerfMidiChannelB", "min":0, "max":15, "isDiscrete":true}, - {"class":"NonPartSensitive", "page":10, "index":266, "name":"PerfMidiChannelC", "min":0, "max":15, "isDiscrete":true}, - {"class":"NonPartSensitive", "page":10, "index":267, "name":"PerfMidiChannelD", "min":0, "max":15, "isDiscrete":true}, + {"class":"NonPartSensitive", "page":10, "index":264, "name":"PerfMidiChannelA", "min":0, "max":16, "isDiscrete":true}, + {"class":"NonPartSensitive", "page":10, "index":265, "name":"PerfMidiChannelB", "min":0, "max":16, "isDiscrete":true}, + {"class":"NonPartSensitive", "page":10, "index":266, "name":"PerfMidiChannelC", "min":0, "max":16, "isDiscrete":true}, + {"class":"NonPartSensitive", "page":10, "index":267, "name":"PerfMidiChannelD", "min":0, "max":16, "isDiscrete":true}, {"class":"NonPartSensitive", "page":10, "index":268, "name":"PerfLfo1SyncA", "min":0, "max":7, "isDiscrete":true}, {"class":"NonPartSensitive", "page":10, "index":269, "name":"PerfLfo1SyncB", "min":0, "max":7, "isDiscrete":true}, {"class":"NonPartSensitive", "page":10, "index":270, "name":"PerfLfo1SyncC", "min":0, "max":7, "isDiscrete":true},