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 }