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

mqsysexremotecontrol.cpp (4790B)


      1 #include "mqsysexremotecontrol.h"
      2 
      3 #include "buttons.h"
      4 #include "mqmiditypes.h"
      5 #include "microq.h"
      6 
      7 #include "synthLib/midiTypes.h"
      8 
      9 namespace mqLib
     10 {
     11 	void SysexRemoteControl::createSysexHeader(std::vector<uint8_t>& _dst, SysexCommand _cmd)
     12 	{
     13 		constexpr uint8_t devId = 0;
     14 		_dst.assign({0xf0, wLib::IdWaldorf, IdMicroQ, devId, static_cast<uint8_t>(_cmd)});
     15 	}
     16 
     17 	void SysexRemoteControl::sendSysexLCD(std::vector<synthLib::SMidiEvent>& _dst) const
     18 	{
     19 		std::array<char, 40> lcdData{};
     20 		m_mq.readLCD(lcdData);
     21 
     22 		synthLib::SMidiEvent ev(synthLib::MidiEventSource::Internal);
     23 		createSysexHeader(ev.sysex, SysexCommand::EmuLCD);
     24 		ev.sysex.insert(ev.sysex.end(), lcdData.begin(), lcdData.end());
     25 		ev.sysex.push_back(0xf7);
     26 
     27 		_dst.emplace_back(ev);
     28 	}
     29 	
     30 	void SysexRemoteControl::sendSysexLCDCGRam(std::vector<synthLib::SMidiEvent>& _dst) const
     31 	{
     32 		std::array<char, 64> lcdData{};
     33 
     34 		std::array<uint8_t, 8> data{};
     35 
     36 		for (auto i=0, k=0; i<8; ++i)
     37 		{
     38 			m_mq.readCustomLCDCharacter(data, i);
     39 			for (auto j=0; j<8; ++j)
     40 				lcdData[k++] = static_cast<char>(data[j]);
     41 		}
     42 
     43 		synthLib::SMidiEvent ev(synthLib::MidiEventSource::Internal);
     44 		createSysexHeader(ev.sysex, SysexCommand::EmuLCDCGRata);
     45 		ev.sysex.insert(ev.sysex.end(), lcdData.begin(), lcdData.end());
     46 		ev.sysex.push_back(0xf7);
     47 
     48 		_dst.emplace_back(ev);
     49 	}
     50 	
     51 	void SysexRemoteControl::sendSysexButtons(std::vector<synthLib::SMidiEvent>& _dst) const
     52 	{
     53 		static_assert(static_cast<uint32_t>(Buttons::ButtonType::Count) < 24, "too many buttons");
     54 		uint32_t buttons = 0;
     55 		for(uint32_t i=0; i<static_cast<uint32_t>(Buttons::ButtonType::Count); ++i)
     56 		{
     57 			if(m_mq.getButton(static_cast<Buttons::ButtonType>(i)))
     58 				buttons |= (1<<i);
     59 		}
     60 
     61 		auto& ev = _dst.emplace_back(synthLib::MidiEventSource::Internal);
     62 
     63 		createSysexHeader(ev.sysex, SysexCommand::EmuButtons);
     64 
     65 		ev.sysex.push_back((buttons>>16) & 0xff);
     66 		ev.sysex.push_back((buttons>>8) & 0xff);
     67 		ev.sysex.push_back(buttons & 0xff);
     68 		ev.sysex.push_back(0xf7);
     69 	}
     70 
     71 	void SysexRemoteControl::sendSysexLEDs(std::vector<synthLib::SMidiEvent>& _dst) const
     72 	{
     73 		static_assert(static_cast<uint32_t>(Leds::Led::Count) < 32, "too many LEDs");
     74 		uint32_t leds = 0;
     75 		for(uint32_t i=0; i<static_cast<uint32_t>(Leds::Led::Count); ++i)
     76 		{
     77 			if(m_mq.getLedState(static_cast<Leds::Led>(i)))
     78 				leds |= (1<<i);
     79 		}
     80 		auto& ev = _dst.emplace_back(synthLib::MidiEventSource::Internal);
     81 		auto& response = ev.sysex;
     82 		createSysexHeader(response, SysexCommand::EmuLEDs);
     83 		response.push_back((leds>>24) & 0xff);
     84 		response.push_back((leds>>16) & 0xff);
     85 		response.push_back((leds>>8) & 0xff);
     86 		response.push_back(leds & 0xff);
     87 		response.push_back(0xf7);
     88 	}
     89 
     90 	void SysexRemoteControl::sendSysexRotaries(std::vector<synthLib::SMidiEvent>& _dst) const
     91 	{
     92 		auto& ev= _dst.emplace_back(synthLib::MidiEventSource::Internal);
     93 		auto& response = ev.sysex;
     94 
     95 		createSysexHeader(response, SysexCommand::EmuRotaries);
     96 
     97 		for(uint32_t i=0; i<static_cast<uint32_t>(Buttons::Encoders::Count); ++i)
     98 		{
     99 			const auto value = m_mq.getEncoder(static_cast<Buttons::Encoders>(i));
    100 			response.push_back(value);
    101 		}
    102 		response.push_back(0xf7);
    103 	}
    104 
    105 	bool SysexRemoteControl::receive(std::vector<synthLib::SMidiEvent>& _output, const std::vector<unsigned char>& _input) const
    106 	{
    107 		if(_input.size() < 5)
    108 			return false;
    109 
    110 		if(_input[1] != wLib::IdWaldorf || _input[2] != IdMicroQ)
    111 			return false;
    112 
    113 		const auto cmd = _input[4];
    114 
    115 		switch (static_cast<SysexCommand>(cmd))
    116 		{
    117 		case SysexCommand::EmuLCD:
    118 			sendSysexLCD(_output);
    119 			return true;
    120 		case SysexCommand::EmuLCDCGRata:
    121 			sendSysexLCDCGRam(_output);
    122 			return true;
    123 		case SysexCommand::EmuButtons:
    124 			{
    125 				if(_input.size() > 6)
    126 				{
    127 					const auto button = static_cast<Buttons::ButtonType>(_input[5]);
    128 					const auto state = _input[6];
    129 					m_mq.setButton(button, state != 0);
    130 				}
    131 				else
    132 				{
    133 					sendSysexButtons(_output);
    134 				}
    135 			}
    136 			return true;
    137 		case SysexCommand::EmuLEDs:
    138 			{
    139 				sendSysexLEDs(_output);
    140 			}
    141 			return true;
    142 		case SysexCommand::EmuRotaries:
    143 			{
    144 				if(_input.size() > 6)
    145 				{
    146 					const auto encoder = static_cast<Buttons::Encoders>(_input[5]);
    147 					const auto amount = static_cast<int>(_input[6]) - 64;
    148 					if(amount)
    149 						m_mq.rotateEncoder(encoder, amount);
    150 				}
    151 				else
    152 				{
    153 					sendSysexRotaries(_output);
    154 				}
    155 			}
    156 			return true;
    157 		default:
    158 			return false;
    159 		}
    160 	}
    161 
    162 	void SysexRemoteControl::handleDirtyFlags(std::vector<synthLib::SMidiEvent>& _output, uint32_t _dirtyFlags) const
    163 	{
    164 		if(_dirtyFlags & static_cast<uint32_t>(MicroQ::DirtyFlags::Lcd))
    165 			sendSysexLCD(_output);
    166 		if(_dirtyFlags & static_cast<uint32_t>(MicroQ::DirtyFlags::LcdCgRam))
    167 			sendSysexLCDCGRam(_output);
    168 		if(_dirtyFlags & static_cast<uint32_t>(MicroQ::DirtyFlags::Leds))
    169 			sendSysexLEDs(_output);
    170 	}
    171 }