commit aa41a7d1a4b0fafafb706ad58c284d88ba91cbd2
parent 24b9a0ef4f200713c00df6879b0cc187513c541f
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date: Thu, 12 Sep 2024 20:07:07 +0200
transfer front panel state via custom midi sysex to prevent direct access to device
Diffstat:
11 files changed, 160 insertions(+), 45 deletions(-)
diff --git a/source/virusJucePlugin/Leds.cpp b/source/virusJucePlugin/Leds.cpp
@@ -10,23 +10,18 @@ namespace genericVirusUI
constexpr const char* g_lfoNames[3] = {"Lfo1LedOn", "Lfo2LedOn", "Lfo3LedOn"};
- Leds::Leds(const genericUI::Editor& _editor, virus::VirusProcessor& _processor) : m_processor(_processor), m_logoAnimationEnabled(_processor.getConfig().getBoolValue(g_logoAnimKey, true))
+ Leds::Leds(const VirusEditor& _editor, virus::VirusProcessor& _processor) : m_processor(_processor), m_logoAnimationEnabled(_processor.getConfig().getBoolValue(g_logoAnimKey, true))
{
+ m_onFrontPanelStateChanged.set(_editor.getController().onFrontPanelStateChanged, [this](const virusLib::FrontpanelState& _frontpanelState)
+ {
+ onFrontPanelStateChanged(_frontpanelState);
+ });
+
for(size_t i=0; i<m_lfos.size(); ++i)
{
if(auto* comp = _editor.findComponentT<juce::Component>(g_lfoNames[i], false))
{
m_lfos[i].reset(new jucePluginEditorLib::Led(comp));
- m_lfos[i]->setSourceCallback([i, &_processor]
- {
- auto* d = dynamic_cast<virusLib::Device*>(_processor.getPlugin().getDevice());
-
- if(!d)
- return 0.0f;
-
- const auto v = std::clamp(d->getFrontpanelState().m_lfoPhases[i], 0.0f, 1.0f);
- return std::pow(1.0f - v, 0.2f);
- });
}
}
@@ -36,22 +31,6 @@ namespace genericVirusUI
m_logoLed.reset(new jucePluginEditorLib::Led(logoAnim));
- m_logoLed->setSourceCallback([this, &_processor]
- {
- if(!m_logoAnimationEnabled)
- return 0.0f;
- auto* d = dynamic_cast<virusLib::Device*>(_processor.getPlugin().getDevice());
-
- if(!d)
- return 0.0f;
-
- const auto& s = d->getFrontpanelState();
-
- const auto v = std::clamp(_processor.getModel() == virusLib::DeviceModel::Snow ? s.m_bpm : s.m_logo, 0.0f, 1.0f);
-
- return std::pow(1.0f - v, 0.2f);
- });
-
m_logoClickListener.reset(new LogoMouseListener(*this));
m_logoAnim->addMouseListener(m_logoClickListener.get(), false);
@@ -65,6 +44,8 @@ namespace genericVirusUI
m_logo->setInterceptsMouseClicks(true, true);
}
}
+
+ onFrontPanelStateChanged(_editor.getController().getFrontpanelState());
}
Leds::~Leds()
@@ -87,4 +68,29 @@ namespace genericVirusUI
m_processor.getConfig().setValue(g_logoAnimKey, m_logoAnimationEnabled);
m_processor.getConfig().saveIfNeeded();
}
+
+ void Leds::onFrontPanelStateChanged(const virusLib::FrontpanelState& _frontpanelState) const
+ {
+ for(size_t i=0; i<_frontpanelState.m_lfoPhases.size(); ++i)
+ {
+ const auto v = std::clamp(_frontpanelState.m_lfoPhases[i], 0.0f, 1.0f);
+ if(!m_lfos[i])
+ continue;
+ m_lfos[i]->setValue(std::pow(1.0f - v, 0.2f));
+ }
+
+ if(m_logoLed)
+ {
+ if(!m_logoAnimationEnabled)
+ {
+ m_logoLed->setValue(0.0f);
+ }
+ else
+ {
+ const auto v = std::clamp(m_processor.getModel() == virusLib::DeviceModel::Snow ? _frontpanelState.m_bpm : _frontpanelState.m_logo, 0.0f, 1.0f);
+
+ m_logoLed->setValue(std::pow(1.0f - v, 0.2f));
+ }
+ }
+ }
}
diff --git a/source/virusJucePlugin/Leds.h b/source/virusJucePlugin/Leds.h
@@ -4,8 +4,9 @@
#include <memory>
#include "jucePluginEditorLib/led.h"
-
+#include "jucePluginLib/event.h"
#include "juce_gui_basics/juce_gui_basics.h"
+#include "virusLib/frontpanelState.h"
namespace juce
{
@@ -24,6 +25,8 @@ namespace genericUI
namespace genericVirusUI
{
+ class VirusEditor;
+
class Leds
{
public:
@@ -44,7 +47,7 @@ namespace genericVirusUI
Leds& m_leds;
};
- Leds(const genericUI::Editor& _editor, virus::VirusProcessor& _processor);
+ Leds(const VirusEditor& _editor, virus::VirusProcessor& _processor);
~Leds();
void toggleLogoAnimation();
@@ -53,6 +56,8 @@ namespace genericVirusUI
bool isLogoAnimationEnabled() const { return m_logoAnimationEnabled; }
private:
+ void onFrontPanelStateChanged(const virusLib::FrontpanelState& _frontpanelState) const;
+
virus::VirusProcessor& m_processor;
bool m_logoAnimationEnabled = true;
@@ -64,5 +69,7 @@ namespace genericVirusUI
juce::Component* m_logoAnim = nullptr;
std::unique_ptr<LogoMouseListener> m_logoClickListener;
+
+ pluginLib::EventListener<virusLib::FrontpanelState> m_onFrontPanelStateChanged;
};
}
diff --git a/source/virusJucePlugin/Parts.cpp b/source/virusJucePlugin/Parts.cpp
@@ -71,6 +71,12 @@ namespace genericVirusUI
startTimer(1000/20);
}
+
+ m_onFrontpanelStateChanged.set(_editor.getController().onFrontPanelStateChanged, [this](const virusLib::FrontpanelState& _frontpanelState)
+ {
+ for(size_t i=0; i<m_frontpanelState.m_midiEventReceived.size(); ++i)
+ m_frontpanelState.m_midiEventReceived[i] |= _frontpanelState.m_midiEventReceived[i];
+ });
}
Parts::~Parts() = default;
@@ -196,12 +202,7 @@ namespace genericVirusUI
void Parts::timerCallback()
{
- auto* device = dynamic_cast<virusLib::Device*>(m_editor.getProcessor().getPlugin().getDevice());
-
- if(!device)
- return;
-
- auto& fpState = device->getFrontpanelState();
+ auto& fpState = m_frontpanelState;
const uint32_t maxPart = m_editor.getController().isMultiMode() ? 16 : 1;
diff --git a/source/virusJucePlugin/Parts.h b/source/virusJucePlugin/Parts.h
@@ -2,7 +2,9 @@
#include <vector>
+#include "jucePluginLib/event.h"
#include "juceUiLib/button.h"
+#include "virusLib/frontpanelState.h"
namespace genericVirusUI
{
@@ -60,5 +62,8 @@ namespace genericVirusUI
std::vector<juce::Component*> m_partActive;
std::vector<PartButton*> m_presetName;
+
+ virusLib::FrontpanelState m_frontpanelState;
+ pluginLib::EventListener<virusLib::FrontpanelState> m_onFrontpanelStateChanged;
};
}
diff --git a/source/virusJucePlugin/VirusController.cpp b/source/virusJucePlugin/VirusController.cpp
@@ -89,6 +89,14 @@ namespace virus
pluginLib::MidiPacket::Data data;
pluginLib::MidiPacket::ParamValues parameterValues;
+ if(_msg.size() > 6 && _msg[6] == virusLib::DUMP_EMU_SYNTHSTATE)
+ {
+ if(!m_frontpanelState.fromMidiEvent(_msg))
+ return false;
+ onFrontPanelStateChanged(m_frontpanelState);
+ return true;
+ }
+
if(parseMidiPacket(name, data, parameterValues, _msg))
{
const auto deviceId = data[pluginLib::MidiDataType::DeviceId];
diff --git a/source/virusJucePlugin/VirusController.h b/source/virusJucePlugin/VirusController.h
@@ -4,6 +4,7 @@
#include "jucePluginLib/controller.h"
#include "jucePluginLib/event.h"
+#include "virusLib/frontpanelState.h"
#include "virusLib/microcontrollerTypes.h"
#include "virusLib/romfile.h"
@@ -14,6 +15,8 @@ namespace virus
class Controller : public pluginLib::Controller
{
public:
+ pluginLib::Event<virusLib::FrontpanelState> onFrontPanelStateChanged;
+
struct Patch
{
std::string name;
@@ -155,6 +158,8 @@ namespace virus
bool parseSingle(pluginLib::MidiPacket::Data& _data, pluginLib::MidiPacket::AnyPartParamValues& _parameterValues, const pluginLib::SysEx& _msg) const;
bool parseSingle(pluginLib::MidiPacket::Data& _data, pluginLib::MidiPacket::AnyPartParamValues& _parameterValues, const pluginLib::SysEx& _msg, MidiPacketType& usedPacketType) const;
+ const auto& getFrontpanelState() const { return m_frontpanelState; }
+
private:
Singles m_singles;
SinglePatch m_singleEditBuffer; // single mode
@@ -177,5 +182,6 @@ namespace virus
uint8_t m_currentProgram[16]{};
PresetSource m_currentPresetSource[16]{PresetSource::Unknown};
pluginLib::EventListener<const virusLib::ROMFile*> m_onRomChanged;
+ virusLib::FrontpanelState m_frontpanelState;
};
}; // namespace Virus
diff --git a/source/virusLib/device.cpp b/source/virusLib/device.cpp
@@ -18,6 +18,8 @@ namespace virusLib
: m_rom(std::move(_rom))
, m_samplerate(getDeviceSamplerate(_preferredDeviceSamplerate, _hostSamplerate))
{
+ m_frontpanelStateMidiEvent.source = synthLib::MidiEventSource::Internal;
+
DspSingle* dsp1;
createDspInstances(dsp1, m_dsp2, m_rom, m_samplerate);
m_dsp.reset(dsp1);
@@ -163,12 +165,8 @@ namespace virusLib
m_numSamplesProcessed += static_cast<uint32_t>(_size);
- m_frontpanelStateGui.m_lfoPhases = m_frontpanelStateDSP.m_lfoPhases;
- m_frontpanelStateGui.m_bpm = m_frontpanelStateDSP.m_bpm;
- m_frontpanelStateGui.m_logo = m_frontpanelStateDSP.m_logo;
-
- for(size_t i=0; i<m_frontpanelStateDSP.m_midiEventReceived.size(); ++i)
- m_frontpanelStateGui.m_midiEventReceived[i] |= m_frontpanelStateDSP.m_midiEventReceived[i];
+ m_frontpanelStateDSP.toMidiEvent(m_frontpanelStateMidiEvent);
+ _midiOut.push_back(m_frontpanelStateMidiEvent);
}
#if !SYNTHLIB_DEMO_MODE
diff --git a/source/virusLib/device.h b/source/virusLib/device.h
@@ -58,8 +58,6 @@ namespace virusLib
static void applyDspMemoryPatches(const DspSingle* _dspA, const DspSingle* _dspB, const ROMFile& _rom);
void applyDspMemoryPatches() const;
- FrontpanelState& getFrontpanelState() { return m_frontpanelStateGui; }
-
private:
bool sendMidi(const synthLib::SMidiEvent& _ev, std::vector<synthLib::SMidiEvent>& _response) override;
void readMidiOut(std::vector<synthLib::SMidiEvent>& _midiOut) override;
@@ -76,6 +74,6 @@ namespace virusLib
uint32_t m_numSamplesProcessed = 0;
float m_samplerate;
FrontpanelState m_frontpanelStateDSP;
- FrontpanelState m_frontpanelStateGui;
+ synthLib::SMidiEvent m_frontpanelStateMidiEvent;
};
}
diff --git a/source/virusLib/frontpanelState.cpp b/source/virusLib/frontpanelState.cpp
@@ -1,16 +1,22 @@
#include "frontpanelState.h"
+#include "microcontrollerTypes.h"
+
+#include "synthLib/midiTypes.h"
+
#include "dsp56kEmu/dsp.h"
#include "dsp56kEmu/peripherals.h"
namespace virusLib
{
+ static constexpr std::initializer_list<uint8_t> g_midiDumpHeader = {0xf0, 0x00, 0x20, 0x33, 0x01, OMNI_DEVICE_ID, DUMP_EMU_SYNTHSTATE};
+
void FrontpanelState::updateLfoPhaseFromTimer(dsp56k::DSP& _dsp, const uint32_t _lfo, const uint32_t _timer, const float _minimumValue/* = 0.0f*/, float _maximumValue/* = 1.0f*/)
{
updatePhaseFromTimer(m_lfoPhases[_lfo], _dsp, _timer, _minimumValue, _maximumValue);
}
- void FrontpanelState::updatePhaseFromTimer(float& _target, dsp56k::DSP& _dsp, uint32_t _timer, float _minimumValue, float _maximumValue)
+ void FrontpanelState::updatePhaseFromTimer(float& _target, dsp56k::DSP& _dsp, const uint32_t _timer, float _minimumValue, float _maximumValue)
{
const auto* peripherals = _dsp.getPeriph(0);
@@ -41,4 +47,73 @@ namespace virusLib
_target = (normalized - _minimumValue) * floatRangeInv;
}
+
+ void writeFloat(std::vector<uint8_t>& _sysex, const float _v)
+ {
+ const auto* ptr = reinterpret_cast<const uint8_t*>(&_v);
+ for(size_t i=0; i<sizeof(_v); ++i)
+ _sysex.push_back(ptr[i]);
+ }
+
+ size_t readFloat(float& _dst, const uint8_t* _s)
+ {
+ auto* ptr = reinterpret_cast<uint8_t*>(&_dst);
+ for(size_t i=0; i<sizeof(_dst); ++i)
+ ptr[i] = _s[i];
+ return sizeof(_dst);
+ }
+
+ void FrontpanelState::toMidiEvent(synthLib::SMidiEvent& _e) const
+ {
+ _e.sysex.assign(g_midiDumpHeader.begin(), g_midiDumpHeader.end());
+
+ uint32_t midiEvents = 0;
+
+ for(size_t i=0; i<m_midiEventReceived.size(); ++i)
+ {
+ if(m_midiEventReceived[i])
+ midiEvents |= (1<<i);
+ }
+
+ _e.sysex.push_back((midiEvents >> 14) & 0x7f);
+ _e.sysex.push_back((midiEvents >> 7) & 0x7f);
+ _e.sysex.push_back((midiEvents) & 0x7f);
+
+ for (const auto lfoPhase : m_lfoPhases)
+ writeFloat(_e.sysex, lfoPhase);
+
+ writeFloat(_e.sysex, m_logo);
+ writeFloat(_e.sysex, m_bpm);
+
+ _e.sysex.push_back(0xf7);
+ }
+
+ bool FrontpanelState::fromMidiEvent(const synthLib::SMidiEvent& _e)
+ {
+ return fromMidiEvent(_e.sysex);
+ }
+
+ bool FrontpanelState::fromMidiEvent(const std::vector<uint8_t>& _sysex)
+ {
+ if(_sysex.size() < g_midiDumpHeader.size())
+ return false;
+
+ const auto* s = &_sysex[g_midiDumpHeader.size()];
+
+ uint32_t midiEvents = 0;
+ midiEvents |= static_cast<uint32_t>(*s) << 14; ++s;
+ midiEvents |= static_cast<uint32_t>(*s) << 7; ++s;
+ midiEvents |= static_cast<uint32_t>(*s); ++s;
+
+ for(size_t i=0; i<m_midiEventReceived.size(); ++i)
+ m_midiEventReceived[i] = (midiEvents & (1<<i)) ? true : false;
+
+ for (auto& lfoPhase : m_lfoPhases)
+ s += readFloat(lfoPhase, s);
+
+ s += readFloat(m_logo, s);
+ readFloat(m_bpm, s);
+
+ return true;
+ }
}
diff --git a/source/virusLib/frontpanelState.h b/source/virusLib/frontpanelState.h
@@ -2,6 +2,12 @@
#include <array>
#include <cstdint>
+#include <vector>
+
+namespace synthLib
+{
+ struct SMidiEvent;
+}
namespace dsp56k
{
@@ -30,6 +36,10 @@ namespace virusLib
static void updatePhaseFromTimer(float& _target, dsp56k::DSP& _dsp, uint32_t _timer, float _minimumValue = 0.0f, float _maximumValue = 1.0f);
static void updatePhaseFromTimer(float& _target, const dsp56k::Timers& _timers, uint32_t _timer, float _minimumValue = 0.0f, float _maximumValue = 1.0f);
+ void toMidiEvent(synthLib::SMidiEvent& _e) const;
+ bool fromMidiEvent(const synthLib::SMidiEvent& _e);
+ bool fromMidiEvent(const std::vector<uint8_t>& _sysex);
+
std::array<bool, 16> m_midiEventReceived;
std::array<float, 3> m_lfoPhases;
diff --git a/source/virusLib/microcontrollerTypes.h b/source/virusLib/microcontrollerTypes.h
@@ -6,6 +6,7 @@ namespace virusLib
{
enum SysexMessageType : uint8_t
{
+ DUMP_EMU_SYNTHSTATE = 0x09,
DUMP_SINGLE = 0x10,
DUMP_MULTI = 0x11,
REQUEST_SINGLE = 0x30,