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

n2xfrontpanel.cpp (6012B)


      1 #include "n2xfrontpanel.h"
      2 
      3 #include <cassert>
      4 #include <cstring>	// memcpy
      5 
      6 #include "n2xhardware.h"
      7 
      8 #include "dsp56kEmu/logging.h"
      9 
     10 namespace n2x
     11 {
     12 	template class FrontPanelCS<g_frontPanelAddressCS4>;
     13 	template class FrontPanelCS<g_frontPanelAddressCS6>;
     14 
     15 	template <uint32_t Base> FrontPanelCS<Base>::FrontPanelCS(FrontPanel& _fp): m_panel(_fp)
     16 	{
     17 	}
     18 
     19 	FrontPanelCS4::FrontPanelCS4(FrontPanel& _fp) : FrontPanelCS(_fp)
     20 	{
     21 		setKnobPosition(KnobType::PitchBend,	0);			// pretend we're a rack unit
     22 		setKnobPosition(KnobType::ModWheel,		0);			// pretend we're a rack unit
     23 
     24 		setKnobPosition(KnobType::MasterVol,	0xff);
     25 		setKnobPosition(KnobType::AmpGain,		0xff);
     26 		setKnobPosition(KnobType::Osc1Fm,		0);
     27 		setKnobPosition(KnobType::Porta,		0);
     28 		setKnobPosition(KnobType::Lfo2Rate,		0x0);
     29 		setKnobPosition(KnobType::Lfo1Rate,		0x0);
     30 		setKnobPosition(KnobType::ModEnvAmt,	0);
     31 		setKnobPosition(KnobType::ModEnvD,		0);
     32 		setKnobPosition(KnobType::ModEnvA,		0);
     33 		setKnobPosition(KnobType::AmpEnvD,		0);
     34 		setKnobPosition(KnobType::FilterFreq,	0xff);
     35 		setKnobPosition(KnobType::FilterEnvA,	0);
     36 		setKnobPosition(KnobType::AmpEnvA,		0);
     37 		setKnobPosition(KnobType::OscMix,		0x7f);
     38 		setKnobPosition(KnobType::Osc2Fine,		0x7f);
     39 		setKnobPosition(KnobType::Lfo1Amount,	0x0f);
     40 		setKnobPosition(KnobType::OscPW,		0x40);
     41 		setKnobPosition(KnobType::FilterEnvR,	0x30);
     42 		setKnobPosition(KnobType::AmpEnvR,		0x90);
     43 		setKnobPosition(KnobType::FilterEnvAmt,	0);
     44 		setKnobPosition(KnobType::FilterEnvS,	0x7f);
     45 		setKnobPosition(KnobType::AmpEnvS,		0x7f);
     46 		setKnobPosition(KnobType::FilterReso,	0x10);
     47 		setKnobPosition(KnobType::FilterEnvD,	0);
     48 		setKnobPosition(KnobType::ExpPedal,		0x0);
     49 		setKnobPosition(KnobType::Lfo2Amount,	0);
     50 		setKnobPosition(KnobType::Osc2Semi,		0x7f);
     51 	}
     52 
     53 	uint8_t FrontPanelCS4::read8(mc68k::PeriphAddress _addr)
     54 	{
     55 		const auto knobType = m_panel.cs6().getKnobType();
     56 
     57 		if(knobType == KnobType::Invalid)
     58 			return 0;
     59 
     60 		return getKnobPosition(knobType);
     61 	}
     62 
     63 	uint8_t FrontPanelCS4::getKnobPosition(KnobType _knob) const
     64 	{
     65 		const auto i = static_cast<uint32_t>(_knob) - static_cast<uint32_t>(KnobType::First);
     66 		return m_knobPositions[i];
     67 	}
     68 
     69 	void FrontPanelCS4::setKnobPosition(KnobType _knob, const uint8_t _value)
     70 	{
     71 		const auto i = static_cast<uint32_t>(_knob) - static_cast<uint32_t>(KnobType::First);
     72 		m_knobPositions[i] = _value;
     73 	}
     74 
     75 	FrontPanelCS6::FrontPanelCS6(FrontPanel& _fp) : FrontPanelCS(_fp), m_buttonStates({})
     76 	{
     77 		m_buttonStates.fill(0xff);
     78 	}
     79 
     80 	void FrontPanelCS6::write8(const mc68k::PeriphAddress _addr, const uint8_t _val)
     81 	{
     82 //		LOG("Write CS6 " << HEXN(_addr - base(),2) << " = " << HEXN(_val,2));
     83 
     84 		switch (static_cast<uint32_t>(_addr))
     85 		{
     86 			case g_frontPanelAddressCS6 + 0x8:
     87 				m_ledLatch8 = _val;
     88 				break;
     89 			case g_frontPanelAddressCS6 + 0xa:
     90 				m_ledLatch10 = _val;
     91 
     92 //				LOG("Read pot " << HEXN((_val & 0x7f), 2));
     93 				m_selectedKnob = static_cast<KnobType>(_val & 0x7f);
     94 
     95 				if(m_ledLatch10 & (1<<7))
     96 				{
     97 					m_lcds[2] = m_ledLatch8;
     98 					onLCDChanged();
     99 				}
    100 				break;
    101 			case g_frontPanelAddressCS6 + 0xc:
    102 				{
    103 					bool gotLCDs = false;
    104 
    105 					m_ledLatch12 = _val;
    106 
    107 					if(m_ledLatch12 & (1<<6))
    108 					{
    109 						m_lcds[0] = m_ledLatch8;
    110 						gotLCDs = true;
    111 					}
    112 					if(m_ledLatch12 & (1<<7))
    113 					{
    114 						m_lcds[1] = m_ledLatch8;
    115 						gotLCDs = true;
    116 					}
    117 
    118 					if(gotLCDs)
    119 						onLCDChanged();
    120 				}
    121 				break;
    122 		}
    123 		FrontPanelCS::write8(_addr, _val);
    124 	}
    125 
    126 	uint8_t FrontPanelCS6::read8(mc68k::PeriphAddress _addr)
    127 	{
    128 		const auto a = static_cast<uint32_t>(_addr);
    129 		switch (a)
    130 		{
    131 		case g_frontPanelAddressCS6:		return m_buttonStates[0];
    132 		case g_frontPanelAddressCS6 + 2:	return m_buttonStates[1];
    133 		case g_frontPanelAddressCS6 + 4:	return m_buttonStates[2];
    134 		case g_frontPanelAddressCS6 + 6:	return m_buttonStates[3];
    135 		}
    136 		return FrontPanelCS::read8(_addr);
    137 	}
    138 
    139 	void FrontPanelCS6::setButtonState(ButtonType _button, const bool _pressed)
    140 	{
    141 		const auto id = static_cast<uint32_t>(_button);
    142 		const auto index = id>>9;
    143 		const auto mask = id & 0xff;
    144 		if(_pressed)
    145 			m_buttonStates[index] |= mask;
    146 		else
    147 			m_buttonStates[index] &= ~mask;
    148 	}
    149 
    150 	bool FrontPanelCS6::getButtonState(ButtonType _button) const
    151 	{
    152 		const auto id = static_cast<uint32_t>(_button);
    153 		const auto index = id>>9;
    154 		const auto mask = id & 0xff;
    155 		return m_buttonStates[index] & mask ? false : true;
    156 	}
    157 
    158 	void FrontPanelCS6::printLCD() const
    159 	{
    160 		static uint32_t count = 0;
    161 		++count;
    162 		if(count & 0xff)
    163 			return;
    164 		/*
    165 		 --    --    --
    166 		|  |  |  |  |  |
    167 		 --    --    --
    168 		|  |  |  |  |  |
    169 		 --    --    --
    170 		*/
    171 
    172 		using Line = std::array<char, 16>;
    173 		std::array<Line,5> buf;
    174 
    175 		for (auto& b : buf)
    176 		{
    177 			b.fill(' ');
    178 		}
    179 
    180 		int off = 0;
    181 
    182 		auto drawH = [&](int _x, const int _y, const bool _set)
    183 		{
    184 			_x += off;
    185 			buf[_y][_x  ] = _set ? '-' : ' ';
    186 			buf[_y][_x+1] = _set ? '-' : ' ';
    187 		};
    188 
    189 		auto drawV = [&](int _x, const int _y, const bool _set)
    190 		{
    191 			_x += off;
    192 			buf[_y][_x] = _set ? '|' : ' ';
    193 		};
    194 
    195 		for(auto i=0; i<3; ++i)
    196 		{
    197 			auto bt = [&](const uint32_t _bit)
    198 			{
    199 				return !(m_lcds[i] & (1<<_bit));
    200 			};
    201 
    202 			drawH(1, 0, bt(7));
    203 			drawH(1, 2, bt(1));
    204 			drawH(1, 4, bt(4));
    205 
    206 			drawV(0, 1, bt(2));
    207 			drawV(3, 1, bt(6));
    208 			drawV(0, 3, bt(3));
    209 			drawV(3, 3, bt(5));
    210 
    211 			off += 6;
    212 		}
    213 
    214 		buf[4][4] = (m_lcds[0] & (1<<0)) ? ' ' : '*';
    215 
    216 		char message[(sizeof(Line) + 1) * buf.size() + 1];
    217 		size_t i=0;
    218 		for (const auto& line : buf)
    219 		{
    220 			memcpy(&message[i], line.data(), line.size());
    221 			i += line.size();
    222 			message[i++] = '\n';
    223 		}
    224 		assert(i == std::size(message)-1);
    225 		message[i] = 0;
    226 
    227 		LOG("LCD:\n" << message);
    228 	}
    229 
    230 	void FrontPanelCS6::onLCDChanged()
    231 	{
    232 		// Check if the LCD displays "  1", used as indicator that device has finished booting
    233 		if(m_lcds[0] == 255 && m_lcds[1] >= 254 && m_lcds[2] == 159)
    234 		{
    235 			m_panel.getHardware().notifyBootFinished();
    236 		}
    237 #ifdef _DEBUG
    238 		printLCD();
    239 #endif
    240 	}
    241 
    242 	FrontPanel::FrontPanel(Hardware& _hardware) : m_hardware(_hardware), m_cs4(*this), m_cs6(*this)
    243 	{
    244 	}
    245 }