mqFrontPanel.cpp (5780B)
1 #include "mqFrontPanel.h" 2 3 #include "mqController.h" 4 #include "mqEditor.h" 5 #include "mqLcd.h" 6 #include "mqLcdText.h" 7 8 #include "mqLib/device.h" 9 #include "mqLib/mqmiditypes.h" 10 11 #include "dsp56kEmu/fastmath.h" 12 13 namespace mqLib 14 { 15 enum class SysexCommand : uint8_t; 16 } 17 18 namespace mqJucePlugin 19 { 20 constexpr float g_encoderSpeed = 2.0f; 21 22 constexpr const char* g_ledNames[] = 23 { 24 "ledOsc1", "ledFilter2", "ledInst1", "ledGlobal", "ledPlay", 25 "ledOsc2", "ledAmpFxArp", "ledInst2", "ledMulti", "ledPeek", 26 "ledOsc3", "ledEnv1", "ledInst3", "ledEdit", "ledMultimode", 27 "ledMixerRouting", "ledEnv2", "ledInst4", "ledSound", "ledShift", 28 "ledFilter1", "ledEnv3", "ledModMatrix", "ledLFOs", "ledEnv4", 29 "ledPower" 30 }; 31 32 constexpr const char* g_buttonNames[] = 33 { 34 "buttonInst1", "buttonInst2", "buttonInst3", "buttonInst4", 35 "buttonD", "buttonL", "buttonR", "buttonU", "buttonGlobal", 36 "buttonMulti", "buttonEdit", "buttonSound", "buttonShift", 37 "buttonMultimode", "buttonPeek", "buttonPlay", "buttonPower" 38 }; 39 40 constexpr const char* g_encoderNames[] = 41 { 42 "encoderMatrix4", "encoderMatrix3", "encoderMatrix2", "encoderMatrix1", 43 "encoderLCDRight", "encoderLCDLeft", 44 "encoderAlphaDial" 45 }; 46 47 FrontPanel::FrontPanel(const mqJucePlugin::Editor& _editor, Controller& _controller) : m_controller(_controller) 48 { 49 _controller.setFrontPanel(this); 50 51 for(size_t i=0; i<std::size(g_ledNames); ++i) 52 m_leds[i] = _editor.findComponentT<juce::Button>(g_ledNames[i], false); 53 54 for(size_t i=0; i<std::size(g_buttonNames); ++i) 55 { 56 auto* b = _editor.findComponentT<juce::Button>(g_buttonNames[i], false); 57 m_buttons[i] = b; 58 if(!b) 59 continue; 60 61 const auto index = static_cast<uint32_t>(i); 62 b->onStateChange = [this, index] 63 { 64 onButtonStateChanged(index); 65 }; 66 } 67 68 for(size_t i=0; i<std::size(g_encoderNames); ++i) 69 { 70 auto* e = _editor.findComponentT<juce::Slider>(g_encoderNames[i], false); 71 if(!e) 72 continue; 73 74 m_encoders[i] = e; 75 76 e->setRotaryParameters(0.0f, juce::MathConstants<float>::twoPi, false); 77 const auto index = static_cast<uint32_t>(i); 78 e->onValueChange = [this, index] 79 { 80 onEncoderValueChanged(index); 81 }; 82 } 83 84 auto *lcdArea = _editor.findComponentT<juce::Component>("lcdArea", false); 85 86 if (lcdArea) 87 m_lcd.reset(new MqLcd(*lcdArea)); 88 89 std::array<juce::Label*, 2> lcdLines{}; 90 91 lcdLines[0] = _editor.findComponentT<juce::Label>("lcdLineA", false); 92 lcdLines[1] = _editor.findComponentT<juce::Label>("lcdLineB", lcdLines[0] != nullptr); 93 94 if (lcdLines[0]) 95 { 96 if (m_lcd) 97 { 98 lcdLines[0]->setVisible(false); 99 lcdLines[1]->setVisible(false); 100 } 101 else 102 { 103 m_lcd.reset(new MqLcdText(*lcdLines[0], *lcdLines[1])); 104 } 105 } 106 107 auto* shadow = _editor.findComponent("lcdshadow", false); 108 109 if(shadow) 110 shadow->setInterceptsMouseClicks(false, false); 111 112 _controller.sendSysEx(Controller::EmuRequestLcd); 113 _controller.sendSysEx(Controller::EmuRequestLeds); 114 } 115 116 FrontPanel::~FrontPanel() 117 { 118 m_controller.setFrontPanel(nullptr); 119 m_lcd.reset(); 120 } 121 122 void FrontPanel::processSysex(const std::vector<uint8_t>& _msg) const 123 { 124 if(_msg.size() < 5) 125 return; 126 127 const auto cmd = static_cast<mqLib::SysexCommand>(_msg[4]); 128 129 switch (cmd) 130 { 131 case mqLib::SysexCommand::EmuLCD: 132 processLCDUpdate(_msg); 133 break; 134 case mqLib::SysexCommand::EmuLCDCGRata: 135 processLCDCGRamUpdate(_msg); 136 break; 137 case mqLib::SysexCommand::EmuLEDs: 138 processLedUpdate(_msg); 139 break; 140 case mqLib::SysexCommand::EmuRotaries: 141 case mqLib::SysexCommand::EmuButtons: 142 default: 143 break; 144 } 145 } 146 147 void FrontPanel::processLCDUpdate(const std::vector<uint8_t>& _msg) const 148 { 149 const auto* data = &_msg[5]; 150 151 std::array<uint8_t, 40> d{}; 152 153 for(size_t i=0; i<d.size(); ++i) 154 d[i] = data[i]; 155 156 m_lcd->setText(d); 157 } 158 159 void FrontPanel::processLCDCGRamUpdate(const std::vector<uint8_t>& _msg) const 160 { 161 const auto *data = &_msg[5]; 162 163 std::array<uint8_t, 64> d{}; 164 for (size_t i = 0; i < d.size(); ++i) 165 d[i] = data[i]; 166 167 m_lcd->setCgRam(d); 168 } 169 170 void FrontPanel::processLedUpdate(const std::vector<uint8_t>& _msg) const 171 { 172 const uint32_t leds = 173 (static_cast<uint32_t>(_msg[5]) << 24) | 174 (static_cast<uint32_t>(_msg[6]) << 16) | 175 (static_cast<uint32_t>(_msg[7]) << 8) | 176 static_cast<uint32_t>(_msg[8]); 177 178 for(size_t i=0; i<static_cast<uint32_t>(mqLib::Leds::Led::Count); ++i) 179 { 180 if(m_leds[i]) 181 m_leds[i]->setToggleState((leds & (1<<i)) != 0, juce::dontSendNotification); 182 } 183 } 184 185 void FrontPanel::onButtonStateChanged(uint32_t _index) const 186 { 187 const auto* b = m_buttons[_index]; 188 189 std::map<pluginLib::MidiDataType, uint8_t> params; 190 191 params[pluginLib::MidiDataType::ParameterIndex] = static_cast<uint8_t>(_index); 192 193 if(b->getClickingTogglesState()) 194 params[pluginLib::MidiDataType::ParameterValue] = b->getToggleState() ? 1 : 0; 195 else 196 params[pluginLib::MidiDataType::ParameterValue] = b->getState() == juce::Button::buttonDown ? 1 : 0; 197 198 m_controller.sendSysEx(Controller::EmuSendButton, params); 199 } 200 201 void FrontPanel::onEncoderValueChanged(uint32_t _index) 202 { 203 const auto* e = m_encoders[_index]; 204 205 float& vOld = m_encoderValues[_index]; 206 const auto v = static_cast<float>(e->getValue()); 207 208 auto delta = v - vOld; 209 210 if(v >= 9.0f && vOld <= 1.0f) 211 delta = v - (vOld + 10.0f); 212 if(v <= 1.0f && vOld >= 9.0f) 213 delta = v - (vOld - 10.0f); 214 215 const int deltaInt = dsp56k::clamp(juce::roundToInt(g_encoderSpeed * delta) + 64, 0, 127); 216 217 if(deltaInt == 64) 218 return; 219 220 vOld = v; 221 222 std::map<pluginLib::MidiDataType, uint8_t> params; 223 224 params[pluginLib::MidiDataType::ParameterIndex] = static_cast<uint8_t>(_index); 225 params[pluginLib::MidiDataType::ParameterValue] = static_cast<uint8_t>(deltaInt); 226 227 m_controller.sendSysEx(Controller::EmuSendRotary, params); 228 } 229 }