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

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 }