#include "rtmidi.hpp" #include namespace rack { static void midiInputCallback(double timeStamp, std::vector *message, void *userData) { if (!message) return; if (!userData) return; RtMidiInputDevice *midiInputDevice = (RtMidiInputDevice*) userData; if (!midiInputDevice) return; MidiMessage msg; if (message->size() >= 1) msg.cmd = (*message)[0]; if (message->size() >= 2) msg.data1 = (*message)[1]; if (message->size() >= 3) msg.data2 = (*message)[2]; midiInputDevice->onMessage(msg); } RtMidiInputDevice::RtMidiInputDevice(int driverId, int deviceId) { rtMidiIn = new RtMidiIn((RtMidi::Api) driverId, "VCV Rack"); assert(rtMidiIn); rtMidiIn->ignoreTypes(false, false, false); rtMidiIn->setCallback(midiInputCallback, this); rtMidiIn->openPort(deviceId, "VCV Rack input"); } RtMidiInputDevice::~RtMidiInputDevice() { rtMidiIn->closePort(); delete rtMidiIn; } RtMidiDriver::RtMidiDriver(int driverId) { this->driverId = driverId; rtMidiIn = new RtMidiIn((RtMidi::Api) driverId); assert(rtMidiIn); rtMidiOut = new RtMidiOut((RtMidi::Api) driverId); assert(rtMidiOut); } RtMidiDriver::~RtMidiDriver() { delete rtMidiIn; delete rtMidiOut; } std::string RtMidiDriver::getName() { switch (driverId) { case RtMidi::UNSPECIFIED: return "Unspecified"; case RtMidi::MACOSX_CORE: return "Core MIDI"; case RtMidi::LINUX_ALSA: return "ALSA"; case RtMidi::UNIX_JACK: return "JACK"; case RtMidi::WINDOWS_MM: return "Windows MIDI"; case RtMidi::RTMIDI_DUMMY: return "Dummy MIDI"; default: return ""; } } std::vector RtMidiDriver::getInputDeviceIds() { // TODO The IDs unfortunately jump around in RtMidi. Is there a way to keep them constant when a MIDI device is added/removed? int count = rtMidiIn->getPortCount(); std::vector deviceIds; for (int i = 0; i < count; i++) deviceIds.push_back(i); return deviceIds; } std::string RtMidiDriver::getInputDeviceName(int deviceId) { if (deviceId >= 0) { return rtMidiIn->getPortName(deviceId); } return ""; } MidiInputDevice *RtMidiDriver::subscribeInputDevice(int deviceId, MidiInput *midiInput) { if (!(0 <= deviceId && deviceId < (int) rtMidiIn->getPortCount())) return NULL; RtMidiInputDevice *device = devices[deviceId]; if (!device) { devices[deviceId] = device = new RtMidiInputDevice(driverId, deviceId); } device->subscribe(midiInput); return device; } void RtMidiDriver::unsubscribeInputDevice(int deviceId, MidiInput *midiInput) { auto it = devices.find(deviceId); if (it == devices.end()) return; RtMidiInputDevice *device = it->second; device->unsubscribe(midiInput); // Destroy device if nothing is subscribed anymore if (device->subscribed.empty()) { devices.erase(it); delete device; } } void rtmidiInit() { std::vector rtApis; RtMidi::getCompiledApi(rtApis); for (RtMidi::Api api : rtApis) { int driverId = (int) api; MidiDriver *driver = new RtMidiDriver(driverId); midiDriverAdd(driverId, driver); } } } // namespace rack