diff --git a/adapters/standalone.cpp b/adapters/standalone.cpp index 37f21682..cfbcfb47 100644 --- a/adapters/standalone.cpp +++ b/adapters/standalone.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -174,6 +175,7 @@ int main(int argc, char* argv[]) { rtmidiInit(); keyboard::init(); gamepad::init(); + midiloopback::init(); INFO("Initializing plugins"); plugin::init(); INFO("Initializing browser"); @@ -189,6 +191,8 @@ int main(int argc, char* argv[]) { // Initialize context contextSet(new Context); + INFO("Creating MIDI loopback"); + APP->midiLoopbackContext = new midiloopback::Context; INFO("Creating engine"); APP->engine = new engine::Engine; INFO("Creating history state"); diff --git a/include/context.hpp b/include/context.hpp index a090a419..ff843a6f 100644 --- a/include/context.hpp +++ b/include/context.hpp @@ -35,6 +35,11 @@ struct Scene; } // namespace app +namespace midiloopback { +struct Context; +} // namespace midiloopback + + /** Rack instance state */ struct Context { @@ -44,6 +49,7 @@ struct Context { window::Window* window = NULL; history::State* history = NULL; patch::Manager* patch = NULL; + midiloopback::Context* midiLoopbackContext = NULL; ~Context(); }; diff --git a/include/midiloopback.hpp b/include/midiloopback.hpp new file mode 100644 index 00000000..7a474c64 --- /dev/null +++ b/include/midiloopback.hpp @@ -0,0 +1,25 @@ +#pragma once +#include +#include + + +namespace rack { +namespace midiloopback { + + +struct Device; + + +struct Context { + Device* devices[1] = {}; + + Context(); + ~Context(); +}; + + +PRIVATE void init(); + + +} // namespace midiloopback +} // namespace rack diff --git a/src/context.cpp b/src/context.cpp index 95343c02..532bcbd0 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include namespace rack { @@ -38,6 +38,10 @@ Context::~Context() { INFO("Deleting engine"); delete engine; engine = NULL; + + INFO("Deleting MIDI loopback"); + delete midiLoopbackContext; + midiLoopbackContext = NULL; } diff --git a/src/midiloopback.cpp b/src/midiloopback.cpp new file mode 100644 index 00000000..77bfeed3 --- /dev/null +++ b/src/midiloopback.cpp @@ -0,0 +1,103 @@ +#include +#include + + +namespace rack { +namespace midiloopback { + + +static const int DRIVER_ID = -12; + + +struct Device : midi::InputDevice, midi::OutputDevice { + std::string getName() override { + return "Loopback"; + } + + void sendMessage(const midi::Message& message) override { + onMessage(message); + } +}; + + +struct Driver : midi::Driver { + std::string getName() override { + return "Loopback"; + } + + // Input methods + std::vector getInputDeviceIds() override { + return {0}; + } + int getDefaultInputDeviceId() override { + return 0; + } + std::string getInputDeviceName(int deviceId) override { + return getDevice(deviceId)->getName(); + } + midi::InputDevice* subscribeInput(int deviceId, midi::Input* input) override { + midi::InputDevice* inputDevice = getDevice(deviceId); + if (!inputDevice) + return NULL; + inputDevice->subscribe(input); + return inputDevice; + } + void unsubscribeInput(int deviceId, midi::Input* input) override { + midi::InputDevice* inputDevice = getDevice(deviceId); + if (!inputDevice) + return; + inputDevice->unsubscribe(input); + } + + // Output methods + std::vector getOutputDeviceIds() override { + return {0}; + } + int getDefaultOutputDeviceId() override { + return 0; + } + std::string getOutputDeviceName(int deviceId) override { + return getDevice(deviceId)->getName(); + } + midi::OutputDevice* subscribeOutput(int deviceId, midi::Output* output) override { + midi::OutputDevice* outputDevice = getDevice(deviceId); + if (!outputDevice) + return NULL; + outputDevice->subscribe(output); + return outputDevice; + } + void unsubscribeOutput(int deviceId, midi::Output* output) override { + midi::OutputDevice* outputDevice = getDevice(deviceId); + if (!outputDevice) + return; + outputDevice->unsubscribe(output); + } + + // Custom methods + Device* getDevice(int deviceId) { + if (!APP->midiLoopbackContext) + return NULL; + if (deviceId != 0) + return NULL; + return APP->midiLoopbackContext->devices[deviceId]; + } +}; + + +Context::Context() { + devices[0] = new Device; +} + +Context::~Context() { + delete devices[0]; +} + + +void init() { + Driver* driver = new Driver; + midi::addDriver(DRIVER_ID, driver); +} + + +} // namespace midiloopback +} // namespace rack