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 eeeedff1475020d4c3000ec08b5348cd98f63f37
parent fe7527b3990009152ad2830e5bcdace01c732f36
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Wed,  9 Mar 2022 20:02:25 +0100

add ability to have multiple Juce parameters for one synth params

Diffstat:
Msource/jucePlugin/VirusController.cpp | 145++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Msource/jucePlugin/VirusController.h | 21++++++++++++---------
2 files changed, 107 insertions(+), 59 deletions(-)

diff --git a/source/jucePlugin/VirusController.cpp b/source/jucePlugin/VirusController.cpp @@ -26,16 +26,20 @@ namespace Virus registerParams(); // add lambda to enforce updating patches when virus switch from/to multi/single. - (findSynthParam(0, 0x72, 0x7a))->onValueChanged = [this] { - const uint8_t prg = isMultiMode() ? 0x0 : virusLib::SINGLE; - sendSysEx(constructMessage({MessageType::REQUEST_SINGLE, 0x0, prg})); - sendSysEx(constructMessage({MessageType::REQUEST_MULTI, 0x0, prg})); + const auto& params = findSynthParam(0, 0x72, 0x7a); + for (const auto& parameter : params) + { + parameter->onValueChanged = [this] { + const uint8_t prg = isMultiMode() ? 0x0 : virusLib::SINGLE; + sendSysEx(constructMessage({ MessageType::REQUEST_SINGLE, 0x0, prg })); + sendSysEx(constructMessage({ MessageType::REQUEST_MULTI, 0x0, prg })); - if (onMsgDone) - { - onMsgDone(); - } - }; + if (onMsgDone) + { + onMsgDone(); + } + }; + } sendSysEx(constructMessage({MessageType::REQUEST_TOTAL})); sendSysEx(constructMessage({MessageType::REQUEST_ARRANGEMENT})); @@ -84,18 +88,45 @@ namespace Virus } if (p->getDescription().isPublic) { - // lifecycle managed by host - m_synthParams.insert_or_assign(idx, p.get()); + // lifecycle managed by Juce + + auto itExisting = m_synthParams.find(idx); + if (itExisting != m_synthParams.end()) + { + itExisting->second.push_back(p.get()); + } + else + { + ParameterList params; + params.emplace_back(p.get()); + m_synthParams.insert(std::make_pair(idx, std::move(params))); + } + if (isNonPartExclusive) { - jassert(pt == 0); + jassert(part == 0); globalParams->addChild(std::move(p)); } else group->addChild(std::move(p)); } else - m_synthInternalParams.insert_or_assign(idx, std::move(p)); + { + // lifecycle handled by us + + auto itExisting = m_synthInternalParams.find(idx); + if (itExisting != m_synthInternalParams.end()) + { + itExisting->second.push_back(p.get()); + } + else + { + ParameterList params; + params.emplace_back(p.get()); + m_synthInternalParams.insert(std::make_pair(idx, std::move(params))); + } + m_synthInternalParamList.emplace_back(std::move(p)); + } } m_processor.addParameterGroup(std::move(group)); } @@ -152,39 +183,41 @@ namespace Virus } } - Parameter *Controller::findSynthParam(const uint8_t _part, const uint8_t _page, const uint8_t _paramIndex) + const Controller::ParameterList& Controller::findSynthParam(const uint8_t _part, const uint8_t _page, const uint8_t _paramIndex) { const ParamIndex paramIndex{ _page, _part, _paramIndex }; return findSynthParam(paramIndex); } - Parameter* Controller::findSynthParam(const ParamIndex& _paramIndex) + const Controller::ParameterList& Controller::findSynthParam(const ParamIndex& _paramIndex) { const auto it = m_synthParams.find(_paramIndex); - if (it == m_synthParams.end()) - { - const auto iti = m_synthInternalParams.find(_paramIndex); + if (it != m_synthParams.end()) + return it->second; - if (iti == m_synthInternalParams.end()) - return nullptr; + const auto iti = m_synthInternalParams.find(_paramIndex); - return iti->second.get(); + if (iti == m_synthInternalParams.end()) + { + static ParameterList empty; + return empty; } - return it->second; - } - juce::Value *Controller::getParamValue(uint8_t ch, uint8_t bank, uint8_t paramIndex) + return iti->second; + } + + juce::Value* Controller::getParamValue(uint8_t ch, uint8_t bank, uint8_t paramIndex) { - auto *param = findSynthParam(ch, static_cast<uint8_t>(virusLib::PAGE_A + bank), paramIndex); - if (param == nullptr) + const auto& params = findSynthParam(ch, static_cast<uint8_t>(virusLib::PAGE_A + bank), paramIndex); + if (params.empty()) { // unregistered param? jassertfalse; return nullptr; } - return &param->getValueObject(); + return &params.front()->getValueObject(); } juce::Value* Controller::getParamValue(const ParameterType _param) @@ -193,12 +226,12 @@ namespace Virus return res ? &res->getValueObject() : nullptr; } - Parameter* Controller::getParameter(const ParameterType _param) + Parameter* Controller::getParameter(const ParameterType _param) const { return getParameter(_param, 0); } - Parameter *Controller::getParameter(const ParameterType _param, const uint8_t _part) + Parameter* Controller::getParameter(const ParameterType _param, const uint8_t _part) const { if (_part >= m_paramsByParamType.size()) return nullptr; @@ -216,24 +249,32 @@ namespace Virus const auto ch = msg[pos + 1]; const auto index = msg[pos + 2]; const auto value = msg[pos + 3]; - auto param = findSynthParam(ch, page, index); - if (param == nullptr && ch != 0) + + const auto& partParams = findSynthParam(ch, page, index); + + if (partParams.empty() && ch != 0) { // ensure it's not global - param = findSynthParam(0, page, index); - if (param == nullptr) + const auto& globalParams = findSynthParam(0, page, index); + if (globalParams.empty()) { jassertfalse; return; } - auto flags = param->getDescription().classFlags; - if (!(flags & Parameter::Class::GLOBAL) && !(flags & Parameter::Class::NON_PART_SENSITIVE)) + for (const auto& param : globalParams) { - jassertfalse; - return; + auto flags = param->getDescription().classFlags; + if (!(flags & Parameter::Class::GLOBAL) && !(flags & Parameter::Class::NON_PART_SENSITIVE)) + { + jassertfalse; + return; + } } - } - param->setValueFromSynth(value, true); + for (const auto& param : globalParams) + param->setValueFromSynth(value, true); + } + for (const auto& param : partParams) + param->setValueFromSynth(value, true); // TODO: /** If a @@ -357,11 +398,15 @@ namespace Virus for (size_t i = 0; i < std::size(patch.data); i++) { const uint8_t page = virusLib::PAGE_A + static_cast<uint8_t>(i / pageSize); - if (auto *p = findSynthParam(ch, page, i % pageSize)) + const auto& params = findSynthParam(ch, page, i % pageSize); + if (!params.empty()) { - if((p->getDescription().classFlags & Parameter::MULTI_OR_SINGLE) && isMultiMode()) - continue; - p->setValueFromSynth(patch.data[i], true); + for (const auto& param : params) + { + if ((param->getDescription().classFlags & Parameter::MULTI_OR_SINGLE) && isMultiMode()) + continue; + param->setValueFromSynth(patch.data[i], true); + } } } if (onProgramChange) @@ -396,13 +441,13 @@ namespace Virus if (patch.bankNumber == 0) { for (uint8_t pt = 0; pt < 16; pt++) { for(int i = 0; i < 8; i++) { - if (auto* p = findSynthParam(pt, virusLib::PAGE_C, virusLib::PART_MIDI_CHANNEL+i)) { - p->setValueFromSynth(patch.data[virusLib::MD_PART_MIDI_CHANNEL + (i*16) + pt], true); - } + const auto& params = findSynthParam(pt, virusLib::PAGE_C, virusLib::PART_MIDI_CHANNEL + i); + for (const auto& p : params) + p->setValueFromSynth(patch.data[virusLib::MD_PART_MIDI_CHANNEL + (i * 16) + pt], true); } - if (auto* p = findSynthParam(pt, virusLib::PAGE_B, virusLib::CLOCK_TEMPO)) { + const auto& params = findSynthParam(pt, virusLib::PAGE_B, virusLib::CLOCK_TEMPO); + for (const auto& p : params) p->setValueFromSynth(patch.data[virusLib::MD_CLOCK_TEMPO], true); - } /* if (auto* p = findSynthParam(pt, virusLib::PAGE_A, virusLib::EFFECT_SEND)) { p->setValueFromSynth(patch.data[virusLib::MD_PART_EFFECT_SEND], true); }*/ @@ -439,8 +484,8 @@ namespace Virus return; DBG(juce::String::formatted("Set part: %d bank: %s param: %d value: %d", part, page == 0 ? "A" : "B", m.b, m.c)); - auto* p = findSynthParam(part, page, m.b); - if(p) + const auto& params = findSynthParam(part, page, m.b); + for (const auto & p : params) p->setValueFromSynth(m.c, true); } diff --git a/source/jucePlugin/VirusController.h b/source/jucePlugin/VirusController.h @@ -39,10 +39,10 @@ namespace Virus // ch - [0-15] // bank - [0-2] (ABC) // paramIndex - [0-127] - juce::Value *getParamValue(uint8_t ch, uint8_t bank, uint8_t paramIndex); - juce::Value *getParamValue(ParameterType _param); - Parameter* getParameter(ParameterType _param); - Parameter *getParameter(ParameterType _param, uint8_t _part); + juce::Value* getParamValue(uint8_t ch, uint8_t bank, uint8_t paramIndex); + juce::Value* getParamValue(ParameterType _param); + Parameter* getParameter(ParameterType _param) const; + Parameter *getParameter(ParameterType _param, uint8_t _part) const; uint8_t getVirusModel() const; // bank - 0-1 (AB) juce::StringArray getSinglePresetNames(virusLib::BankNumber bank) const; @@ -104,15 +104,18 @@ namespace Virus } }; - std::map<ParamIndex, std::unique_ptr<Parameter>> m_synthInternalParams; - std::map<ParamIndex, Parameter *> m_synthParams; // exposed and managed by audio processor - std::array<std::vector<Parameter*>, 16> m_paramsByParamType; + using ParameterList = std::vector<Parameter*>; + + std::map<ParamIndex, ParameterList> m_synthInternalParams; + std::map<ParamIndex, ParameterList> m_synthParams; // exposed and managed by audio processor + std::array<ParameterList, 16> m_paramsByParamType; + std::vector<std::unique_ptr<Parameter>> m_synthInternalParamList; void registerParams(); // tries to find synth param in both internal and host. // @return found parameter or nullptr if none found. - Parameter *findSynthParam(uint8_t _part, uint8_t _page, uint8_t _paramIndex); - Parameter* findSynthParam(const ParamIndex& _paramIndex); + const ParameterList& findSynthParam(uint8_t _part, uint8_t _page, uint8_t _paramIndex); + const ParameterList& findSynthParam(const ParamIndex& _paramIndex); // unchecked copy for patch data bytes static inline uint8_t copyData(const SysEx &src, int startPos, std::array<uint8_t, kDataSizeInBytes>& dst);