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

midiInput.cpp (2748B)


      1 #include "midiInput.h"
      2 
      3 #include <array>
      4 #include <cassert>
      5 
      6 #include "portmidi/pm_common/portmidi.h"
      7 
      8 #include <chrono>
      9 
     10 #include "dsp56kEmu/logging.h"
     11 
     12 #ifndef Pm_MessageData3
     13 #define Pm_MessageData3(msg) (((msg) >> 24) & 0xFF)
     14 #endif
     15 
     16 PmTimestamp returnTimeProc(void*)
     17 {
     18 	const auto now = std::chrono::system_clock::now().time_since_epoch();
     19 	return static_cast<PmTimestamp>(std::chrono::duration_cast<std::chrono::milliseconds>(now).count());
     20 }
     21 
     22 namespace mqConsoleLib
     23 {
     24 MidiInput::MidiInput(const std::string& _deviceName) : MidiDevice(_deviceName, false)
     25 {
     26 	Device::openDevice();
     27 }
     28 
     29 MidiInput::~MidiInput()
     30 {
     31 	Pm_Close(m_stream);
     32 	m_stream = nullptr;
     33 	m_deviceId = -1;
     34 }
     35 
     36 int MidiInput::getDefaultDeviceId() const
     37 {
     38 	return Pm_GetDefaultInputDeviceID();
     39 }
     40 
     41 bool MidiInput::openDevice(int _devId)
     42 {
     43 	const auto err = Pm_OpenInput(&m_stream, _devId, nullptr, 1024, returnTimeProc, this);
     44 
     45 	if(err != pmNoError)
     46 	{
     47 		LOG("Failed to open MIDI input device " << deviceNameFromId(_devId));
     48 		m_stream = nullptr;
     49 	}
     50 
     51 	return err == pmNoError;
     52 }
     53 
     54 bool MidiInput::process(std::vector<synthLib::SMidiEvent>& _events)
     55 {
     56 	if(!m_stream)
     57 		return false;
     58 
     59 	if(Pm_Poll(m_stream) == pmNoData)
     60 		return false;
     61 
     62 	while(true)
     63 	{
     64 		PmEvent e;
     65 		const auto count = Pm_Read(m_stream, &e, 1);
     66 
     67 		if(!count)
     68 			return false;
     69 
     70 		if(count != 1)
     71 			continue;
     72 
     73 		process(_events, e.message);
     74 	}
     75 }
     76 
     77 void MidiInput::process(std::vector<synthLib::SMidiEvent>& _events, uint32_t _message)
     78 {
     79 	const uint8_t bytes[] = {
     80 		static_cast<uint8_t>(Pm_MessageStatus(_message)),
     81 		static_cast<uint8_t>(Pm_MessageData1(_message)),
     82 		static_cast<uint8_t>(Pm_MessageData2(_message)),
     83 		static_cast<uint8_t>(Pm_MessageData3(_message))
     84 	};
     85 
     86 	for (const auto byte : bytes)
     87 	{
     88 		if(byte == synthLib::M_STARTOFSYSEX)
     89 		{
     90 			assert(m_sysexBuffer.empty());
     91 			m_readSysex = true;
     92 			m_sysexBuffer.push_back(byte);
     93 		}
     94 		else if(m_readSysex)
     95 		{
     96 			if(byte >= 0x80)
     97 			{
     98 				if(byte == synthLib::M_ENDOFSYSEX)
     99 				{
    100 					m_sysexBuffer.push_back(byte);
    101 					std::stringstream ss;
    102 					ss << HEXN(m_sysexBuffer.front(), 2);
    103 					for(size_t i=1; i<m_sysexBuffer.size(); ++i)
    104 						ss << ',' << HEXN(m_sysexBuffer[i], 2);
    105 					const std::string s(ss.str());
    106 					LOG("Received sysex of size " << m_sysexBuffer.size() << ": " << s);
    107 				}
    108 				else
    109 				{
    110 					LOG("Received ABORTED sysex of size " << m_sysexBuffer.size());
    111 				}
    112 
    113 				m_readSysex = false;
    114 				synthLib::SMidiEvent ev(synthLib::MidiEventSource::PhysicalInput);
    115 				std::swap(m_sysexBuffer, ev.sysex);
    116 				m_sysexBuffer.clear();
    117 				_events.emplace_back(ev);
    118 				return;
    119 			}
    120 
    121 			m_sysexBuffer.push_back(byte);
    122 		}
    123 	}
    124 
    125 	if(!m_readSysex)
    126 		_events.emplace_back(synthLib::MidiEventSource::PhysicalInput, bytes[0], bytes[1], bytes[2]);
    127 }
    128 }