From ba275e31e5746032624e8fa0da2d419d9edc4b3a Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Fri, 18 May 2018 18:02:19 -0400 Subject: [PATCH] Massive refactor to MIDI API, re-enable Bridge --- include/bridge.hpp | 18 +++++- include/gamepad.hpp | 14 +++-- include/keyboard.hpp | 12 ++-- include/midi.hpp | 58 +++++++++---------- include/rtmidi.hpp | 32 ++++++----- src/bridge.cpp | 56 ++++++++++++------- src/gamepad.cpp | 31 ++++++----- src/keyboard.cpp | 35 ++++++------ src/main.cpp | 2 + src/midi.cpp | 129 +++++++++++++++++++------------------------ src/rtmidi.cpp | 108 +++++++++++++++++++++++------------- 11 files changed, 271 insertions(+), 224 deletions(-) diff --git a/include/bridge.hpp b/include/bridge.hpp index 28dfbc06..ec333446 100644 --- a/include/bridge.hpp +++ b/include/bridge.hpp @@ -7,12 +7,26 @@ namespace rack { +struct BridgeMidiInputDevice : MidiInputDevice { +}; + + +struct BridgeMidiDriver : MidiDriver { + BridgeMidiInputDevice devices[16]; + std::string getName() override {return "Bridge";} + + std::vector getInputDeviceIds() override; + std::string getInputDeviceName(int deviceId) override; + MidiInputDevice *subscribeInputDevice(int deviceId, MidiInput *midiInput) override; + void unsubscribeInputDevice(int deviceId, MidiInput *midiInput) override; +}; + + void bridgeInit(); void bridgeDestroy(); -void bridgeMidiSubscribe(int channel, MidiInput *midi); -void bridgeMidiUnsubscribe(int channel, MidiInput *midi); void bridgeAudioSubscribe(int channel, AudioIO *audio); void bridgeAudioUnsubscribe(int channel, AudioIO *audio); +BridgeMidiDriver *bridgeGetMidiDriver(); } // namespace rack diff --git a/include/gamepad.hpp b/include/gamepad.hpp index 21f09303..c618f176 100644 --- a/include/gamepad.hpp +++ b/include/gamepad.hpp @@ -18,18 +18,20 @@ struct GamepadInputDevice : MidiInputDevice { }; -struct GamepadInputDriver : MidiInputDriver { +struct GamepadDriver : MidiDriver { GamepadInputDevice devices[16]; - GamepadInputDriver(); - std::vector getDeviceIds() override; - std::string getDeviceName(int deviceId) override; - MidiInputDevice *getDevice(int deviceId) override; + GamepadDriver(); + std::string getName() override {return "Gamepad";} + std::vector getInputDeviceIds() override; + std::string getInputDeviceName(int deviceId) override; + MidiInputDevice *subscribeInputDevice(int deviceId, MidiInput *midiInput) override; + void unsubscribeInputDevice(int deviceId, MidiInput *midiInput) override; }; void gamepadStep(); -MidiInputDriver *gamepadGetInputDriver(); +GamepadDriver *gamepadGetDriver(); } // namespace rack diff --git a/include/keyboard.hpp b/include/keyboard.hpp index afedc38a..0e84b736 100644 --- a/include/keyboard.hpp +++ b/include/keyboard.hpp @@ -16,18 +16,20 @@ struct KeyboardInputDevice : MidiInputDevice { }; -struct KeyboardInputDriver : MidiInputDriver { +struct KeyboardDriver : MidiDriver { KeyboardInputDevice device; + std::string getName() override {return "Computer keyboard";} - std::vector getDeviceIds() override; - std::string getDeviceName(int deviceId) override; - MidiInputDevice *getDevice(int deviceId) override; + std::vector getInputDeviceIds() override; + std::string getInputDeviceName(int deviceId) override; + MidiInputDevice *subscribeInputDevice(int deviceId, MidiInput *midiInput) override; + void unsubscribeInputDevice(int deviceId, MidiInput *midiInput) override; }; void keyboardPress(int key); void keyboardRelease(int key); -KeyboardInputDriver *keyboardGetInputDriver(); +KeyboardDriver *keyboardGetDriver(); } // namespace rack diff --git a/include/midi.hpp b/include/midi.hpp index 8663dc67..23a20e81 100644 --- a/include/midi.hpp +++ b/include/midi.hpp @@ -30,42 +30,43 @@ struct MidiMessage { }; //////////////////// -// MidiIODevice +// MidiDevice //////////////////// -struct MidiIODevice { - virtual ~MidiIODevice() {} +struct MidiDevice { + virtual ~MidiDevice() {} }; struct MidiInput; -struct MidiInputDevice : MidiIODevice { +struct MidiInputDevice : MidiDevice { std::set subscribed; void subscribe(MidiInput *midiInput); void unsubscribe(MidiInput *midiInput); void onMessage(MidiMessage message); }; -struct MidiOutputDevice : MidiIODevice { +struct MidiOutputDevice : MidiDevice { // TODO }; //////////////////// -// MidiIODriver +// MidiDriver //////////////////// -struct MidiIODriver { - virtual ~MidiIODriver() {} - virtual std::vector getDeviceIds() = 0; - virtual std::string getDeviceName(int deviceId) = 0; -}; +struct MidiDriver { + virtual ~MidiDriver() {} + virtual std::string getName() {return "";} -struct MidiInputDriver : MidiIODriver { - virtual MidiInputDevice *getDevice(int deviceId) = 0; -}; + virtual std::vector getInputDeviceIds() {return {};} + virtual std::string getInputDeviceName(int deviceId) {return "";} + virtual MidiInputDevice *subscribeInputDevice(int deviceId, MidiInput *midiInput) {return NULL;} + virtual void unsubscribeInputDevice(int deviceId, MidiInput *midiInput) {} -struct MidiOutputDriver : MidiIODriver { - virtual MidiOutputDevice *getDevice(int deviceId) = 0; + // virtual std::vector getOutputDeviceIds() = 0; + // virtual std::string getOutputDeviceName(int deviceId) = 0; + // virtual MidiOutputDevice *subscribeOutputDevice(int deviceId, MidiOutput *midiOutput) = 0; + // virtual void unsubscribeOutputDevice(int deviceId, MidiOutput *midiOutput) = 0; }; //////////////////// @@ -81,12 +82,14 @@ struct MidiIO { Zero indexed. */ int channel = -1; + /** Not owned */ + MidiDriver *driver = NULL; - virtual ~MidiIO() {} + virtual ~MidiIO(); std::vector getDriverIds(); std::string getDriverName(int driverId); - virtual void setDriverId(int driverId) = 0; + void setDriverId(int driverId); virtual std::vector getDeviceIds() = 0; virtual std::string getDeviceName(int deviceId) = 0; @@ -99,26 +102,17 @@ struct MidiIO { struct MidiInput : MidiIO { - /** Not owned */ - MidiInputDriver *driver = NULL; - /** Not owned, must unsubscribe when destructed */ - MidiInputDevice *device = NULL; - - MidiInput(); ~MidiInput(); - void setDriverId(int driverId) override; std::vector getDeviceIds() override; std::string getDeviceName(int deviceId) override; void setDeviceId(int deviceId) override; - virtual void onMessage(MidiMessage message) {} }; struct MidiInputQueue : MidiInput { - int queueSize = 8192; - // TODO Switch to RingBuffer + int queueMaxSize = 8192; std::queue queue; void onMessage(MidiMessage message) override; /** If a MidiMessage is available, writes `message` and return true */ @@ -127,15 +121,13 @@ struct MidiInputQueue : MidiInput { struct MidiOutput : MidiIO { - /** Not owned */ - MidiOutputDriver *driver = NULL; - /** Not owned, must unsubscribe when destructed */ - MidiOutputDevice *device = NULL; MidiOutput(); ~MidiOutput(); - void setDriverId(int driverId) override; void setDeviceId(int deviceId) override; }; +void midiInit(); + + } // namespace rack diff --git a/include/rtmidi.hpp b/include/rtmidi.hpp index b765597b..3b9d8489 100644 --- a/include/rtmidi.hpp +++ b/include/rtmidi.hpp @@ -2,6 +2,7 @@ #include "util/common.hpp" #include "midi.hpp" +#include #pragma GCC diagnostic push #ifndef __clang__ @@ -14,30 +15,33 @@ namespace rack { -struct RtMidiInputDriver : MidiInputDriver { - /** Just for querying MIDI driver information */ +struct RtMidiInputDevice : MidiInputDevice { RtMidiIn *rtMidiIn; - RtMidiInputDriver(int driverId); - ~RtMidiInputDriver(); - std::vector getDeviceIds() override; - std::string getDeviceName(int deviceId) override; - MidiInputDevice *getDevice(int deviceId) override; + RtMidiInputDevice(int driverId, int deviceId); + ~RtMidiInputDevice(); }; -struct RtMidiInputDevice : MidiInputDevice { +struct RtMidiDriver : MidiDriver { + int driverId; + /** Just for querying MIDI driver information */ RtMidiIn *rtMidiIn; - /** Cached */ - std::string deviceName; - - RtMidiInputDevice(int driverId, int deviceId); - ~RtMidiInputDevice(); + RtMidiOut *rtMidiOut; + std::map devices; + + RtMidiDriver(int driverId); + ~RtMidiDriver(); + std::string getName() override; + std::vector getInputDeviceIds() override; + std::string getInputDeviceName(int deviceId) override; + MidiInputDevice *subscribeInputDevice(int deviceId, MidiInput *midiInput) override; + void unsubscribeInputDevice(int deviceId, MidiInput *midiInput) override; }; std::vector rtmidiGetDrivers(); -MidiInputDriver *rtmidiGetInputDriver(int driverId); +RtMidiDriver *rtmidiCreateDriver(int driverId); } // namespace rack diff --git a/src/bridge.cpp b/src/bridge.cpp index 50327c04..8c979751 100644 --- a/src/bridge.cpp +++ b/src/bridge.cpp @@ -23,9 +23,9 @@ namespace rack { struct BridgeClientConnection; static BridgeClientConnection *connections[BRIDGE_NUM_PORTS] = {}; static AudioIO *audioListeners[BRIDGE_NUM_PORTS] = {}; -static MidiInput *midiListeners[BRIDGE_NUM_PORTS] = {}; static std::thread serverThread; static bool serverRunning = false; +static BridgeMidiDriver driver; struct BridgeClientConnection { @@ -206,9 +206,7 @@ struct BridgeClientConnection { void processMidi(MidiMessage message) { if (!(0 <= port && port < BRIDGE_NUM_PORTS)) return; - if (!midiListeners[port]) - return; - midiListeners[port]->onMessage(message); + driver.devices[port].onMessage(message); } void setSampleRate(int sampleRate) { @@ -372,6 +370,35 @@ static void serverRun() { } } + +std::vector BridgeMidiDriver::getInputDeviceIds() { + std::vector deviceIds; + for (int i = 0; i < 16; i++) { + deviceIds.push_back(i); + } + return deviceIds; +} + +std::string BridgeMidiDriver::getInputDeviceName(int deviceId) { + return stringf("Port %d", deviceId + 1); +} + +MidiInputDevice *BridgeMidiDriver::subscribeInputDevice(int deviceId, MidiInput *midiInput) { + if (!(0 <= deviceId && deviceId < 16)) + return NULL; + + devices[deviceId].subscribe(midiInput); + return &devices[deviceId]; +} + +void BridgeMidiDriver::unsubscribeInputDevice(int deviceId, MidiInput *midiInput) { + if (!(0 <= deviceId && deviceId < 16)) + return; + + devices[deviceId].unsubscribe(midiInput); +} + + void bridgeInit() { serverRunning = true; serverThread = std::thread(serverRun); @@ -382,23 +409,6 @@ void bridgeDestroy() { serverThread.join(); } -void bridgeMidiSubscribe(int port, MidiInput *midi) { - if (!(0 <= port && port < BRIDGE_NUM_PORTS)) - return; - // Check if a Midi is already subscribed on the port - if (midiListeners[port]) - return; - midiListeners[port] = midi; -} - -void bridgeMidiUnsubscribe(int port, MidiInput *midi) { - if (!(0 <= port && port < BRIDGE_NUM_PORTS)) - return; - if (midiListeners[port] != midi) - return; - midiListeners[port] = NULL; -} - void bridgeAudioSubscribe(int port, AudioIO *audio) { if (!(0 <= port && port < BRIDGE_NUM_PORTS)) return; @@ -418,5 +428,9 @@ void bridgeAudioUnsubscribe(int port, AudioIO *audio) { audioListeners[port] = NULL; } +BridgeMidiDriver *bridgeGetMidiDriver() { + return &driver; +} + } // namespace rack diff --git a/src/gamepad.cpp b/src/gamepad.cpp index 43b771cc..420e8303 100644 --- a/src/gamepad.cpp +++ b/src/gamepad.cpp @@ -49,13 +49,13 @@ void GamepadInputDevice::step() { } -GamepadInputDriver::GamepadInputDriver() { +GamepadDriver::GamepadDriver() { for (int i = 0; i < 16; i++) { devices[i].deviceId = i; } } -std::vector GamepadInputDriver::getDeviceIds() { +std::vector GamepadDriver::getInputDeviceIds() { std::vector deviceIds; for (int i = 0; i < 16; i++) { if (glfwJoystickPresent(i)) { @@ -65,7 +65,7 @@ std::vector GamepadInputDriver::getDeviceIds() { return deviceIds; } -std::string GamepadInputDriver::getDeviceName(int deviceId) { +std::string GamepadDriver::getInputDeviceName(int deviceId) { if (!(0 <= deviceId && deviceId < 16)) return ""; @@ -76,34 +76,35 @@ std::string GamepadInputDriver::getDeviceName(int deviceId) { return stringf("Gamepad %d (unavailable)", deviceId + 1); } -MidiInputDevice *GamepadInputDriver::getDevice(int deviceId) { +MidiInputDevice *GamepadDriver::subscribeInputDevice(int deviceId, MidiInput *midiInput) { if (!(0 <= deviceId && deviceId < 16)) return NULL; + devices[deviceId].subscribe(midiInput); return &devices[deviceId]; } +void GamepadDriver::unsubscribeInputDevice(int deviceId, MidiInput *midiInput) { + if (!(0 <= deviceId && deviceId < 16)) + return; -static GamepadInputDriver *driver = NULL; + devices[deviceId].unsubscribe(midiInput); +} -void gamepadStep() { - // Check if the driver has been instantiated - if (!driver) - return; +static GamepadDriver driver; + +void gamepadStep() { for (int i = 0; i < 16; i++) { if (glfwJoystickPresent(i)) { - driver->devices[i].step(); + driver.devices[i].step(); } } } -MidiInputDriver *gamepadGetInputDriver() { - if (!driver) { - driver = new GamepadInputDriver(); - } - return driver; +GamepadDriver *gamepadGetDriver() { + return &driver; } diff --git a/src/keyboard.cpp b/src/keyboard.cpp index 4240d850..61c5608a 100644 --- a/src/keyboard.cpp +++ b/src/keyboard.cpp @@ -74,41 +74,44 @@ void KeyboardInputDevice::processKey(int key, bool released) { } -std::vector KeyboardInputDriver::getDeviceIds() { +std::vector KeyboardDriver::getInputDeviceIds() { return {0}; } -std::string KeyboardInputDriver::getDeviceName(int deviceId) { +std::string KeyboardDriver::getInputDeviceName(int deviceId) { if (deviceId == 0) return "QWERTY keyboard (US)"; return ""; } -MidiInputDevice *KeyboardInputDriver::getDevice(int deviceId) { +MidiInputDevice *KeyboardDriver::subscribeInputDevice(int deviceId, MidiInput *midiInput) { + if (deviceId != 0) + return NULL; + + device.subscribe(midiInput); return &device; } +void KeyboardDriver::unsubscribeInputDevice(int deviceId, MidiInput *midiInput) { + if (deviceId != 0) + return; + + device.unsubscribe(midiInput); +} + -static KeyboardInputDriver *driver = NULL; +static KeyboardDriver driver; void keyboardPress(int key) { - if (!driver) - return; - driver->device.processKey(key, false); + driver.device.processKey(key, false); } void keyboardRelease(int key) { - if (!driver) - return; - driver->device.processKey(key, true); + driver.device.processKey(key, true); } -KeyboardInputDriver *keyboardGetInputDriver() { - // Lazily create driver - if (!driver) { - driver = new KeyboardInputDriver(); - } - return driver; +KeyboardDriver *keyboardGetDriver() { + return &driver; } diff --git a/src/main.cpp b/src/main.cpp index db99a1b5..dade5432 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,7 @@ #include "settings.hpp" #include "asset.hpp" #include "bridge.hpp" +#include "midi.hpp" #include "osdialog.h" #include @@ -36,6 +37,7 @@ int main(int argc, char* argv[]) { pluginInit(); engineInit(); + midiInit(); bridgeInit(); windowInit(); appInit(); diff --git a/src/midi.cpp b/src/midi.cpp index d3c74b35..a3d27acd 100644 --- a/src/midi.cpp +++ b/src/midi.cpp @@ -8,8 +8,11 @@ namespace rack { +static std::map drivers; + + //////////////////// -// MidiIODevice +// MidiDevice //////////////////// void MidiInputDevice::subscribe(MidiInput *midiInput) { @@ -17,13 +20,10 @@ void MidiInputDevice::subscribe(MidiInput *midiInput) { } void MidiInputDevice::unsubscribe(MidiInput *midiInput) { + // Remove MidiInput from subscriptions auto it = subscribed.find(midiInput); if (it != subscribed.end()) subscribed.erase(it); - - if (subscribed.size() == 0) { - warn("TODO: Fix memory leak"); - } } void MidiInputDevice::onMessage(MidiMessage message) { @@ -33,7 +33,7 @@ void MidiInputDevice::onMessage(MidiMessage message) { } //////////////////// -// MidiIODriver +// MidiDriver //////////////////// @@ -41,28 +41,40 @@ void MidiInputDevice::onMessage(MidiMessage message) { // MidiIO //////////////////// +MidiIO::~MidiIO() { + // Because of polymorphic destruction, descendants must call this in their own destructor + // setDriverId(-1); +} + std::vector MidiIO::getDriverIds() { - std::vector driverIds = rtmidiGetDrivers(); - // Add custom driverIds - driverIds.push_back(BRIDGE_DRIVER); - driverIds.push_back(GAMEPAD_DRIVER); - driverIds.push_back(KEYBOARD_DRIVER); + std::vector driverIds; + for (auto pair : drivers) { + driverIds.push_back(pair.first); + } return driverIds; } std::string MidiIO::getDriverName(int driverId) { - switch (driverId) { - case -1: return "None"; - 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"; - case BRIDGE_DRIVER: return "Bridge"; - case GAMEPAD_DRIVER: return "Gamepad"; - case KEYBOARD_DRIVER: return "Computer keyboard"; - default: return "Unknown"; + MidiDriver *driver = drivers[driverId]; + if (driver) { + return driver->getName(); + } + return ""; +} + +void MidiIO::setDriverId(int driverId) { + // Destroy driver + setDeviceId(-1); + if (driver) { + driver = NULL; + } + this->driverId = -1; + + // Set driver + auto it = drivers.find(driverId); + if (it != drivers.end()) { + driver = it->second; + this->driverId = driverId; } } @@ -109,72 +121,34 @@ void MidiIO::fromJson(json_t *rootJ) { // MidiInput //////////////////// - -MidiInput::MidiInput() { -} - MidiInput::~MidiInput() { setDriverId(-1); } -void MidiInput::setDriverId(int driverId) { - // Destroy driver - setDeviceId(-1); - if (driver) { - driver = NULL; - } - this->driverId = -1; - - // Create driver - if (driverId >= 0) { - driver = rtmidiGetInputDriver(driverId); - } - else if (driverId == BRIDGE_DRIVER) { - // TODO - } - else if (driverId == GAMEPAD_DRIVER) { - driver = gamepadGetInputDriver(); - } - else if (driverId == KEYBOARD_DRIVER) { - driver = keyboardGetInputDriver(); - } - - // Set driverId - if (driver) { - this->driverId = driverId; - } -} - std::vector MidiInput::getDeviceIds() { if (driver) { - return driver->getDeviceIds(); + return driver->getInputDeviceIds(); } return {}; } std::string MidiInput::getDeviceName(int deviceId) { if (driver) { - return driver->getDeviceName(deviceId); + return driver->getInputDeviceName(deviceId); } return ""; } void MidiInput::setDeviceId(int deviceId) { // Destroy device - if (device) { - device->unsubscribe(this); - device = NULL; + if (driver && deviceId >= 0) { + driver->unsubscribeInputDevice(deviceId, this); } this->deviceId = -1; // Create device if (driver && deviceId >= 0) { - device = driver->getDevice(deviceId); - device->subscribe(this); - } - - // Set deviceId - if (device) { + driver->subscribeInputDevice(deviceId, this); this->deviceId = deviceId; } } @@ -187,12 +161,13 @@ void MidiInputQueue::onMessage(MidiMessage message) { } // Push to queue - if ((int) queue.size() < queueSize) + if ((int) queue.size() < queueMaxSize) queue.push(message); } bool MidiInputQueue::shift(MidiMessage *message) { - if (!message) return false; + if (!message) + return false; if (!queue.empty()) { *message = queue.front(); queue.pop(); @@ -201,7 +176,6 @@ bool MidiInputQueue::shift(MidiMessage *message) { return false; } - //////////////////// // MidiOutput //////////////////// @@ -210,15 +184,24 @@ MidiOutput::MidiOutput() { } MidiOutput::~MidiOutput() { - // TODO + setDriverId(-1); } -void MidiOutput::setDriverId(int driverId) { +void MidiOutput::setDeviceId(int deviceId) { // TODO } -void MidiOutput::setDeviceId(int deviceId) { - // TODO +//////////////////// +// midi +//////////////////// + +void midiInit() { + for (int driverId : rtmidiGetDrivers()) { + drivers[driverId] = rtmidiCreateDriver(driverId); + } + // drivers[BRIDGE_DRIVER] = bridgeCreateDriver(); + drivers[GAMEPAD_DRIVER] = gamepadGetDriver(); + drivers[KEYBOARD_DRIVER] = keyboardGetDriver(); } diff --git a/src/rtmidi.cpp b/src/rtmidi.cpp index 74f0be40..6feaaa05 100644 --- a/src/rtmidi.cpp +++ b/src/rtmidi.cpp @@ -5,36 +5,6 @@ namespace rack { -RtMidiInputDriver::RtMidiInputDriver(int driverId) { - rtMidiIn = new RtMidiIn((RtMidi::Api) driverId); - assert(rtMidiIn); -} - -RtMidiInputDriver::~RtMidiInputDriver() { - delete rtMidiIn; -} - -std::vector RtMidiInputDriver::getDeviceIds() { - int count = rtMidiIn->getPortCount();; - std::vector deviceIds; - for (int i = 0; i < count; i++) - deviceIds.push_back(i); - return deviceIds; -} - -std::string RtMidiInputDriver::getDeviceName(int deviceId) { - if (deviceId >= 0) { - return rtMidiIn->getPortName(deviceId); - } - return ""; -} - -MidiInputDevice *RtMidiInputDriver::getDevice(int deviceId) { - // TODO Get from cache - return new RtMidiInputDevice(rtMidiIn->getCurrentApi(), deviceId); -} - - static void midiInputCallback(double timeStamp, std::vector *message, void *userData) { if (!message) return; if (!userData) return; @@ -54,6 +24,7 @@ static void midiInputCallback(double timeStamp, std::vector *mess 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); } @@ -64,6 +35,72 @@ RtMidiInputDevice::~RtMidiInputDevice() { } +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) { + 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) { + RtMidiInputDevice *device = devices[deviceId]; + assert(device); + device->unsubscribe(midiInput); + + // Destroy device if nothing else is subscribed + if (device->subscribed.empty()) { + auto it = devices.find(deviceId); + assert(it != devices.end()); + devices.erase(it); + delete device; + } +} + + std::vector rtmidiGetDrivers() { std::vector rtApis; RtMidi::getCompiledApi(rtApis); @@ -75,15 +112,8 @@ std::vector rtmidiGetDrivers() { return drivers; } -static std::map rtmidiInputDrivers; - -MidiInputDriver *rtmidiGetInputDriver(int driverId) { - // Lazily create RtMidiInputDriver - RtMidiInputDriver *d = rtmidiInputDrivers[driverId]; - if (!d) { - rtmidiInputDrivers[driverId] = d = new RtMidiInputDriver(driverId); - } - return d; +RtMidiDriver *rtmidiCreateDriver(int driverId) { + return new RtMidiDriver(driverId); }