From d7186474d32c3c11b2a36afc7cadf6ebccf22619 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 17 Jan 2019 01:35:47 -0500 Subject: [PATCH] Implement midi::Output. Tweak midi API a bit --- include/bridge.hpp | 4 +-- include/gamepad.hpp | 4 +-- include/keyboard.hpp | 4 +-- include/midi.hpp | 66 +++++++++++++++++++++++------------- include/rtmidi.hpp | 4 +-- src/bridge.cpp | 4 +-- src/gamepad.cpp | 4 +-- src/keyboard.cpp | 4 +-- src/midi.cpp | 79 +++++++++++++++++++++++++++++++++----------- src/rtmidi.cpp | 4 +-- 10 files changed, 119 insertions(+), 58 deletions(-) diff --git a/include/bridge.hpp b/include/bridge.hpp index 994876f3..ff363edb 100644 --- a/include/bridge.hpp +++ b/include/bridge.hpp @@ -17,8 +17,8 @@ struct BridgeMidiDriver : midi::Driver { std::vector getInputDeviceIds() override; std::string getInputDeviceName(int deviceId) override; - midi::InputDevice *subscribeInputDevice(int deviceId, midi::Input *input) override; - void unsubscribeInputDevice(int deviceId, midi::Input *input) override; + midi::InputDevice *subscribeInput(int deviceId, midi::Input *input) override; + void unsubscribeInput(int deviceId, midi::Input *input) override; }; diff --git a/include/gamepad.hpp b/include/gamepad.hpp index 2a8b25a3..9a0c1893 100644 --- a/include/gamepad.hpp +++ b/include/gamepad.hpp @@ -22,8 +22,8 @@ struct Driver : midi::Driver { std::string getName() override {return "Gamepad";} std::vector getInputDeviceIds() override; std::string getInputDeviceName(int deviceId) override; - midi::InputDevice *subscribeInputDevice(int deviceId, midi::Input *input) override; - void unsubscribeInputDevice(int deviceId, midi::Input *input) override; + midi::InputDevice *subscribeInput(int deviceId, midi::Input *input) override; + void unsubscribeInput(int deviceId, midi::Input *input) override; }; diff --git a/include/keyboard.hpp b/include/keyboard.hpp index d70f0be2..8e50c49d 100644 --- a/include/keyboard.hpp +++ b/include/keyboard.hpp @@ -22,8 +22,8 @@ struct Driver : midi::Driver { std::vector getInputDeviceIds() override; std::string getInputDeviceName(int deviceId) override; - midi::InputDevice *subscribeInputDevice(int deviceId, midi::Input *input) override; - void unsubscribeInputDevice(int deviceId, midi::Input *input) override; + midi::InputDevice *subscribeInput(int deviceId, midi::Input *input) override; + void unsubscribeInput(int deviceId, midi::Input *input) override; }; diff --git a/include/midi.hpp b/include/midi.hpp index 12be0a75..f8fa8062 100644 --- a/include/midi.hpp +++ b/include/midi.hpp @@ -29,6 +29,30 @@ struct Message { } }; +//////////////////// +// Driver +//////////////////// + +struct InputDevice; +struct Input; +struct OutputDevice; +struct Output; + +struct Driver { + virtual ~Driver() {} + virtual std::string getName() {return "";} + + virtual std::vector getInputDeviceIds() {return {};} + virtual std::string getInputDeviceName(int deviceId) {return "";} + virtual InputDevice *subscribeInput(int deviceId, Input *input) {return NULL;} + virtual void unsubscribeInput(int deviceId, Input *input) {} + + virtual std::vector getOutputDeviceIds() {return {};} + virtual std::string getOutputDeviceName(int deviceId) {return "";} + virtual OutputDevice *subscribeOutput(int deviceId, Output *output) {return NULL;} + virtual void unsubscribeOutput(int deviceId, Output *output) {} +}; + //////////////////// // Device //////////////////// @@ -37,8 +61,6 @@ struct Device { virtual ~Device() {} }; -struct Input; - struct InputDevice : Device { std::set subscribed; void subscribe(Input *input); @@ -47,26 +69,10 @@ struct InputDevice : Device { }; struct OutputDevice : Device { - // TODO -}; - -//////////////////// -// Driver -//////////////////// - -struct Driver { - virtual ~Driver() {} - virtual std::string getName() {return "";} - - virtual std::vector getInputDeviceIds() {return {};} - virtual std::string getInputDeviceName(int deviceId) {return "";} - virtual InputDevice *subscribeInputDevice(int deviceId, Input *input) {return NULL;} - virtual void unsubscribeInputDevice(int deviceId, Input *input) {} - - // virtual std::vector getOutputDeviceIds() = 0; - // virtual std::string getOutputDeviceName(int deviceId) = 0; - // virtual OutputDevice *subscribeOutputDevice(int deviceId, Output *midiOutput) = 0; - // virtual void unsubscribeOutputDevice(int deviceId, Output *midiOutput) = 0; + std::set subscribed; + void subscribe(Output *input); + void unsubscribe(Output *input); + virtual void sendMessage(Message message) {} }; //////////////////// @@ -85,7 +91,8 @@ struct IO { /** Not owned */ Driver *driver = NULL; - virtual ~IO(); + /** Remember to call setDriverId(-1) in subclass destructors. */ + virtual ~IO() {} std::vector getDriverIds(); std::string getDriverName(int driverId); @@ -96,12 +103,17 @@ struct IO { virtual void setDeviceId(int deviceId) = 0; std::string getChannelName(int channel); + void setChannel(int channel); + json_t *toJson(); void fromJson(json_t *rootJ); }; struct Input : IO { + /** Not owned */ + InputDevice *inputDevice = NULL; + Input(); ~Input(); @@ -122,9 +134,17 @@ struct InputQueue : Input { struct Output : IO { + /** Not owned */ + OutputDevice *outputDevice = NULL; + Output(); ~Output(); + + std::vector getDeviceIds() override; + std::string getDeviceName(int deviceId) override; void setDeviceId(int deviceId) override; + + void sendMessage(Message message); }; diff --git a/include/rtmidi.hpp b/include/rtmidi.hpp index b20b6a0e..68f8de97 100644 --- a/include/rtmidi.hpp +++ b/include/rtmidi.hpp @@ -34,8 +34,8 @@ struct RtMidiDriver : midi::Driver { std::string getName() override; std::vector getInputDeviceIds() override; std::string getInputDeviceName(int deviceId) override; - midi::InputDevice *subscribeInputDevice(int deviceId, midi::Input *input) override; - void unsubscribeInputDevice(int deviceId, midi::Input *input) override; + midi::InputDevice *subscribeInput(int deviceId, midi::Input *input) override; + void unsubscribeInput(int deviceId, midi::Input *input) override; }; diff --git a/src/bridge.cpp b/src/bridge.cpp index 2d07c8f8..38d8561e 100644 --- a/src/bridge.cpp +++ b/src/bridge.cpp @@ -386,7 +386,7 @@ std::string BridgeMidiDriver::getInputDeviceName(int deviceId) { return string::f("Port %d", deviceId + 1); } -midi::InputDevice *BridgeMidiDriver::subscribeInputDevice(int deviceId, midi::Input *input) { +midi::InputDevice *BridgeMidiDriver::subscribeInput(int deviceId, midi::Input *input) { if (!(0 <= deviceId && deviceId < 16)) return NULL; @@ -394,7 +394,7 @@ midi::InputDevice *BridgeMidiDriver::subscribeInputDevice(int deviceId, midi::In return &devices[deviceId]; } -void BridgeMidiDriver::unsubscribeInputDevice(int deviceId, midi::Input *input) { +void BridgeMidiDriver::unsubscribeInput(int deviceId, midi::Input *input) { if (!(0 <= deviceId && deviceId < 16)) return; diff --git a/src/gamepad.cpp b/src/gamepad.cpp index 81d8fb33..9ffe470e 100644 --- a/src/gamepad.cpp +++ b/src/gamepad.cpp @@ -82,7 +82,7 @@ std::string Driver::getInputDeviceName(int deviceId) { return string::f(" %d (unavailable)", deviceId + 1); } -midi::InputDevice *Driver::subscribeInputDevice(int deviceId, midi::Input *input) { +midi::InputDevice *Driver::subscribeInput(int deviceId, midi::Input *input) { if (!(0 <= deviceId && deviceId < 16)) return NULL; @@ -90,7 +90,7 @@ midi::InputDevice *Driver::subscribeInputDevice(int deviceId, midi::Input *input return &devices[deviceId]; } -void Driver::unsubscribeInputDevice(int deviceId, midi::Input *input) { +void Driver::unsubscribeInput(int deviceId, midi::Input *input) { if (!(0 <= deviceId && deviceId < 16)) return; diff --git a/src/keyboard.cpp b/src/keyboard.cpp index ba1a9cc3..9a4671fa 100644 --- a/src/keyboard.cpp +++ b/src/keyboard.cpp @@ -103,7 +103,7 @@ std::string Driver::getInputDeviceName(int deviceId) { return ""; } -midi::InputDevice *Driver::subscribeInputDevice(int deviceId, midi::Input *input) { +midi::InputDevice *Driver::subscribeInput(int deviceId, midi::Input *input) { if (deviceId != 0) return NULL; @@ -111,7 +111,7 @@ midi::InputDevice *Driver::subscribeInputDevice(int deviceId, midi::Input *input return &device; } -void Driver::unsubscribeInputDevice(int deviceId, midi::Input *input) { +void Driver::unsubscribeInput(int deviceId, midi::Input *input) { if (deviceId != 0) return; diff --git a/src/midi.cpp b/src/midi.cpp index c7a81b78..18abdf41 100644 --- a/src/midi.cpp +++ b/src/midi.cpp @@ -7,6 +7,7 @@ namespace rack { namespace midi { +/** Preserves the order of IDs */ static std::vector driverIds; static std::map drivers; @@ -28,24 +29,28 @@ void InputDevice::unsubscribe(Input *input) { void InputDevice::onMessage(Message message) { for (Input *input : subscribed) { - input->onMessage(message); + // Filter channel + if (input->channel < 0 || message.status() == 0xf || message.channel() == input->channel) { + input->onMessage(message); + } } } -//////////////////// -// Driver -//////////////////// +void OutputDevice::subscribe(Output *output) { + subscribed.insert(output); +} +void OutputDevice::unsubscribe(Output *output) { + // Remove Output from subscriptions + auto it = subscribed.find(output); + if (it != subscribed.end()) + subscribed.erase(it); +} //////////////////// // IO //////////////////// -IO::~IO() { - // Because of polymorphic destruction, descendants must call this in their own destructor - // setDriverId(-1); -} - std::vector IO::getDriverIds() { return driverIds; } @@ -59,7 +64,7 @@ std::string IO::getDriverName(int driverId) { } void IO::setDriverId(int driverId) { - // Destroy driver + // Unset device and driver setDeviceId(-1); if (driver) { driver = NULL; @@ -81,6 +86,10 @@ std::string IO::getChannelName(int channel) { return string::f("Channel %d", channel + 1); } +void IO::setChannel(int channel) { + this->channel = channel; +} + json_t *IO::toJson() { json_t *rootJ = json_object(); json_object_set_new(rootJ, "driver", json_integer(driverId)); @@ -118,6 +127,7 @@ void IO::fromJson(json_t *rootJ) { //////////////////// Input::Input() { + // Set first driver as default if (driverIds.size() >= 1) { setDriverId(driverIds[0]); } @@ -144,24 +154,19 @@ std::string Input::getDeviceName(int deviceId) { void Input::setDeviceId(int deviceId) { // Destroy device if (driver && this->deviceId >= 0) { - driver->unsubscribeInputDevice(this->deviceId, this); + driver->unsubscribeInput(this->deviceId, this); + inputDevice = NULL; } this->deviceId = -1; // Create device if (driver && deviceId >= 0) { - driver->subscribeInputDevice(deviceId, this); + inputDevice = driver->subscribeInput(deviceId, this); this->deviceId = deviceId; } } void InputQueue::onMessage(Message message) { - // Filter channel - if (channel >= 0) { - if (message.status() != 0xf && message.channel() != channel) - return; - } - // Push to queue if ((int) queue.size() < queueMaxSize) queue.push(message); @@ -183,16 +188,52 @@ bool InputQueue::shift(Message *message) { //////////////////// Output::Output() { + // Set first driver as default + if (driverIds.size() >= 1) { + setDriverId(driverIds[0]); + } } Output::~Output() { setDriverId(-1); } +std::vector Output::getDeviceIds() { + if (driver) { + return driver->getOutputDeviceIds(); + } + return {}; +} + +std::string Output::getDeviceName(int deviceId) { + if (driver) { + return driver->getOutputDeviceName(deviceId); + } + return ""; +} + void Output::setDeviceId(int deviceId) { - // TODO + // Destroy device + if (driver && this->deviceId >= 0) { + driver->unsubscribeOutput(this->deviceId, this); + outputDevice = NULL; + } + this->deviceId = -1; + + // Create device + if (driver && deviceId >= 0) { + outputDevice = driver->subscribeOutput(deviceId, this); + this->deviceId = deviceId; + } } +void Output::sendMessage(Message message) { + if (outputDevice) { + outputDevice->sendMessage(message); + } +} + + //////////////////// // midi //////////////////// diff --git a/src/rtmidi.cpp b/src/rtmidi.cpp index f34e20b9..07c8a705 100644 --- a/src/rtmidi.cpp +++ b/src/rtmidi.cpp @@ -77,7 +77,7 @@ std::string RtMidiDriver::getInputDeviceName(int deviceId) { return ""; } -midi::InputDevice *RtMidiDriver::subscribeInputDevice(int deviceId, midi::Input *input) { +midi::InputDevice *RtMidiDriver::subscribeInput(int deviceId, midi::Input *input) { if (!(0 <= deviceId && deviceId < (int) rtMidiIn->getPortCount())) return NULL; RtMidiInputDevice *device = devices[deviceId]; @@ -89,7 +89,7 @@ midi::InputDevice *RtMidiDriver::subscribeInputDevice(int deviceId, midi::Input return device; } -void RtMidiDriver::unsubscribeInputDevice(int deviceId, midi::Input *input) { +void RtMidiDriver::unsubscribeInput(int deviceId, midi::Input *input) { auto it = devices.find(deviceId); if (it == devices.end()) return;