n2xstate.h (5751B)
1 #pragma once 2 3 #include <array> 4 #include <vector> 5 #include <cstddef> 6 #include <unordered_map> 7 #include <string> 8 9 #include "n2xmiditypes.h" 10 #include "n2xtypes.h" 11 12 #include "synthLib/midiTypes.h" 13 14 namespace synthLib 15 { 16 class MidiTranslator; 17 } 18 19 namespace n2x 20 { 21 class Hardware; 22 23 class State 24 { 25 public: 26 using SingleDump = std::array<uint8_t, g_singleDumpWithNameSize>; 27 using MultiDump = std::array<uint8_t, g_multiDumpWithNameSize>; 28 29 explicit State(Hardware* _hardware, synthLib::MidiTranslator* _midiTranslator); 30 31 bool getState(std::vector<uint8_t>& _state); 32 bool setState(const std::vector<uint8_t>& _state); 33 34 bool receive(const synthLib::SMidiEvent& _ev) 35 { 36 std::vector<synthLib::SMidiEvent> responses; 37 return receive(responses, _ev); 38 } 39 bool receive(std::vector<synthLib::SMidiEvent>& _responses, const synthLib::SMidiEvent& _ev); 40 bool receive(const std::vector<uint8_t>& _data, synthLib::MidiEventSource _source); 41 42 bool receiveNonSysex(const synthLib::SMidiEvent& _ev); 43 44 bool changeSingleParameter(uint8_t _part, const synthLib::SMidiEvent& _ev); 45 46 bool changeSingleParameter(uint8_t _part, SingleParam _parameter, uint8_t _value); 47 bool changeMultiParameter(MultiParam _parameter, uint8_t _value); 48 49 static bool changeSingleParameter(SingleDump& _dump, SingleParam _param, uint8_t _value); 50 51 template<typename TDump> 52 static bool changeDumpParameter(TDump& _dump, uint32_t _offset, uint8_t _value) 53 { 54 const auto current = unpackNibbles(_dump, _offset); 55 if(current == _value) 56 return false; 57 packNibbles(_dump, _offset, _value); 58 return true; 59 } 60 61 void updateMultiFromSingles(); 62 63 const auto& getMulti() const { return m_multi; } 64 const auto& getSingle(uint8_t _part) const { return m_singles[_part]; } 65 66 const auto& updateAndGetMulti() 67 { 68 updateMultiFromSingles(); 69 return getMulti(); 70 } 71 72 static void createDefaultSingle(SingleDump& _single, uint8_t _program, uint8_t _bank = n2x::SingleDumpBankEditBuffer); 73 static void copySingleToMulti(MultiDump& _multi, const SingleDump& _single, uint8_t _index); 74 static void extractSingleFromMulti(SingleDump& _single, const MultiDump& _multi, uint8_t _index); 75 static void createDefaultMulti(MultiDump& _multi, uint8_t _bank = SysexByte::MultiDumpBankEditBuffer); 76 77 template<size_t Size> 78 static void createHeader(std::array<uint8_t, Size>& _buffer, uint8_t _msgType, uint8_t _msgSpec); 79 80 static uint32_t getOffsetInSingleDump(SingleParam _param); 81 static uint32_t getOffsetInMultiDump(MultiParam _param); 82 83 uint8_t getPartMidiChannel(const uint8_t _part) const 84 { 85 return getPartMidiChannel(m_multi, _part); 86 } 87 88 std::vector<uint8_t> getPartsForMidiChannel(const synthLib::SMidiEvent& _ev) const; 89 std::vector<uint8_t> getPartsForMidiChannel(uint8_t _channel) const; 90 91 template<typename TDump> static uint8_t getPartMidiChannel(const TDump& _dump, const uint8_t _part) 92 { 93 return getMultiParam(_dump, static_cast<MultiParam>(SlotAMidiChannel + _part), 0); 94 } 95 96 template<typename TDump> static void setPartMidiChannel(TDump& _dump, const uint8_t _part, const uint8_t _channel) 97 { 98 setMultiParam(_dump, static_cast<MultiParam>(SlotAMidiChannel + _part), 0, _channel); 99 } 100 101 uint8_t getMultiParam(const MultiParam _param, const uint8_t _part) const 102 { 103 return getMultiParam(m_multi, _param, _part); 104 } 105 106 template<typename TDump> static uint8_t getMultiParam(const TDump& _dump, const MultiParam _param, const uint8_t _part) 107 { 108 const auto off = getOffsetInMultiDump(_param) + (_part << 2); 109 110 return unpackNibbles<TDump>(_dump, off); 111 } 112 113 template<typename TDump> static void setMultiParam(TDump& _dump, const MultiParam _param, const uint8_t _part, const uint8_t _value) 114 { 115 const auto off = getOffsetInMultiDump(_param) + (_part << 2); 116 117 packNibbles(_dump, off, _value); 118 } 119 120 template<typename TDump> static uint8_t getSingleParam(const TDump& _dump, const SingleParam _param, const uint8_t _part) 121 { 122 const auto off = getOffsetInSingleDump(_param) + (_part << 2); 123 124 return unpackNibbles<TDump>(_dump, off); 125 } 126 127 template<typename TDump> static uint8_t unpackNibbles(const TDump& _dump, uint32_t _off) 128 { 129 return static_cast<uint8_t>((_dump[_off] & 0xf) | (_dump[_off + 1] << 4)); 130 } 131 132 template<typename TDump> static void packNibbles(TDump& _dump, uint32_t _off, const uint8_t _value) 133 { 134 _dump[_off ] = _value & 0x0f; 135 _dump[_off+1] = _value >> 4; 136 } 137 138 static std::vector<uint8_t> createKnobSysex(KnobType _type, uint8_t _value); 139 static bool parseKnobSysex(KnobType& _type, uint8_t& _value, const std::vector<uint8_t>& _sysex); 140 141 bool getKnobState(uint8_t& _result, KnobType _type) const; 142 143 static bool isSingleDump(const std::vector<uint8_t>& _dump); 144 static bool isMultiDump(const std::vector<uint8_t>& _dump); 145 146 static std::string extractPatchName(const std::vector<uint8_t>& _dump); 147 static bool isDumpWithPatchName(const std::vector<uint8_t>& _dump); 148 static std::vector<uint8_t> stripPatchName(const std::vector<uint8_t>& _dump); 149 static bool isValidPatchName(const std::vector<uint8_t>& _dump); 150 static std::vector<uint8_t> validateDump(const std::vector<uint8_t>& _dump); 151 152 static synthLib::SMidiEvent& createPartCC(uint8_t _part, synthLib::SMidiEvent& _ccEvent); 153 154 private: 155 template<size_t Size> bool receive(const std::array<uint8_t, Size>& _data) 156 { 157 synthLib::SMidiEvent e; 158 e.sysex.insert(e.sysex.begin(), _data.begin(), _data.end()); 159 e.source = synthLib::MidiEventSource::Host; 160 return receive(e); 161 } 162 163 void send(const synthLib::SMidiEvent& _e) const; 164 165 Hardware* m_hardware; 166 synthLib::MidiTranslator* m_midiTranslator; 167 std::array<SingleDump, 4> m_singles; 168 MultiDump m_multi; 169 std::unordered_map<KnobType, uint8_t> m_knobStates; 170 }; 171 }