@@ -7,12 +7,26 @@ | |||||
namespace rack { | namespace rack { | ||||
struct BridgeMidiInputDevice : MidiInputDevice { | |||||
}; | |||||
struct BridgeMidiDriver : MidiDriver { | |||||
BridgeMidiInputDevice devices[16]; | |||||
std::string getName() override {return "Bridge";} | |||||
std::vector<int> 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 bridgeInit(); | ||||
void bridgeDestroy(); | void bridgeDestroy(); | ||||
void bridgeMidiSubscribe(int channel, MidiInput *midi); | |||||
void bridgeMidiUnsubscribe(int channel, MidiInput *midi); | |||||
void bridgeAudioSubscribe(int channel, AudioIO *audio); | void bridgeAudioSubscribe(int channel, AudioIO *audio); | ||||
void bridgeAudioUnsubscribe(int channel, AudioIO *audio); | void bridgeAudioUnsubscribe(int channel, AudioIO *audio); | ||||
BridgeMidiDriver *bridgeGetMidiDriver(); | |||||
} // namespace rack | } // namespace rack |
@@ -18,18 +18,20 @@ struct GamepadInputDevice : MidiInputDevice { | |||||
}; | }; | ||||
struct GamepadInputDriver : MidiInputDriver { | |||||
struct GamepadDriver : MidiDriver { | |||||
GamepadInputDevice devices[16]; | GamepadInputDevice devices[16]; | ||||
GamepadInputDriver(); | |||||
std::vector<int> getDeviceIds() override; | |||||
std::string getDeviceName(int deviceId) override; | |||||
MidiInputDevice *getDevice(int deviceId) override; | |||||
GamepadDriver(); | |||||
std::string getName() override {return "Gamepad";} | |||||
std::vector<int> getInputDeviceIds() override; | |||||
std::string getInputDeviceName(int deviceId) override; | |||||
MidiInputDevice *subscribeInputDevice(int deviceId, MidiInput *midiInput) override; | |||||
void unsubscribeInputDevice(int deviceId, MidiInput *midiInput) override; | |||||
}; | }; | ||||
void gamepadStep(); | void gamepadStep(); | ||||
MidiInputDriver *gamepadGetInputDriver(); | |||||
GamepadDriver *gamepadGetDriver(); | |||||
} // namespace rack | } // namespace rack |
@@ -16,18 +16,20 @@ struct KeyboardInputDevice : MidiInputDevice { | |||||
}; | }; | ||||
struct KeyboardInputDriver : MidiInputDriver { | |||||
struct KeyboardDriver : MidiDriver { | |||||
KeyboardInputDevice device; | KeyboardInputDevice device; | ||||
std::string getName() override {return "Computer keyboard";} | |||||
std::vector<int> getDeviceIds() override; | |||||
std::string getDeviceName(int deviceId) override; | |||||
MidiInputDevice *getDevice(int deviceId) override; | |||||
std::vector<int> 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 keyboardPress(int key); | ||||
void keyboardRelease(int key); | void keyboardRelease(int key); | ||||
KeyboardInputDriver *keyboardGetInputDriver(); | |||||
KeyboardDriver *keyboardGetDriver(); | |||||
} // namespace rack | } // namespace rack |
@@ -30,42 +30,43 @@ struct MidiMessage { | |||||
}; | }; | ||||
//////////////////// | //////////////////// | ||||
// MidiIODevice | |||||
// MidiDevice | |||||
//////////////////// | //////////////////// | ||||
struct MidiIODevice { | |||||
virtual ~MidiIODevice() {} | |||||
struct MidiDevice { | |||||
virtual ~MidiDevice() {} | |||||
}; | }; | ||||
struct MidiInput; | struct MidiInput; | ||||
struct MidiInputDevice : MidiIODevice { | |||||
struct MidiInputDevice : MidiDevice { | |||||
std::set<MidiInput*> subscribed; | std::set<MidiInput*> subscribed; | ||||
void subscribe(MidiInput *midiInput); | void subscribe(MidiInput *midiInput); | ||||
void unsubscribe(MidiInput *midiInput); | void unsubscribe(MidiInput *midiInput); | ||||
void onMessage(MidiMessage message); | void onMessage(MidiMessage message); | ||||
}; | }; | ||||
struct MidiOutputDevice : MidiIODevice { | |||||
struct MidiOutputDevice : MidiDevice { | |||||
// TODO | // TODO | ||||
}; | }; | ||||
//////////////////// | //////////////////// | ||||
// MidiIODriver | |||||
// MidiDriver | |||||
//////////////////// | //////////////////// | ||||
struct MidiIODriver { | |||||
virtual ~MidiIODriver() {} | |||||
virtual std::vector<int> 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<int> 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<int> 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. | Zero indexed. | ||||
*/ | */ | ||||
int channel = -1; | int channel = -1; | ||||
/** Not owned */ | |||||
MidiDriver *driver = NULL; | |||||
virtual ~MidiIO() {} | |||||
virtual ~MidiIO(); | |||||
std::vector<int> getDriverIds(); | std::vector<int> getDriverIds(); | ||||
std::string getDriverName(int driverId); | std::string getDriverName(int driverId); | ||||
virtual void setDriverId(int driverId) = 0; | |||||
void setDriverId(int driverId); | |||||
virtual std::vector<int> getDeviceIds() = 0; | virtual std::vector<int> getDeviceIds() = 0; | ||||
virtual std::string getDeviceName(int deviceId) = 0; | virtual std::string getDeviceName(int deviceId) = 0; | ||||
@@ -99,26 +102,17 @@ struct MidiIO { | |||||
struct MidiInput : MidiIO { | struct MidiInput : MidiIO { | ||||
/** Not owned */ | |||||
MidiInputDriver *driver = NULL; | |||||
/** Not owned, must unsubscribe when destructed */ | |||||
MidiInputDevice *device = NULL; | |||||
MidiInput(); | |||||
~MidiInput(); | ~MidiInput(); | ||||
void setDriverId(int driverId) override; | |||||
std::vector<int> getDeviceIds() override; | std::vector<int> getDeviceIds() override; | ||||
std::string getDeviceName(int deviceId) override; | std::string getDeviceName(int deviceId) override; | ||||
void setDeviceId(int deviceId) override; | void setDeviceId(int deviceId) override; | ||||
virtual void onMessage(MidiMessage message) {} | virtual void onMessage(MidiMessage message) {} | ||||
}; | }; | ||||
struct MidiInputQueue : MidiInput { | struct MidiInputQueue : MidiInput { | ||||
int queueSize = 8192; | |||||
// TODO Switch to RingBuffer | |||||
int queueMaxSize = 8192; | |||||
std::queue<MidiMessage> queue; | std::queue<MidiMessage> queue; | ||||
void onMessage(MidiMessage message) override; | void onMessage(MidiMessage message) override; | ||||
/** If a MidiMessage is available, writes `message` and return true */ | /** If a MidiMessage is available, writes `message` and return true */ | ||||
@@ -127,15 +121,13 @@ struct MidiInputQueue : MidiInput { | |||||
struct MidiOutput : MidiIO { | struct MidiOutput : MidiIO { | ||||
/** Not owned */ | |||||
MidiOutputDriver *driver = NULL; | |||||
/** Not owned, must unsubscribe when destructed */ | |||||
MidiOutputDevice *device = NULL; | |||||
MidiOutput(); | MidiOutput(); | ||||
~MidiOutput(); | ~MidiOutput(); | ||||
void setDriverId(int driverId) override; | |||||
void setDeviceId(int deviceId) override; | void setDeviceId(int deviceId) override; | ||||
}; | }; | ||||
void midiInit(); | |||||
} // namespace rack | } // namespace rack |
@@ -2,6 +2,7 @@ | |||||
#include "util/common.hpp" | #include "util/common.hpp" | ||||
#include "midi.hpp" | #include "midi.hpp" | ||||
#include <map> | |||||
#pragma GCC diagnostic push | #pragma GCC diagnostic push | ||||
#ifndef __clang__ | #ifndef __clang__ | ||||
@@ -14,30 +15,33 @@ | |||||
namespace rack { | namespace rack { | ||||
struct RtMidiInputDriver : MidiInputDriver { | |||||
/** Just for querying MIDI driver information */ | |||||
struct RtMidiInputDevice : MidiInputDevice { | |||||
RtMidiIn *rtMidiIn; | RtMidiIn *rtMidiIn; | ||||
RtMidiInputDriver(int driverId); | |||||
~RtMidiInputDriver(); | |||||
std::vector<int> 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; | RtMidiIn *rtMidiIn; | ||||
/** Cached */ | |||||
std::string deviceName; | |||||
RtMidiInputDevice(int driverId, int deviceId); | |||||
~RtMidiInputDevice(); | |||||
RtMidiOut *rtMidiOut; | |||||
std::map<int, RtMidiInputDevice*> devices; | |||||
RtMidiDriver(int driverId); | |||||
~RtMidiDriver(); | |||||
std::string getName() override; | |||||
std::vector<int> getInputDeviceIds() override; | |||||
std::string getInputDeviceName(int deviceId) override; | |||||
MidiInputDevice *subscribeInputDevice(int deviceId, MidiInput *midiInput) override; | |||||
void unsubscribeInputDevice(int deviceId, MidiInput *midiInput) override; | |||||
}; | }; | ||||
std::vector<int> rtmidiGetDrivers(); | std::vector<int> rtmidiGetDrivers(); | ||||
MidiInputDriver *rtmidiGetInputDriver(int driverId); | |||||
RtMidiDriver *rtmidiCreateDriver(int driverId); | |||||
} // namespace rack | } // namespace rack |
@@ -23,9 +23,9 @@ namespace rack { | |||||
struct BridgeClientConnection; | struct BridgeClientConnection; | ||||
static BridgeClientConnection *connections[BRIDGE_NUM_PORTS] = {}; | static BridgeClientConnection *connections[BRIDGE_NUM_PORTS] = {}; | ||||
static AudioIO *audioListeners[BRIDGE_NUM_PORTS] = {}; | static AudioIO *audioListeners[BRIDGE_NUM_PORTS] = {}; | ||||
static MidiInput *midiListeners[BRIDGE_NUM_PORTS] = {}; | |||||
static std::thread serverThread; | static std::thread serverThread; | ||||
static bool serverRunning = false; | static bool serverRunning = false; | ||||
static BridgeMidiDriver driver; | |||||
struct BridgeClientConnection { | struct BridgeClientConnection { | ||||
@@ -206,9 +206,7 @@ struct BridgeClientConnection { | |||||
void processMidi(MidiMessage message) { | void processMidi(MidiMessage message) { | ||||
if (!(0 <= port && port < BRIDGE_NUM_PORTS)) | if (!(0 <= port && port < BRIDGE_NUM_PORTS)) | ||||
return; | return; | ||||
if (!midiListeners[port]) | |||||
return; | |||||
midiListeners[port]->onMessage(message); | |||||
driver.devices[port].onMessage(message); | |||||
} | } | ||||
void setSampleRate(int sampleRate) { | void setSampleRate(int sampleRate) { | ||||
@@ -372,6 +370,35 @@ static void serverRun() { | |||||
} | } | ||||
} | } | ||||
std::vector<int> BridgeMidiDriver::getInputDeviceIds() { | |||||
std::vector<int> 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() { | void bridgeInit() { | ||||
serverRunning = true; | serverRunning = true; | ||||
serverThread = std::thread(serverRun); | serverThread = std::thread(serverRun); | ||||
@@ -382,23 +409,6 @@ void bridgeDestroy() { | |||||
serverThread.join(); | 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) { | void bridgeAudioSubscribe(int port, AudioIO *audio) { | ||||
if (!(0 <= port && port < BRIDGE_NUM_PORTS)) | if (!(0 <= port && port < BRIDGE_NUM_PORTS)) | ||||
return; | return; | ||||
@@ -418,5 +428,9 @@ void bridgeAudioUnsubscribe(int port, AudioIO *audio) { | |||||
audioListeners[port] = NULL; | audioListeners[port] = NULL; | ||||
} | } | ||||
BridgeMidiDriver *bridgeGetMidiDriver() { | |||||
return &driver; | |||||
} | |||||
} // namespace rack | } // namespace rack |
@@ -49,13 +49,13 @@ void GamepadInputDevice::step() { | |||||
} | } | ||||
GamepadInputDriver::GamepadInputDriver() { | |||||
GamepadDriver::GamepadDriver() { | |||||
for (int i = 0; i < 16; i++) { | for (int i = 0; i < 16; i++) { | ||||
devices[i].deviceId = i; | devices[i].deviceId = i; | ||||
} | } | ||||
} | } | ||||
std::vector<int> GamepadInputDriver::getDeviceIds() { | |||||
std::vector<int> GamepadDriver::getInputDeviceIds() { | |||||
std::vector<int> deviceIds; | std::vector<int> deviceIds; | ||||
for (int i = 0; i < 16; i++) { | for (int i = 0; i < 16; i++) { | ||||
if (glfwJoystickPresent(i)) { | if (glfwJoystickPresent(i)) { | ||||
@@ -65,7 +65,7 @@ std::vector<int> GamepadInputDriver::getDeviceIds() { | |||||
return deviceIds; | return deviceIds; | ||||
} | } | ||||
std::string GamepadInputDriver::getDeviceName(int deviceId) { | |||||
std::string GamepadDriver::getInputDeviceName(int deviceId) { | |||||
if (!(0 <= deviceId && deviceId < 16)) | if (!(0 <= deviceId && deviceId < 16)) | ||||
return ""; | return ""; | ||||
@@ -76,34 +76,35 @@ std::string GamepadInputDriver::getDeviceName(int deviceId) { | |||||
return stringf("Gamepad %d (unavailable)", deviceId + 1); | return stringf("Gamepad %d (unavailable)", deviceId + 1); | ||||
} | } | ||||
MidiInputDevice *GamepadInputDriver::getDevice(int deviceId) { | |||||
MidiInputDevice *GamepadDriver::subscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||||
if (!(0 <= deviceId && deviceId < 16)) | if (!(0 <= deviceId && deviceId < 16)) | ||||
return NULL; | return NULL; | ||||
devices[deviceId].subscribe(midiInput); | |||||
return &devices[deviceId]; | 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++) { | for (int i = 0; i < 16; i++) { | ||||
if (glfwJoystickPresent(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; | |||||
} | } | ||||
@@ -74,41 +74,44 @@ void KeyboardInputDevice::processKey(int key, bool released) { | |||||
} | } | ||||
std::vector<int> KeyboardInputDriver::getDeviceIds() { | |||||
std::vector<int> KeyboardDriver::getInputDeviceIds() { | |||||
return {0}; | return {0}; | ||||
} | } | ||||
std::string KeyboardInputDriver::getDeviceName(int deviceId) { | |||||
std::string KeyboardDriver::getInputDeviceName(int deviceId) { | |||||
if (deviceId == 0) | if (deviceId == 0) | ||||
return "QWERTY keyboard (US)"; | return "QWERTY keyboard (US)"; | ||||
return ""; | return ""; | ||||
} | } | ||||
MidiInputDevice *KeyboardInputDriver::getDevice(int deviceId) { | |||||
MidiInputDevice *KeyboardDriver::subscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||||
if (deviceId != 0) | |||||
return NULL; | |||||
device.subscribe(midiInput); | |||||
return &device; | 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) { | void keyboardPress(int key) { | ||||
if (!driver) | |||||
return; | |||||
driver->device.processKey(key, false); | |||||
driver.device.processKey(key, false); | |||||
} | } | ||||
void keyboardRelease(int key) { | 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; | |||||
} | } | ||||
@@ -6,6 +6,7 @@ | |||||
#include "settings.hpp" | #include "settings.hpp" | ||||
#include "asset.hpp" | #include "asset.hpp" | ||||
#include "bridge.hpp" | #include "bridge.hpp" | ||||
#include "midi.hpp" | |||||
#include "osdialog.h" | #include "osdialog.h" | ||||
#include <unistd.h> | #include <unistd.h> | ||||
@@ -36,6 +37,7 @@ int main(int argc, char* argv[]) { | |||||
pluginInit(); | pluginInit(); | ||||
engineInit(); | engineInit(); | ||||
midiInit(); | |||||
bridgeInit(); | bridgeInit(); | ||||
windowInit(); | windowInit(); | ||||
appInit(); | appInit(); | ||||
@@ -8,8 +8,11 @@ | |||||
namespace rack { | namespace rack { | ||||
static std::map<int, MidiDriver*> drivers; | |||||
//////////////////// | //////////////////// | ||||
// MidiIODevice | |||||
// MidiDevice | |||||
//////////////////// | //////////////////// | ||||
void MidiInputDevice::subscribe(MidiInput *midiInput) { | void MidiInputDevice::subscribe(MidiInput *midiInput) { | ||||
@@ -17,13 +20,10 @@ void MidiInputDevice::subscribe(MidiInput *midiInput) { | |||||
} | } | ||||
void MidiInputDevice::unsubscribe(MidiInput *midiInput) { | void MidiInputDevice::unsubscribe(MidiInput *midiInput) { | ||||
// Remove MidiInput from subscriptions | |||||
auto it = subscribed.find(midiInput); | auto it = subscribed.find(midiInput); | ||||
if (it != subscribed.end()) | if (it != subscribed.end()) | ||||
subscribed.erase(it); | subscribed.erase(it); | ||||
if (subscribed.size() == 0) { | |||||
warn("TODO: Fix memory leak"); | |||||
} | |||||
} | } | ||||
void MidiInputDevice::onMessage(MidiMessage message) { | 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::~MidiIO() { | |||||
// Because of polymorphic destruction, descendants must call this in their own destructor | |||||
// setDriverId(-1); | |||||
} | |||||
std::vector<int> MidiIO::getDriverIds() { | std::vector<int> MidiIO::getDriverIds() { | ||||
std::vector<int> driverIds = rtmidiGetDrivers(); | |||||
// Add custom driverIds | |||||
driverIds.push_back(BRIDGE_DRIVER); | |||||
driverIds.push_back(GAMEPAD_DRIVER); | |||||
driverIds.push_back(KEYBOARD_DRIVER); | |||||
std::vector<int> driverIds; | |||||
for (auto pair : drivers) { | |||||
driverIds.push_back(pair.first); | |||||
} | |||||
return driverIds; | return driverIds; | ||||
} | } | ||||
std::string MidiIO::getDriverName(int driverId) { | 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::~MidiInput() { | MidiInput::~MidiInput() { | ||||
setDriverId(-1); | 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<int> MidiInput::getDeviceIds() { | std::vector<int> MidiInput::getDeviceIds() { | ||||
if (driver) { | if (driver) { | ||||
return driver->getDeviceIds(); | |||||
return driver->getInputDeviceIds(); | |||||
} | } | ||||
return {}; | return {}; | ||||
} | } | ||||
std::string MidiInput::getDeviceName(int deviceId) { | std::string MidiInput::getDeviceName(int deviceId) { | ||||
if (driver) { | if (driver) { | ||||
return driver->getDeviceName(deviceId); | |||||
return driver->getInputDeviceName(deviceId); | |||||
} | } | ||||
return ""; | return ""; | ||||
} | } | ||||
void MidiInput::setDeviceId(int deviceId) { | void MidiInput::setDeviceId(int deviceId) { | ||||
// Destroy device | // Destroy device | ||||
if (device) { | |||||
device->unsubscribe(this); | |||||
device = NULL; | |||||
if (driver && deviceId >= 0) { | |||||
driver->unsubscribeInputDevice(deviceId, this); | |||||
} | } | ||||
this->deviceId = -1; | this->deviceId = -1; | ||||
// Create device | // Create device | ||||
if (driver && deviceId >= 0) { | if (driver && deviceId >= 0) { | ||||
device = driver->getDevice(deviceId); | |||||
device->subscribe(this); | |||||
} | |||||
// Set deviceId | |||||
if (device) { | |||||
driver->subscribeInputDevice(deviceId, this); | |||||
this->deviceId = deviceId; | this->deviceId = deviceId; | ||||
} | } | ||||
} | } | ||||
@@ -187,12 +161,13 @@ void MidiInputQueue::onMessage(MidiMessage message) { | |||||
} | } | ||||
// Push to queue | // Push to queue | ||||
if ((int) queue.size() < queueSize) | |||||
if ((int) queue.size() < queueMaxSize) | |||||
queue.push(message); | queue.push(message); | ||||
} | } | ||||
bool MidiInputQueue::shift(MidiMessage *message) { | bool MidiInputQueue::shift(MidiMessage *message) { | ||||
if (!message) return false; | |||||
if (!message) | |||||
return false; | |||||
if (!queue.empty()) { | if (!queue.empty()) { | ||||
*message = queue.front(); | *message = queue.front(); | ||||
queue.pop(); | queue.pop(); | ||||
@@ -201,7 +176,6 @@ bool MidiInputQueue::shift(MidiMessage *message) { | |||||
return false; | return false; | ||||
} | } | ||||
//////////////////// | //////////////////// | ||||
// MidiOutput | // MidiOutput | ||||
//////////////////// | //////////////////// | ||||
@@ -210,15 +184,24 @@ MidiOutput::MidiOutput() { | |||||
} | } | ||||
MidiOutput::~MidiOutput() { | MidiOutput::~MidiOutput() { | ||||
// TODO | |||||
setDriverId(-1); | |||||
} | } | ||||
void MidiOutput::setDriverId(int driverId) { | |||||
void MidiOutput::setDeviceId(int deviceId) { | |||||
// TODO | // 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(); | |||||
} | } | ||||
@@ -5,36 +5,6 @@ | |||||
namespace rack { | namespace rack { | ||||
RtMidiInputDriver::RtMidiInputDriver(int driverId) { | |||||
rtMidiIn = new RtMidiIn((RtMidi::Api) driverId); | |||||
assert(rtMidiIn); | |||||
} | |||||
RtMidiInputDriver::~RtMidiInputDriver() { | |||||
delete rtMidiIn; | |||||
} | |||||
std::vector<int> RtMidiInputDriver::getDeviceIds() { | |||||
int count = rtMidiIn->getPortCount();; | |||||
std::vector<int> 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<unsigned char> *message, void *userData) { | static void midiInputCallback(double timeStamp, std::vector<unsigned char> *message, void *userData) { | ||||
if (!message) return; | if (!message) return; | ||||
if (!userData) return; | if (!userData) return; | ||||
@@ -54,6 +24,7 @@ static void midiInputCallback(double timeStamp, std::vector<unsigned char> *mess | |||||
RtMidiInputDevice::RtMidiInputDevice(int driverId, int deviceId) { | RtMidiInputDevice::RtMidiInputDevice(int driverId, int deviceId) { | ||||
rtMidiIn = new RtMidiIn((RtMidi::Api) driverId, "VCV Rack"); | rtMidiIn = new RtMidiIn((RtMidi::Api) driverId, "VCV Rack"); | ||||
assert(rtMidiIn); | |||||
rtMidiIn->ignoreTypes(false, false, false); | rtMidiIn->ignoreTypes(false, false, false); | ||||
rtMidiIn->setCallback(midiInputCallback, this); | 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<int> 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<int> 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<int> rtmidiGetDrivers() { | std::vector<int> rtmidiGetDrivers() { | ||||
std::vector<RtMidi::Api> rtApis; | std::vector<RtMidi::Api> rtApis; | ||||
RtMidi::getCompiledApi(rtApis); | RtMidi::getCompiledApi(rtApis); | ||||
@@ -75,15 +112,8 @@ std::vector<int> rtmidiGetDrivers() { | |||||
return drivers; | return drivers; | ||||
} | } | ||||
static std::map<int, RtMidiInputDriver*> 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); | |||||
} | } | ||||