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 5e2897af88a390cf418672341e01a1a37c81080b
parent a8b474be0f622002672680b4979dd13a6e0db0f1
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Sat, 18 May 2024 16:43:59 +0200

[Osirus][OsTIrus][Fix] Editor didn't update knobs if parameters are modified via MIDI control changes by using the physical midi input port

Diffstat:
Msource/jucePluginLib/controller.cpp | 7+++++++
Msource/jucePluginLib/controller.h | 6+++++-
Msource/jucePluginLib/processor.cpp | 10+++++-----
Msource/mqJucePlugin/mqController.cpp | 108++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msource/mqJucePlugin/mqController.h | 4+++-
Msource/virusJucePlugin/VirusController.cpp | 21+++++++++++++++------
Msource/virusJucePlugin/VirusController.h | 5+++--
Msource/virusLib/microcontroller.cpp | 8--------
Msource/xtJucePlugin/xtController.cpp | 114++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msource/xtJucePlugin/xtController.h | 5++++-
10 files changed, 161 insertions(+), 127 deletions(-)

diff --git a/source/jucePluginLib/controller.cpp b/source/jucePluginLib/controller.cpp @@ -431,6 +431,13 @@ namespace pluginLib return false; } + bool Controller::parseMidiMessage(const synthLib::SMidiEvent& _e) + { + if(_e.sysex.empty()) + return parseControllerMessage(_e); + return parseSysexMessage(_e.sysex, _e.source); + } + void Controller::addPluginMidiOut(const std::vector<synthLib::SMidiEvent>& _events) { const std::lock_guard l(m_pluginMidiOutLock); diff --git a/source/jucePluginLib/controller.h b/source/jucePluginLib/controller.h @@ -55,7 +55,11 @@ namespace pluginLib uint8_t getCurrentPart() const { return m_currentPart; } void setCurrentPart(const uint8_t _part) { m_currentPart = _part; } - virtual void parseSysexMessage(const SysEx&) = 0; + virtual bool parseSysexMessage(const SysEx&, synthLib::MidiEventSource) = 0; + virtual bool parseControllerMessage(const synthLib::SMidiEvent&) = 0; + + virtual bool parseMidiMessage(const synthLib::SMidiEvent& _e); + virtual void onStateLoaded() = 0; // this is called by the plug-in on audio thread! diff --git a/source/jucePluginLib/processor.cpp b/source/jucePluginLib/processor.cpp @@ -79,6 +79,8 @@ namespace pluginLib void Processor::handleIncomingMidiMessage(juce::MidiInput *source, const juce::MidiMessage &message) { + synthLib::SMidiEvent sm(synthLib::MidiEventSource::PhysicalInput); + const auto* raw = message.getSysExData(); if (raw) { @@ -90,10 +92,9 @@ namespace pluginLib syx.push_back(raw[i]); } syx.push_back(0xf7); - synthLib::SMidiEvent sm(synthLib::MidiEventSource::PhysicalInput); - sm.sysex = syx; - getController().parseSysexMessage(syx); + sm.sysex = std::move(syx); + getController().parseMidiMessage(sm); addMidiEvent(sm); if (m_midiOutput) @@ -110,8 +111,6 @@ namespace pluginLib } else { - synthLib::SMidiEvent sm(synthLib::MidiEventSource::PhysicalInput); - const auto count = message.getRawDataSize(); const auto* rawData = message.getRawData(); if (count >= 1 && count <= 3) @@ -128,6 +127,7 @@ namespace pluginLib sm.sysex = syx; } + getController().parseMidiMessage(sm); addMidiEvent(sm); } } diff --git a/source/mqJucePlugin/mqController.cpp b/source/mqJucePlugin/mqController.cpp @@ -121,7 +121,7 @@ void Controller::timerCallback() for (const auto& e : events) { if(!e.sysex.empty()) - parseSysexMessage(e.sysex); + parseSysexMessage(e.sysex, e.source); } } @@ -247,7 +247,7 @@ void Controller::parseMulti(const pluginLib::SysEx& _msg, const pluginLib::MidiP } } -void Controller::parseSysexMessage(const pluginLib::SysEx& _msg) +bool Controller::parseSysexMessage(const pluginLib::SysEx& _msg, synthLib::MidiEventSource _source) { if(_msg.size() >= 5) { @@ -261,7 +261,7 @@ void Controller::parseSysexMessage(const pluginLib::SysEx& _msg) case mqLib::SysexCommand::EmuLEDs: if(m_frontPanel) m_frontPanel->processSysex(_msg); - return; + return true; default: break; } @@ -273,60 +273,68 @@ void Controller::parseSysexMessage(const pluginLib::SysEx& _msg) pluginLib::MidiPacket::Data data; pluginLib::MidiPacket::ParamValues parameterValues; - if(pluginLib::Controller::parseMidiPacket(name, data, parameterValues, _msg)) + if(!pluginLib::Controller::parseMidiPacket(name, data, parameterValues, _msg)) + return false; + + if(name == midiPacketName(SingleDump)) { - if(name == midiPacketName(SingleDump)) - { - parseSingle(_msg, data, parameterValues); - } - else if (name == midiPacketName(MultiDump)) - { - parseMulti(_msg, data, parameterValues); - } - else if(name == midiPacketName(GlobalDump)) - { - const auto lastPlayMode = isMultiMode(); - memcpy(m_globalData.data(), &_msg[5], sizeof(m_globalData)); - const auto newPlayMode = isMultiMode(); - - if(lastPlayMode != newPlayMode) - onPlayModeChanged(newPlayMode); - else - requestAllPatches(); - } - else if(name == midiPacketName(SingleParameterChange)) - { - const auto page = data[pluginLib::MidiDataType::Page]; - const auto index = data[pluginLib::MidiDataType::ParameterIndex]; - const auto part = data[pluginLib::MidiDataType::Part]; - const auto value = data[pluginLib::MidiDataType::ParameterValue]; + parseSingle(_msg, data, parameterValues); + } + else if (name == midiPacketName(MultiDump)) + { + parseMulti(_msg, data, parameterValues); + } + else if(name == midiPacketName(GlobalDump)) + { + const auto lastPlayMode = isMultiMode(); + memcpy(m_globalData.data(), &_msg[5], sizeof(m_globalData)); + const auto newPlayMode = isMultiMode(); + + if(lastPlayMode != newPlayMode) + onPlayModeChanged(newPlayMode); + else + requestAllPatches(); + } + else if(name == midiPacketName(SingleParameterChange)) + { + const auto page = data[pluginLib::MidiDataType::Page]; + const auto index = data[pluginLib::MidiDataType::ParameterIndex]; + const auto part = data[pluginLib::MidiDataType::Part]; + const auto value = data[pluginLib::MidiDataType::ParameterValue]; - auto& params = findSynthParam(part, page, index); + auto& params = findSynthParam(part, page, index); - for (auto& param : params) - param->setValueFromSynth(value, true, pluginLib::Parameter::ChangedBy::ControlChange); + for (auto& param : params) + param->setValueFromSynth(value, true, pluginLib::Parameter::ChangedBy::ControlChange); - LOG("Single parameter " << static_cast<int>(index) << ", page " << static_cast<int>(page) << " for part " << static_cast<int>(part) << " changed to value " << static_cast<int>(value)); - } - else if(name == midiPacketName(GlobalParameterChange)) - { - const auto index = (static_cast<uint32_t>(data[pluginLib::MidiDataType::Page]) << 7) + static_cast<uint32_t>(data[pluginLib::MidiDataType::ParameterIndex]); - const auto value = data[pluginLib::MidiDataType::ParameterValue]; + LOG("Single parameter " << static_cast<int>(index) << ", page " << static_cast<int>(page) << " for part " << static_cast<int>(part) << " changed to value " << static_cast<int>(value)); + } + else if(name == midiPacketName(GlobalParameterChange)) + { + const auto index = (static_cast<uint32_t>(data[pluginLib::MidiDataType::Page]) << 7) + static_cast<uint32_t>(data[pluginLib::MidiDataType::ParameterIndex]); + const auto value = data[pluginLib::MidiDataType::ParameterValue]; - if(m_globalData[index] != value) - { - LOG("Global parameter " << index << " changed to value " << static_cast<int>(value)); - m_globalData[index] = value; + if(m_globalData[index] != value) + { + LOG("Global parameter " << index << " changed to value " << static_cast<int>(value)); + m_globalData[index] = value; - if (index == static_cast<uint32_t>(mqLib::GlobalParameter::SingleMultiMode)) - requestAllPatches(); - } - } - else - { - LOG("Received unknown sysex of size " << _msg.size()); - } + if (index == static_cast<uint32_t>(mqLib::GlobalParameter::SingleMultiMode)) + requestAllPatches(); + } } + else + { + LOG("Received unknown sysex of size " << _msg.size()); + return false; + } + return true; +} + +bool Controller::parseControllerMessage(const synthLib::SMidiEvent&) +{ + // TODO + return false; } bool Controller::parseMidiPacket(MidiPacketType _type, pluginLib::MidiPacket::Data& _data, pluginLib::MidiPacket::AnyPartParamValues& _params, const pluginLib::SysEx& _sysex) const diff --git a/source/mqJucePlugin/mqController.h b/source/mqJucePlugin/mqController.h @@ -89,9 +89,11 @@ private: void applyPatchParameters(const pluginLib::MidiPacket::ParamValues& _params, uint8_t _part); void parseSingle(const pluginLib::SysEx& _msg, const pluginLib::MidiPacket::Data& _data, const pluginLib::MidiPacket::ParamValues& _params); void parseMulti(const pluginLib::SysEx& _msg, const pluginLib::MidiPacket::Data& _data, const pluginLib::MidiPacket::ParamValues& _params); - void parseSysexMessage(const pluginLib::SysEx&) override; bool parseMidiPacket(MidiPacketType _type, pluginLib::MidiPacket::Data& _data, pluginLib::MidiPacket::AnyPartParamValues& _params, const pluginLib::SysEx& _sysex) const; + bool parseSysexMessage(const pluginLib::SysEx&, synthLib::MidiEventSource _source) override; + bool parseControllerMessage(const synthLib::SMidiEvent&) override; + void sendParameterChange(const pluginLib::Parameter& _parameter, uint8_t _value) override; bool sendGlobalParameterChange(mqLib::GlobalParameter _param, uint8_t _value); void requestSingle(mqLib::MidiBufferNum _buf, mqLib::MidiSoundLocation _location, uint8_t _locationOffset = 0) const; diff --git a/source/virusJucePlugin/VirusController.cpp b/source/virusJucePlugin/VirusController.cpp @@ -87,7 +87,7 @@ namespace Virus stopTimer(); } - void Controller::parseSysexMessage(const pluginLib::SysEx& _msg) + bool Controller::parseSysexMessage(const pluginLib::SysEx& _msg, synthLib::MidiEventSource) { std::string name; pluginLib::MidiPacket::Data data; @@ -98,7 +98,7 @@ namespace Virus const auto deviceId = data[pluginLib::MidiDataType::DeviceId]; if(deviceId != m_deviceId && deviceId != virusLib::OMNI_DEVICE_ID) - return; // not intended to this device! + return false; // not intended to this device! if(name == midiPacketName(MidiPacketType::SingleDump) || name == midiPacketName(MidiPacketType::SingleDump_C)) parseSingle(_msg, data, parameterValues); @@ -111,13 +111,20 @@ namespace Virus LOG("Controller: Begin unhandled SysEx! --"); printMessage(_msg); LOG("Controller: End unhandled SysEx! --"); + return false; } - return; + return true; } LOG("Controller: Begin unknown SysEx! --"); printMessage(_msg); LOG("Controller: End unknown SysEx! --"); + return false; + } + + bool Controller::parseControllerMessage(const synthLib::SMidiEvent& e) + { + return parseControllerDump(e); } juce::Value* Controller::getParamValue(uint8_t ch, uint8_t bank, uint8_t paramIndex) @@ -534,7 +541,7 @@ namespace Virus } } - void Controller::parseControllerDump(const synthLib::SMidiEvent& m) + bool Controller::parseControllerDump(const synthLib::SMidiEvent& m) { const uint8_t status = m.a & 0xf0; const uint8_t part = m.a & 0x0f; @@ -546,11 +553,13 @@ namespace Virus else if (status == synthLib::M_POLYPRESSURE) page = virusLib::PAGE_B; else - return; + return false; const auto& params = findSynthParam(part, page, m.b); for (const auto & p : params) p->setValueFromSynth(m.c, true, pluginLib::Parameter::ChangedBy::ControlChange); + + return true; } void Controller::printMessage(const pluginLib::SysEx &msg) @@ -663,7 +672,7 @@ namespace Virus } else { - parseSysexMessage(msg.sysex); + parseSysexMessage(msg.sysex, msg.source); } } } diff --git a/source/virusJucePlugin/VirusController.h b/source/virusJucePlugin/VirusController.h @@ -126,7 +126,8 @@ namespace Virus juce::String getCurrentPartPresetName(uint8_t _part) const; uint32_t getBankCount() const { return static_cast<uint32_t>(m_singles.size()); } - void parseSysexMessage(const pluginLib::SysEx &) override; + bool parseSysexMessage(const pluginLib::SysEx& _msg, synthLib::MidiEventSource _source) override; + bool parseControllerMessage(const synthLib::SMidiEvent&) override; void onStateLoaded() override; std::function<void(int)> onProgramChange = {}; std::function<void()> onMsgDone = {}; @@ -171,7 +172,7 @@ namespace Virus void parseMulti(const pluginLib::SysEx& _msg, const pluginLib::MidiPacket::Data& _data, const pluginLib::MidiPacket::ParamValues& _parameterValues); void parseParamChange(const pluginLib::MidiPacket::Data& _data); - void parseControllerDump(const synthLib::SMidiEvent&); + bool parseControllerDump(const synthLib::SMidiEvent&); VirusProcessor& m_processor; virusLib::DeviceModel m_defaultModel; diff --git a/source/virusLib/microcontroller.cpp b/source/virusLib/microcontroller.cpp @@ -815,14 +815,6 @@ bool Microcontroller::sendSysex(const std::vector<uint8_t>& _data, std::vector<S } } - // bounce back to UI if not sent by editor - if(_source != MidiEventSource::Editor) - { - SMidiEvent ev(MidiEventSource::Editor); // don't send to output - ev.sysex = _data; - _responses.push_back(ev); - } - return send(page, part, param, value); } default: diff --git a/source/xtJucePlugin/xtController.cpp b/source/xtJucePlugin/xtController.cpp @@ -164,7 +164,7 @@ void Controller::timerCallback() for (const auto& e : events) { if(!e.sysex.empty()) - parseSysexMessage(e.sysex); + parseSysexMessage(e.sysex, e.source); } } @@ -309,7 +309,7 @@ void Controller::parseGlobal(const pluginLib::SysEx& _msg, const pluginLib::Midi applyPatchParameters(_params, 0); } -void Controller::parseSysexMessage(const pluginLib::SysEx& _msg) +bool Controller::parseSysexMessage(const pluginLib::SysEx& _msg, synthLib::MidiEventSource) { if(_msg.size() >= 5) { @@ -321,7 +321,7 @@ void Controller::parseSysexMessage(const pluginLib::SysEx& _msg) case xt::SysexCommand::EmuLEDs: if(m_frontPanel) m_frontPanel->processSysex(_msg); - return; + return true; default: break; } @@ -333,61 +333,69 @@ void Controller::parseSysexMessage(const pluginLib::SysEx& _msg) pluginLib::MidiPacket::Data data; pluginLib::MidiPacket::ParamValues parameterValues; - if(pluginLib::Controller::parseMidiPacket(name, data, parameterValues, _msg)) - { - if(name == midiPacketName(SingleDump)) - { - parseSingle(_msg, data, parameterValues); - } - else if (name == midiPacketName(MultiDump)) - { - parseMulti(_msg, data, parameterValues); - } - else if(name == midiPacketName(GlobalDump)) - { - parseGlobal(_msg, data, parameterValues); - } - else if(name == midiPacketName(ModeDump)) - { - const auto lastPlayMode = isMultiMode(); - memcpy(m_modeData.data(), &_msg[xt::IdxModeParamFirst], sizeof(m_modeData)); - const auto newPlayMode = isMultiMode(); + if(!pluginLib::Controller::parseMidiPacket(name, data, parameterValues, _msg)) + return false; - if(lastPlayMode != newPlayMode) - onPlayModeChanged(newPlayMode); - else - requestAllPatches(); - } - else if(name == midiPacketName(SingleParameterChange)) - { - const auto page = data[pluginLib::MidiDataType::Page]; - const auto index = data[pluginLib::MidiDataType::ParameterIndex]; - const auto part = data[pluginLib::MidiDataType::Part]; - const auto value = data[pluginLib::MidiDataType::ParameterValue]; + if(name == midiPacketName(SingleDump)) + { + parseSingle(_msg, data, parameterValues); + } + else if (name == midiPacketName(MultiDump)) + { + parseMulti(_msg, data, parameterValues); + } + else if(name == midiPacketName(GlobalDump)) + { + parseGlobal(_msg, data, parameterValues); + } + else if(name == midiPacketName(ModeDump)) + { + const auto lastPlayMode = isMultiMode(); + memcpy(m_modeData.data(), &_msg[xt::IdxModeParamFirst], sizeof(m_modeData)); + const auto newPlayMode = isMultiMode(); + + if(lastPlayMode != newPlayMode) + onPlayModeChanged(newPlayMode); + else + requestAllPatches(); + } + else if(name == midiPacketName(SingleParameterChange)) + { + const auto page = data[pluginLib::MidiDataType::Page]; + const auto index = data[pluginLib::MidiDataType::ParameterIndex]; + const auto part = data[pluginLib::MidiDataType::Part]; + const auto value = data[pluginLib::MidiDataType::ParameterValue]; - auto& params = findSynthParam(part, page, index); + auto& params = findSynthParam(part, page, index); - for (auto& param : params) - param->setValueFromSynth(value, true, pluginLib::Parameter::ChangedBy::ControlChange); + for (auto& param : params) + param->setValueFromSynth(value, true, pluginLib::Parameter::ChangedBy::ControlChange); - LOG("Single parameter " << static_cast<int>(index) << ", page " << static_cast<int>(page) << " for part " << static_cast<int>(part) << " changed to value " << static_cast<int>(value)); - } - else if(name == midiPacketName(GlobalParameterChange)) - { - const auto index = (static_cast<uint32_t>(data[pluginLib::MidiDataType::Page]) << 7) + static_cast<uint32_t>(data[pluginLib::MidiDataType::ParameterIndex]); - const auto value = data[pluginLib::MidiDataType::ParameterValue]; - - if(m_globalData[index] != value) - { - LOG("Global parameter " << index << " changed to value " << static_cast<int>(value)); - m_globalData[index] = value; - } - } - else - { - LOG("Received unknown sysex of size " << _msg.size()); - } + LOG("Single parameter " << static_cast<int>(index) << ", page " << static_cast<int>(page) << " for part " << static_cast<int>(part) << " changed to value " << static_cast<int>(value)); } + else if(name == midiPacketName(GlobalParameterChange)) + { + const auto index = (static_cast<uint32_t>(data[pluginLib::MidiDataType::Page]) << 7) + static_cast<uint32_t>(data[pluginLib::MidiDataType::ParameterIndex]); + const auto value = data[pluginLib::MidiDataType::ParameterValue]; + + if(m_globalData[index] != value) + { + LOG("Global parameter " << index << " changed to value " << static_cast<int>(value)); + m_globalData[index] = value; + } + } + else + { + LOG("Received unknown sysex of size " << _msg.size()); + return false; + } + return true; +} + +bool Controller::parseControllerMessage(const synthLib::SMidiEvent&) +{ + // TODO + return false; } bool Controller::parseMidiPacket(MidiPacketType _type, pluginLib::MidiPacket::Data& _data, pluginLib::MidiPacket::AnyPartParamValues& _params, const pluginLib::SysEx& _sysex) const diff --git a/source/xtJucePlugin/xtController.h b/source/xtJucePlugin/xtController.h @@ -95,9 +95,12 @@ private: void parseSingle(const pluginLib::SysEx& _msg, const pluginLib::MidiPacket::Data& _data, const pluginLib::MidiPacket::ParamValues& _params); void parseMulti(const pluginLib::SysEx& _msg, const pluginLib::MidiPacket::Data& _data, const pluginLib::MidiPacket::ParamValues& _params) const; void parseGlobal(const pluginLib::SysEx& _msg, const pluginLib::MidiPacket::Data& _data, const pluginLib::MidiPacket::ParamValues& _params); - void parseSysexMessage(const pluginLib::SysEx&) override; + bool parseMidiPacket(MidiPacketType _type, pluginLib::MidiPacket::Data& _data, pluginLib::MidiPacket::AnyPartParamValues& _params, const pluginLib::SysEx& _sysex) const; + bool parseSysexMessage(const pluginLib::SysEx&, synthLib::MidiEventSource) override; + bool parseControllerMessage(const synthLib::SMidiEvent&) override; + void sendParameterChange(const pluginLib::Parameter& _parameter, uint8_t _value) override; bool sendGlobalParameterChange(xt::GlobalParameter _param, uint8_t _value); bool sendModeDump() const;