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

device.cpp (3711B)


      1 #include "device.h"
      2 
      3 #include "synthLib/deviceTypes.h"
      4 
      5 #include "mqbuildconfig.h"
      6 #include "mqhardware.h"
      7 
      8 namespace mqLib
      9 {
     10 	Device::Device(const synthLib::DeviceCreateParams& _params)
     11 		: wLib::Device(_params)
     12 		, m_mq(BootMode::Default, _params.romData, _params.romName)
     13 		, m_state(m_mq)
     14 		, m_sysexRemote(m_mq)
     15 	{
     16 		// we need to hit the play button to resume boot if the used rom is an OS update. mQ will complain about an uninitialized ROM area in this case
     17 		m_mq.setButton(Buttons::ButtonType::Play, true);
     18 		while(!m_mq.isBootCompleted())
     19 			m_mq.process(8);
     20 		m_mq.setButton(Buttons::ButtonType::Play, false);
     21 
     22 		m_state.createInitState();
     23 
     24 		auto* hw = m_mq.getHardware();
     25 		hw->resetMidiCounter();
     26 	}
     27 
     28 	Device::~Device() = default;
     29 
     30 	uint32_t Device::getInternalLatencyMidiToOutput() const
     31 	{
     32 		return 0;
     33 	}
     34 
     35 	uint32_t Device::getInternalLatencyInputToOutput() const
     36 	{
     37 		return 0;
     38 	}
     39 
     40 	float Device::getSamplerate() const
     41 	{
     42 		return 44100.0f;
     43 	}
     44 
     45 	bool Device::isValid() const
     46 	{
     47 		return m_mq.isValid();
     48 	}
     49 
     50 	bool Device::getState(std::vector<uint8_t>& _state, synthLib::StateType _type)
     51 	{
     52 		return m_state.getState(_state, _type);
     53 	}
     54 
     55 	bool Device::setState(const std::vector<uint8_t>& _state, synthLib::StateType _type)
     56 	{
     57 		if constexpr (g_pluginDemo)
     58 			return false;
     59 
     60 		return m_state.setState(_state, _type);
     61 	}
     62 
     63 	uint32_t Device::getChannelCountIn()
     64 	{
     65 		return 2;
     66 	}
     67 
     68 	uint32_t Device::getChannelCountOut()
     69 	{
     70 		return 6;
     71 	}
     72 
     73 	void Device::readMidiOut(std::vector<synthLib::SMidiEvent>& _midiOut)
     74 	{
     75 		m_mq.receiveMidi(m_midiOutBuffer);
     76 		m_midiOutParser.write(m_midiOutBuffer);
     77 		m_midiOutParser.getEvents(_midiOut);
     78 		m_midiOutBuffer.clear();
     79 
     80 		Responses responses;
     81 
     82 		for (const auto& midiOut : _midiOut)
     83 		{
     84 			m_state.receive(responses, midiOut, State::Origin::Device);
     85 
     86 			for (auto& response : responses)
     87 			{
     88 				auto& r = _midiOut.emplace_back();
     89 				std::swap(response, r.sysex);
     90 			}
     91 		}
     92 
     93 		if(!m_customSysexOut.empty())
     94 		{
     95 			_midiOut.insert(_midiOut.begin(), m_customSysexOut.begin(), m_customSysexOut.end());
     96 			m_customSysexOut.clear();
     97 		}
     98 	}
     99 
    100 	void Device::processAudio(const synthLib::TAudioInputs& _inputs, const synthLib::TAudioOutputs& _outputs, const size_t _samples)
    101 	{
    102 		const float* inputs[2] = {_inputs[0], _inputs[1]};
    103 		float* outputs[6] = {_outputs[0], _outputs[1], _outputs[2], _outputs[3], _outputs[4], _outputs[5]};
    104 
    105 		m_mq.process(inputs, outputs, static_cast<uint32_t>(_samples), getExtraLatencySamples());
    106 
    107 		const auto dirty = static_cast<uint32_t>(m_mq.getDirtyFlags());
    108 
    109 		m_sysexRemote.handleDirtyFlags(m_customSysexOut, dirty);
    110 	}
    111 
    112 	bool Device::sendMidi(const synthLib::SMidiEvent& _ev, std::vector<synthLib::SMidiEvent>& _response)
    113 	{
    114 		const auto& sysex = _ev.sysex;
    115 
    116 		if (!sysex.empty())
    117 		{
    118 			if (m_sysexRemote.receive(m_customSysexOut, sysex))
    119 				return true;
    120 		}
    121 
    122 		Responses responses;
    123 
    124 		const auto res = m_state.receive(responses, _ev, State::Origin::External);
    125 
    126 		for (auto& response : responses)
    127 		{
    128 			auto& r = _response.emplace_back();
    129 			std::swap(response, r.sysex);
    130 		}
    131 
    132 		// do not forward to device if our cache was able to reply. It might have sent something to the device already on its own if a cache miss occured
    133 		if(res)
    134 			return true;
    135 
    136 		if(_ev.sysex.empty())
    137 		{
    138 			auto e = _ev;
    139 			e.offset += m_numSamplesProcessed + getExtraLatencySamples();
    140 			m_mq.sendMidiEvent(e);
    141 		}
    142 		else
    143 		{
    144 			m_mq.sendMidiEvent(_ev);
    145 		}
    146 
    147 		return true;
    148 	}
    149 
    150 	dsp56k::EsxiClock* Device::getDspEsxiClock() const
    151 	{
    152 		auto& mq = const_cast<MicroQ&>(m_mq);
    153 		auto* p = dynamic_cast<dsp56k::Peripherals56362*>(mq.getHardware()->getDSP().dsp().getPeriph(dsp56k::MemArea_X));
    154 		if(!p)
    155 			return nullptr;
    156 		return &p->getEsaiClock();
    157 	}
    158 }