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 2e28812682452266321ddf75d823f48ddec6e1d2
parent a78166a26b89bfde356ec6267af8f5e5888bfd3b
Author: Tal Aviram <me@talaviram.com>
Date:   Sun, 15 Aug 2021 08:30:15 +0300

controller - major changes to use JUCE parameters if parameter is considered public. also fixes some c'tor issues for juce params.

Diffstat:
Msource/jucePlugin/PluginProcessor.cpp | 2+-
Msource/jucePlugin/VirusController.cpp | 67++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msource/jucePlugin/VirusController.h | 10+++++++---
Msource/jucePlugin/VirusParameter.cpp | 24+++++++++++++++++-------
Msource/jucePlugin/VirusParameter.h | 7++++---
5 files changed, 73 insertions(+), 37 deletions(-)

diff --git a/source/jucePlugin/PluginProcessor.cpp b/source/jucePlugin/PluginProcessor.cpp @@ -10,6 +10,7 @@ AudioPluginAudioProcessor::AudioPluginAudioProcessor() : .withOutput("Output", juce::AudioChannelSet::stereo(), true)), m_device(synthLib::findROM()), m_plugin(&m_device) { + auto &ctrl = getController(); // init controller } AudioPluginAudioProcessor::~AudioPluginAudioProcessor() @@ -86,7 +87,6 @@ void AudioPluginAudioProcessor::prepareToPlay (double sampleRate, int samplesPer { // Use this method as the place to do any pre-playback // initialisation that you need.. - getController(); // ensures controller is constructed before calling from processBlock! m_plugin.setSamplerate(static_cast<float>(sampleRate)); m_plugin.setBlockSize(samplesPerBlock); setLatencySamples(m_plugin.getLatencySamples()); diff --git a/source/jucePlugin/VirusController.cpp b/source/jucePlugin/VirusController.cpp @@ -34,8 +34,15 @@ namespace Virus if (pt != 0) return; // only register on first part! } - m_synthParams.insert_or_assign(idx, std::move(p)); - } + if (p->getDescription().isPublic) + { + // lifecycle managed by host + m_synthParams.insert_or_assign(idx, p.get()); + m_processor.addParameter(p.release()); + } + else + m_synthInternalParams.insert_or_assign(idx, std::move(p)); + } } } @@ -83,45 +90,59 @@ namespace Virus } } - juce::Value *Controller::getParam(uint8_t ch, uint8_t bank, uint8_t paramIndex) - { - auto it = m_synthParams.find({static_cast<uint8_t>(0x70 + bank), ch, paramIndex}); - if (it != m_synthParams.end()) - return &it->second->getValueObject(); - else - { + Parameter *Controller::findSynthParam(const uint8_t ch, const uint8_t bank, const uint8_t paramIndex) + { + auto it = m_synthParams.find({static_cast<uint8_t>(bank), ch, paramIndex}); + if (it == m_synthParams.end()) + { + auto iti = m_synthInternalParams.find({static_cast<uint8_t>(bank), ch, paramIndex}); + if (iti == m_synthInternalParams.end()) + return nullptr; + else + return iti->second.get(); + } + return it->second; + } + + juce::Value *Controller::getParam(uint8_t ch, uint8_t bank, uint8_t paramIndex) + { + auto *param = findSynthParam(ch, static_cast<uint8_t>(0x70 + bank), paramIndex); + if (param == nullptr) + { // unregistered param? jassertfalse; return nullptr; } - } + return &param->getValueObject(); + } - void Controller::parseParamChange(const SysEx &msg) + void Controller::parseParamChange(const SysEx &msg) { const auto pos = kHeaderWithMsgCodeLen - 1; const auto value = msg[pos + 3]; - ParamIndex idx = {msg[pos], msg[pos + 1], msg[pos + 2]}; - auto paramIt = m_synthParams.find(idx); - if (paramIt == m_synthParams.end()) - { + const auto bank = msg[pos]; + const auto ch = msg[pos + 1]; + const auto index = msg[pos + 2]; + auto param = findSynthParam(ch, bank, index); + if (param == nullptr && ch != 0) + { // ensure it's not global - idx.partNum = 0; - paramIt = m_synthParams.find(idx); - if (paramIt == m_synthParams.end()) - { + param = findSynthParam(0, bank, index); + if (param == nullptr) + { jassertfalse; return; } - auto flags = paramIt->second->getDescription().classFlags; - if (!(flags & Parameter::Class::GLOBAL) && !(flags & Parameter::Class::NON_PART_SENSITIVE)) + auto flags = param->getDescription().classFlags; + if (!(flags & Parameter::Class::GLOBAL) && !(flags & Parameter::Class::NON_PART_SENSITIVE)) { jassertfalse; return; } } - paramIt->second->getValueObject().setValue(value); - // TODO: + param->getValueObject().setValue(value); + // TODO: /** If a global parameter or a Multi parameter is ac- diff --git a/source/jucePlugin/VirusController.h b/source/jucePlugin/VirusController.h @@ -74,11 +74,15 @@ namespace Virus } }; - std::map<ParamIndex, std::unique_ptr<Parameter>> m_synthParams; + std::map<ParamIndex, std::unique_ptr<Parameter>> m_synthInternalParams; + std::map<ParamIndex, Parameter *> m_synthParams; // exposed and managed by audio processor - void registerParams(); + void registerParams(); + // tries to find synth param in both internal and host. + // @return found parameter or nullptr if none found. + Parameter *findSynthParam(uint8_t ch, uint8_t bank, uint8_t paramIndex); - // unchecked copy for patch data bytes + // unchecked copy for patch data bytes static inline uint8_t copyData(const SysEx &src, int startPos, uint8_t *dst); template <typename T> juce::String parseAsciiText(const T &, int startPos) const; diff --git a/source/jucePlugin/VirusParameter.cpp b/source/jucePlugin/VirusParameter.cpp @@ -5,22 +5,32 @@ namespace Virus { Parameter::Parameter(Controller &ctrl, const Description desc, const uint8_t partNum) : - m_ctrl(ctrl), m_desc(desc), m_partNum(partNum), juce::RangedAudioParameter(genId(), (m_desc.classFlags | Class::GLOBAL) ? "" : ("Ch " + juce::String(m_partNum + 1) + " ") + m_desc.name) + m_ctrl(ctrl), m_desc(desc), + m_partNum(partNum), juce::RangedAudioParameter(genId(desc, partNum), + (m_desc.classFlags & Class::GLOBAL) + ? "" + : ("Ch " + juce::String(m_partNum + 1) + " ") + desc.name) { m_range.start = m_desc.range.getStart(); m_range.end = m_desc.range.getEnd(); + m_range.interval = m_desc.isDiscrete || m_desc.isBool ? 1 : 0; m_value.addListener(this); } void Parameter::valueChanged(juce::Value &) { const uint8_t value = static_cast<int>(m_value.getValue()); - m_ctrl.sendSysEx(m_ctrl.constructMessage({static_cast<uint8_t>(m_desc.page), m_partNum, m_desc.index, value})); - } + if (value != m_lastValue) + { + m_ctrl.sendSysEx( + m_ctrl.constructMessage({static_cast<uint8_t>(m_desc.page), m_partNum, m_desc.index, value})); + m_lastValue = value; + } + } - juce::String Parameter::genId() - { - return juce::String::formatted("%d_%d_%d", (int)m_desc.page, m_partNum, m_paramNum); - } + juce::String Parameter::genId(const Description &d, const int part) + { + return juce::String::formatted("%d_%d_%d", (int)d.page, part, d.index); + } } // namespace Virus diff --git a/source/jucePlugin/VirusParameter.h b/source/jucePlugin/VirusParameter.h @@ -64,13 +64,14 @@ namespace Virus } private: - juce::String genId(); - void valueChanged(juce::Value &) override; + juce::String genId(const Description &d, int part); + void valueChanged(juce::Value &) override; Controller &m_ctrl; const Description m_desc; juce::NormalisableRange<float> m_range; uint8_t m_paramNum, m_partNum; - juce::Value m_value; + int m_lastValue{-1}; + juce::Value m_value; }; } // namespace Virus