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 224c0d8d72c970e500d8d7d04fdb8950b232c6f5
parent dded541aeee9cb759d5b2d1ca69fb9aa52dbf5e4
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Mon,  5 Aug 2024 21:34:35 +0200

master volume knob works, state not preserved yet

Diffstat:
Msource/nord/n2x/n2xJucePlugin/CMakeLists.txt | 1+
Msource/nord/n2x/n2xJucePlugin/n2xController.h | 2++
Msource/nord/n2x/n2xJucePlugin/n2xEditor.cpp | 3+++
Msource/nord/n2x/n2xJucePlugin/n2xEditor.h | 2++
Asource/nord/n2x/n2xJucePlugin/n2xMasterVolume.cpp | 20++++++++++++++++++++
Asource/nord/n2x/n2xJucePlugin/n2xMasterVolume.h | 22++++++++++++++++++++++
Msource/nord/n2x/n2xLib/n2xmiditypes.h | 4++++
Msource/nord/n2x/n2xLib/n2xstate.cpp | 36++++++++++++++++++++++++++++++++++++
Msource/nord/n2x/n2xLib/n2xstate.h | 4++++
9 files changed, 94 insertions(+), 0 deletions(-)

diff --git a/source/nord/n2x/n2xJucePlugin/CMakeLists.txt b/source/nord/n2x/n2xJucePlugin/CMakeLists.txt @@ -6,6 +6,7 @@ set(SOURCES n2xArp.cpp n2xArp.h n2xController.cpp n2xController.h n2xEditor.cpp n2xEditor.h + n2xMasterVolume.cpp n2xMasterVolume.h n2xLcd.cpp n2xLcd.h n2xPart.cpp n2xPart.h n2xParts.cpp n2xParts.h diff --git a/source/nord/n2x/n2xJucePlugin/n2xController.h b/source/nord/n2x/n2xJucePlugin/n2xController.h @@ -61,6 +61,8 @@ namespace n2xJucePlugin std::string getSingleName(uint8_t _part) const; std::string getPatchName(uint8_t _part) const; + using pluginLib::Controller::sendSysEx; + private: n2x::State m_state; pluginLib::EventListener<uint8_t> m_currentPartChanged; diff --git a/source/nord/n2x/n2xJucePlugin/n2xEditor.cpp b/source/nord/n2x/n2xJucePlugin/n2xEditor.cpp @@ -5,6 +5,7 @@ #include "n2xArp.h" #include "n2xController.h" #include "n2xLcd.h" +#include "n2xMasterVolume.h" #include "n2xPart.h" #include "n2xParts.h" #include "n2xPatchManager.h" @@ -69,6 +70,7 @@ namespace n2xJucePlugin m_arp.reset(new Arp(*this)); m_lcd.reset(new Lcd(*this)); + m_masterVolume.reset(new MasterVolume(*this)); m_parts.reset(new Parts(*this)); onPartChanged.set(m_controller.onCurrentPartChanged, [this](const uint8_t& _part) @@ -111,6 +113,7 @@ namespace n2xJucePlugin { m_arp.reset(); m_lcd.reset(); + m_masterVolume.reset(); m_parts.reset(); } diff --git a/source/nord/n2x/n2xJucePlugin/n2xEditor.h b/source/nord/n2x/n2xJucePlugin/n2xEditor.h @@ -21,6 +21,7 @@ namespace n2xJucePlugin class Lcd; class Arp; class Parts; + class MasterVolume; class Editor final : public jucePluginEditorLib::Editor { @@ -57,6 +58,7 @@ namespace n2xJucePlugin std::unique_ptr<Arp> m_arp; std::unique_ptr<Lcd> m_lcd; + std::unique_ptr<MasterVolume> m_masterVolume; std::unique_ptr<Parts> m_parts; pluginLib::EventListener<uint8_t> onPartChanged; diff --git a/source/nord/n2x/n2xJucePlugin/n2xMasterVolume.cpp b/source/nord/n2x/n2xJucePlugin/n2xMasterVolume.cpp @@ -0,0 +1,20 @@ +#include "n2xMasterVolume.h" + +#include "n2xController.h" +#include "n2xEditor.h" + +namespace n2xJucePlugin +{ + MasterVolume::MasterVolume(const Editor& _editor) : m_editor(_editor), m_volume(_editor.findComponentT<juce::Slider>("MasterVolume")) + { + m_volume->setRange(0.0f, 255.0f); + m_volume->setValue(255.0f); + + m_volume->onValueChange = [this] + { + const auto sysex = n2x::State::createKnobSysex(n2x::KnobType::MasterVol, static_cast<uint8_t>(m_volume->getValue())); + + m_editor.getN2xController().sendSysEx(sysex); + }; + } +} diff --git a/source/nord/n2x/n2xJucePlugin/n2xMasterVolume.h b/source/nord/n2x/n2xJucePlugin/n2xMasterVolume.h @@ -0,0 +1,22 @@ +#pragma once + +namespace juce +{ + class Slider; +} + +namespace n2xJucePlugin +{ + class Editor; + + class MasterVolume + { + public: + explicit MasterVolume(const Editor& _editor); + + private: + const Editor& m_editor; + + juce::Slider* m_volume; + }; +} diff --git a/source/nord/n2x/n2xLib/n2xmiditypes.h b/source/nord/n2x/n2xLib/n2xmiditypes.h @@ -13,6 +13,8 @@ namespace n2x MultiDumpBankEditBuffer = 30, MultiDumpBankA, MultiRequestBankEditBuffer = 40, + + EmuSetPotPosition = 90, // total dump is: f0, IdClavia, IdDevice, IdN2x, EmuSetPotPosition, KnobType / nibble high, nibble low / f7 }; enum SysexIndex @@ -22,6 +24,8 @@ namespace n2x IdxN2x, IdxMsgType, IdxMsgSpec, + IdxPotPosH, + IdxPotPosL }; enum SingleParam diff --git a/source/nord/n2x/n2xLib/n2xstate.cpp b/source/nord/n2x/n2xLib/n2xstate.cpp @@ -249,6 +249,18 @@ namespace n2x if(sysex.size() == g_patchRequestSize) return false; + if(bank == n2x::SysexByte::EmuSetPotPosition) + { + KnobType knobType; + uint8_t knobValue; + + if(parseKnobSysex(knobType, knobValue, sysex)) + { + m_hardware->setKnobPosition(knobType, knobValue); + return true; + } + } + return false; } @@ -414,6 +426,30 @@ namespace n2x return res; } + std::vector<uint8_t> State::createKnobSysex(KnobType _type, uint8_t _value) + { + return {0xf0, IdClavia, DefaultDeviceId, IdN2X, + EmuSetPotPosition, + static_cast<uint8_t>(_type), + static_cast<uint8_t>(_value >> 4), + static_cast<uint8_t>(_value & 0x0f), + 0xf7 + }; + } + + bool State::parseKnobSysex(KnobType& _type, uint8_t& _value, const std::vector<uint8_t>& _sysex) + { + if(_sysex.size() <= SysexIndex::IdxPotPosL) + return false; + if(_sysex[SysexIndex::IdxMsgType] != SysexByte::EmuSetPotPosition) + return false; + + _type = static_cast<KnobType>(_sysex[SysexIndex::IdxMsgSpec]); + _value = static_cast<uint8_t>((_sysex[SysexIndex::IdxPotPosH] << 4) | _sysex[SysexIndex::IdxPotPosL]); + + return true; + } + void State::send(const synthLib::SMidiEvent& _e) const { if(_e.source == synthLib::MidiEventSource::Plugin) diff --git a/source/nord/n2x/n2xLib/n2xstate.h b/source/nord/n2x/n2xLib/n2xstate.h @@ -5,6 +5,7 @@ #include <cstddef> #include "n2xmiditypes.h" +#include "n2xtypes.h" #include "synthLib/midiTypes.h" @@ -106,6 +107,9 @@ namespace n2x _dump[_off+1] = _value >> 4; } + static std::vector<uint8_t> createKnobSysex(KnobType _type, uint8_t _value); + static bool parseKnobSysex(KnobType& _type, uint8_t& _value, const std::vector<uint8_t>& _sysex); + private: template<size_t Size> bool receive(const std::array<uint8_t, Size>& _data) {