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 ba4d1003bdf40f77d9646ad08731c1172fbd0817
parent bb2b1811635a64ecfe5a3996df9307a5d1caece9
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Sat,  8 Mar 2025 22:33:37 +0100

Xenia: implement controller message parsing to update UI parameters

Diffstat:
Mdoc/changelog.txt | 1+
Msource/jucePluginLib/controller.h | 7+++++++
Msource/nord/n2x/n2xJucePlugin/n2xController.cpp | 7++++++-
Msource/nord/n2x/n2xJucePlugin/n2xController.h | 2++
Msource/xtJucePlugin/xtController.cpp | 48+++++++++++++++++++++++++++++++++++++++++++++---
Msource/xtJucePlugin/xtController.h | 2++
6 files changed, 63 insertions(+), 4 deletions(-)

diff --git a/doc/changelog.txt b/doc/changelog.txt @@ -13,6 +13,7 @@ Xenia: - [Fix] Checksum of exported patches was incorrect due to bug in documentation - [Fix] Emulator might get stuck while "Reorganising Memory" +- [Fix] UI didn't react to parameter changes via MIDI controller messages OsTIrus: diff --git a/source/jucePluginLib/controller.h b/source/jucePluginLib/controller.h @@ -79,6 +79,13 @@ namespace pluginLib static Parameter::Origin midiEventSourceToParameterOrigin(synthLib::MidiEventSource _source); + std::vector<uint8_t> getPartsForMidiEvent(const synthLib::SMidiEvent& _e) + { + return getPartsForMidiChannel(_e.a & 0x0f); + } + + virtual std::vector<uint8_t> getPartsForMidiChannel(uint8_t _channel) { return {}; } + private: void getMidiMessages(std::vector<synthLib::SMidiEvent>&); void processMidiMessages(); diff --git a/source/nord/n2x/n2xJucePlugin/n2xController.cpp b/source/nord/n2x/n2xJucePlugin/n2xController.cpp @@ -161,7 +161,7 @@ namespace n2xJucePlugin m_state.receive(_e); - const auto parts = m_state.getPartsForMidiChannel(_e); + const auto parts = getPartsForMidiEvent(_e); for (const uint8_t part : parts) { @@ -451,6 +451,11 @@ namespace n2xJucePlugin return m_state.getKnobState(_result, _type); } + std::vector<uint8_t> Controller::getPartsForMidiChannel(const uint8_t _channel) + { + return m_state.getPartsForMidiChannel(_channel); + } + uint8_t Controller::combineSyncRingModDistortion(const uint8_t _part, const uint8_t _currentCombinedValue, bool _lockedOnly) { // this controls both Sync and RingMod diff --git a/source/nord/n2x/n2xJucePlugin/n2xController.h b/source/nord/n2x/n2xJucePlugin/n2xController.h @@ -62,6 +62,8 @@ namespace n2xJucePlugin bool getKnobState(uint8_t& _result, n2x::KnobType _type) const; + std::vector<uint8_t> getPartsForMidiChannel(uint8_t _channel) override; + private: uint8_t combineSyncRingModDistortion(uint8_t _part, uint8_t _currentCombinedValue, bool _lockedOnly); diff --git a/source/xtJucePlugin/xtController.cpp b/source/xtJucePlugin/xtController.cpp @@ -162,6 +162,26 @@ namespace xtJucePlugin return 8; } + std::vector<uint8_t> Controller::getPartsForMidiChannel(const uint8_t _channel) + { + if (!isMultiMode()) + return {0}; + + std::vector<uint8_t> parts; + + for (uint8_t p=0; p<getPartCount(); ++p) + { + char paramName[16]; + (void)snprintf(paramName, std::size(paramName), "MI%dMidiChannel", static_cast<int>(p)); + auto* param = getParameter(paramName, 0); + assert(param && "parameter not found"); + const auto v = param->getUnnormalizedValue(); + if (v < 2 || v - 2 == _channel) // omni, global, 0, 1, .... + parts.push_back(p); + } + return parts; + } + std::string Controller::getSingleName(const pluginLib::MidiPacket::ParamValues& _values) const { std::string name; @@ -417,10 +437,32 @@ namespace xtJucePlugin return true; } - bool Controller::parseControllerMessage(const synthLib::SMidiEvent&) + bool Controller::parseControllerMessage(const synthLib::SMidiEvent& _e) { - // TODO - return false; + const auto& cm = getParameterDescriptions().getControllerMap(); + const auto paramIndices = cm.getControlledParameters(_e); + + if(paramIndices.empty()) + return false; + + const auto origin = midiEventSourceToParameterOrigin(_e.source); + + const auto parts = isMultiMode() ? getPartsForMidiEvent(_e) : std::vector<uint8_t>{0}; + + if (parts.empty()) + return false; + + for (const uint8_t part : parts) + { + for (const auto paramIndex : paramIndices) + { + auto* param = getParameter(paramIndex, part); + assert(param && "parameter not found for control change"); + param->setValueFromSynth(_e.c, origin); + } + } + + return true; } 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,6 +95,8 @@ namespace xtJucePlugin uint8_t getPartCount() const override; + std::vector<uint8_t> getPartsForMidiChannel(uint8_t _channel) override; + private: void selectPreset(int _offset);