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

xt.cpp (3647B)


      1 #include "xt.h"
      2 
      3 #include "synthLib/midiTypes.h"
      4 
      5 #include "dsp56kEmu/threadtools.h"
      6 
      7 #include "xtHardware.h"
      8 #include "xtRomLoader.h"
      9 
     10 namespace xt
     11 {
     12 	Xt::Xt(const std::vector<uint8_t>& _romData, const std::string& _romName)
     13 	{
     14 		m_hw.reset(new Hardware(_romData, _romName));
     15 
     16 		if(!isValid())
     17 			return;
     18 
     19 		m_midiOutBuffer.reserve(1024);
     20 
     21 		m_ucThread.reset(new std::thread([&]()
     22 		{
     23 			dsp56k::ThreadTools::setCurrentThreadPriority(dsp56k::ThreadPriority::Highest);
     24 			dsp56k::ThreadTools::setCurrentThreadName("MC68331");
     25 			while(!m_destroy)
     26 				processUcThread();
     27 			m_destroy = false;
     28 			m_hw->ucThreadTerminated();
     29 		}));
     30 
     31 		m_hw->initVoiceExpansion();
     32 
     33 		m_hw->getUC().setLcdDirtyCallback([this]
     34 		{
     35 			m_dirtyFlags.fetch_or(static_cast<uint32_t>(DirtyFlags::Lcd));
     36 		});
     37 		m_hw->getUC().setLedsDirtyCallback([this]
     38 		{
     39 			m_dirtyFlags.fetch_or(static_cast<uint32_t>(DirtyFlags::Leds));
     40 		});
     41 	}
     42 
     43 	Xt::~Xt()
     44 	{
     45 		if(!isValid())
     46 			return;
     47 
     48 		// we need to have passed the boot stage
     49 		m_hw->processAudio(1);
     50 
     51 		m_destroy = true;
     52 
     53 		// DSP needs to run to let the uc thread wake up
     54 		const auto& esai = m_hw->getDSP().getPeriph().getEssi0();
     55 		while(m_destroy)
     56 		{
     57 			if(!esai.getAudioOutputs().empty())
     58 				m_hw->processAudio(1);
     59 			else
     60 				std::this_thread::yield();
     61 		}
     62 
     63 		m_ucThread->join();
     64 		m_ucThread.reset();
     65 		m_hw.reset();
     66 	}
     67 
     68 	bool Xt::isValid() const
     69 	{
     70 		return m_hw && m_hw->isValid();
     71 	}
     72 
     73 	void Xt::process(const float** _inputs, float** _outputs, uint32_t _frames, uint32_t _latency)
     74 	{
     75 		std::lock_guard lock(m_mutex);
     76 
     77 		m_hw->ensureBufferSize(_frames);
     78 
     79 		// convert inputs from float to DSP words
     80 		auto& dspIns = m_hw->getAudioInputs();
     81 
     82 		for(size_t c=0; c<dspIns.size(); ++c)
     83 		{
     84 			for(uint32_t i=0; i<_frames; ++i)
     85 				dspIns[c][i] = dsp56k::sample2dsp(_inputs[c][i]);
     86 		}
     87 
     88 		internalProcess(_frames, _latency);
     89 
     90 		// convert outputs from DSP words to float
     91 		const auto& dspOuts = m_hw->getAudioOutputs();
     92 
     93 		for(size_t c=0; c<dspOuts.size(); ++c)
     94 		{
     95 			for(uint32_t i=0; i<_frames; ++i)
     96 				_outputs[c][i] = dsp56k::dsp2sample<float>(dspOuts[c][i]);
     97 		}
     98 	}
     99 
    100 	void Xt::process(uint32_t _frames, uint32_t _latency)
    101 	{
    102 		std::lock_guard lock(m_mutex);
    103 		internalProcess(_frames, _latency);
    104 	}
    105 
    106 	void Xt::internalProcess(uint32_t _frames, uint32_t _latency)
    107 	{
    108 		// process audio
    109 		m_hw->processAudio(_frames, _latency);
    110 
    111 		// receive midi output
    112 		m_hw->receiveMidi(m_midiOutBuffer);
    113 	}
    114 
    115 	TAudioInputs& Xt::getAudioInputs() const
    116 	{
    117 		return m_hw->getAudioInputs();
    118 	}
    119 
    120 	TAudioOutputs& Xt::getAudioOutputs() const
    121 	{
    122 		return m_hw->getAudioOutputs();
    123 	}
    124 
    125 	void Xt::sendMidiEvent(const synthLib::SMidiEvent& _ev) const
    126 	{
    127 		m_hw->sendMidi(_ev);
    128 	}
    129 
    130 	void Xt::receiveMidi(std::vector<uint8_t>& _buffer)
    131 	{
    132 		std::lock_guard lock(m_mutex);
    133 		std::swap(_buffer, m_midiOutBuffer);
    134 		m_midiOutBuffer.clear();
    135 	}
    136 
    137 	Hardware* Xt::getHardware() const
    138 	{
    139 		return m_hw.get();
    140 	}
    141 
    142 	bool Xt::isBootCompleted() const
    143 	{
    144 		return m_hw && m_hw->isBootCompleted();
    145 	}
    146 
    147 	Xt::DirtyFlags Xt::getDirtyFlags()
    148 	{
    149 		const auto r = m_dirtyFlags.exchange(0);
    150 		return static_cast<DirtyFlags>(r);
    151 	}
    152 
    153 	void Xt::readLCD(std::array<char, 80>& _lcdData) const
    154 	{
    155 		_lcdData = m_hw->getUC().getLcd().getData();
    156 	}
    157 
    158 	bool Xt::getLedState(LedType _led) const
    159 	{
    160 		return m_hw->getUC().getLedState(_led);
    161 	}
    162 
    163 	bool Xt::getButton(ButtonType _button) const
    164 	{
    165 		return m_hw->getUC().getButton(_button);
    166 	}
    167 
    168 	void Xt::processUcThread() const
    169 	{
    170 		for(size_t i=0; i<32; ++i)
    171 		{
    172 			m_hw->process();
    173 			m_hw->process();
    174 			m_hw->process();
    175 			m_hw->process();
    176 			m_hw->process();
    177 			m_hw->process();
    178 			m_hw->process();
    179 			m_hw->process();
    180 		}
    181 	}
    182 }