/** * Furnace Tracker - multi-system chiptune tracker * Copyright (C) 2021-2022 tildearrow and contributors * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "rtmidi.h" #include "../ta-log.h" #include "taAudio.h" String sanitizePortName(const String& name) { #if defined(_WIN32) // remove port number size_t namePos=name.rfind(' '); if (namePos!=String::npos) { return name.substr(0,namePos); } return name; #elif defined(__linux__) // remove port location size_t namePos=name.rfind(' '); if (namePos!=String::npos) { return name.substr(0,namePos); } return name; #else return name; #endif } // --- IN --- bool TAMidiInRtMidi::gather() { std::vector msg; if (port==NULL) return false; try { while (true) { TAMidiMessage m; double t=port->getMessage(&msg); if (msg.empty()) break; // parse message m.time=t; m.type=msg[0]; if (m.type!=TA_MIDI_SYSEX && msg.size()>1) { memcpy(m.data,msg.data()+1,MIN(msg.size()-1,7)); } else if (m.type==TA_MIDI_SYSEX) { m.sysExData.reset(new unsigned char[msg.size()]); m.sysExLen=msg.size(); logD("got a SysEx of length %ld!",msg.size()); memcpy(m.sysExData.get(),msg.data(),msg.size()); } queue.push(m); } } catch (RtMidiError& e) { logE("MIDI input error! %s",e.what()); closeDevice(); return false; } return true; } std::vector TAMidiInRtMidi::listDevices() { std::vector ret; logD("listing devices."); if (port==NULL) return ret; try { unsigned int count=port->getPortCount(); logD("got port count."); for (unsigned int i=0; igetPortName(i)); if (name!="") ret.push_back(name); } } catch (RtMidiError& e) { logW("could not get MIDI inputs! %s",e.what()); } return ret; } bool TAMidiInRtMidi::isDeviceOpen() { return isOpen; } bool TAMidiInRtMidi::openDevice(String name) { if (port==NULL) return false; if (isOpen) return false; try { bool portOpen=false; unsigned int count=port->getPortCount(); logD("finding port %s...",name); for (unsigned int i=0; igetPortName(i)); logV("- %d: %s",i,portName); if (portName==name) { logD("opening port %d...",i); port->openPort(i); portOpen=true; break; } } isOpen=portOpen; if (!portOpen) logW("could not find MIDI in device..."); return portOpen; } catch (RtMidiError& e) { logW("could not open MIDI in device! %s",e.what()); return false; } return true; } bool TAMidiInRtMidi::closeDevice() { if (port==NULL) return false; if (!isOpen) return false; try { port->closePort(); } catch (RtMidiError& e) { logW("could not close MIDI in device! %s",e.what()); isOpen=false; // still return false; } isOpen=false; return true; } bool TAMidiInRtMidi::init() { if (port!=NULL) return true; try { port=new RtMidiIn; port->ignoreTypes(false,true,true); } catch (RtMidiError& e) { logW("could not initialize RtMidi in! %s",e.what()); return false; } return true; } bool TAMidiInRtMidi::quit() { if (port!=NULL) { delete port; port=NULL; } return true; } // --- OUT --- bool TAMidiOutRtMidi::send(const TAMidiMessage& what) { if (!isOpen) return false; if (what.type<0x80) return false; size_t len=0; switch (what.type&0xf0) { case TA_MIDI_NOTE_OFF: case TA_MIDI_NOTE_ON: case TA_MIDI_AFTERTOUCH: case TA_MIDI_CONTROL: case TA_MIDI_PITCH_BEND: len=3; break; case TA_MIDI_PROGRAM: case TA_MIDI_CHANNEL_AFTERTOUCH: len=2; break; } if (len==0) switch (what.type) { case TA_MIDI_SYSEX: if (what.sysExLen<1) { logE("sysExLen is NULL!"); return false; } if (what.sysExData.get()==NULL) { logE("sysExData is NULL!"); return false; } len=what.sysExLen; try { port->sendMessage(what.sysExData.get(),len); } catch (RtMidiError& e) { logE("MIDI output error! %s",e.what()); return false; } return true; break; case TA_MIDI_MTC_FRAME: case TA_MIDI_SONG_SELECT: len=2; break; case TA_MIDI_POSITION: len=3; break; default: len=1; break; } try { port->sendMessage((const unsigned char*)&what.type,len); } catch (RtMidiError& e) { logE("MIDI output error! %s",e.what()); return false; } return true; } bool TAMidiOutRtMidi::isDeviceOpen() { return isOpen; } bool TAMidiOutRtMidi::openDevice(String name) { if (port==NULL) return false; if (isOpen) return false; try { bool portOpen=false; unsigned int count=port->getPortCount(); logD("finding port %s...",name); for (unsigned int i=0; igetPortName(i)); logV("- %d: %s",i,portName); if (portName==name) { logD("opening port %d...",i); port->openPort(i); portOpen=true; break; } } isOpen=portOpen; if (!portOpen) logW("could not find MIDI out device..."); return portOpen; } catch (RtMidiError& e) { logW("could not open MIDI out device! %s",e.what()); return false; } return true; } bool TAMidiOutRtMidi::closeDevice() { if (port==NULL) return false; if (!isOpen) return false; try { port->closePort(); } catch (RtMidiError& e) { logW("could not close MIDI out device! %s",e.what()); isOpen=false; // still return false; } isOpen=false; return true; } std::vector TAMidiOutRtMidi::listDevices() { std::vector ret; if (port==NULL) return ret; try { unsigned int count=port->getPortCount(); for (unsigned int i=0; igetPortName(i)); if (name!="") ret.push_back(name); } } catch (RtMidiError& e) { logW("could not get MIDI outputs! %s",e.what()); } return ret; } bool TAMidiOutRtMidi::init() { if (port!=NULL) return true; try { port=new RtMidiOut; } catch (RtMidiError& e) { logW("could not initialize RtMidi out! %s",e.what()); return false; } return true; } bool TAMidiOutRtMidi::quit() { if (port!=NULL) { delete port; port=NULL; } return true; }