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

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 }