@@ -16,8 +16,8 @@ namespace audio { | |||
// Driver | |||
//////////////////// | |||
struct Port; | |||
struct Device; | |||
struct Port; | |||
struct Driver { | |||
virtual ~Driver() {} | |||
@@ -95,7 +95,9 @@ struct Device { | |||
//////////////////// | |||
struct Port { | |||
/** The first channel index of the device to process. */ | |||
int offset = 0; | |||
/** Maximum number of channels to process. */ | |||
int maxChannels = 8; | |||
// private | |||
@@ -107,6 +109,7 @@ struct Port { | |||
Port(); | |||
virtual ~Port(); | |||
void reset(); | |||
Driver* getDriver() { | |||
return driver; | |||
@@ -18,6 +18,9 @@ struct Message { | |||
uint8_t size = 3; | |||
uint8_t bytes[3] = {}; | |||
uint8_t getSize() { | |||
return size; | |||
} | |||
void setSize(uint8_t size) { | |||
assert(size <= 3); | |||
this->size = size; | |||
@@ -91,6 +94,9 @@ struct Driver { | |||
struct Device { | |||
virtual ~Device() {} | |||
virtual std::string getName() { | |||
return ""; | |||
} | |||
}; | |||
struct InputDevice : Device { | |||
@@ -112,31 +118,47 @@ struct OutputDevice : Device { | |||
//////////////////// | |||
struct Port { | |||
int driverId = -1; | |||
int deviceId = -1; | |||
/* For MIDI output, the channel to output messages. | |||
For MIDI input, the channel to filter. | |||
Set to -1 to allow all MIDI channels (for input). | |||
Zero indexed. | |||
*/ | |||
int channel = -1; | |||
// private | |||
int driverId = -1; | |||
int deviceId = -1; | |||
/** Not owned */ | |||
Driver* driver = NULL; | |||
Device* device = NULL; | |||
/** Remember to call setDriverId(-1) in subclass destructors. */ | |||
virtual ~Port() {} | |||
Port(); | |||
virtual ~Port(); | |||
std::vector<int> getDriverIds(); | |||
std::string getDriverName(int driverId); | |||
Driver* getDriver() { | |||
return driver; | |||
} | |||
int getDriverId() { | |||
return driverId; | |||
} | |||
void setDriverId(int driverId); | |||
Device* getDevice() { | |||
return device; | |||
} | |||
virtual std::vector<int> getDeviceIds() = 0; | |||
virtual std::string getDeviceName(int deviceId) = 0; | |||
int getDeviceId() { | |||
return deviceId; | |||
} | |||
virtual void setDeviceId(int deviceId) = 0; | |||
virtual std::string getDeviceName(int deviceId) = 0; | |||
virtual std::vector<int> getChannels() = 0; | |||
std::string getChannelName(int channel); | |||
int getChannel() { | |||
return channel; | |||
} | |||
void setChannel(int channel); | |||
std::string getChannelName(int channel); | |||
json_t* toJson(); | |||
void fromJson(json_t* rootJ); | |||
@@ -149,11 +171,20 @@ struct Input : Port { | |||
Input(); | |||
~Input(); | |||
void reset(); | |||
std::vector<int> getDeviceIds() override; | |||
std::string getDeviceName(int deviceId) override; | |||
std::vector<int> getDeviceIds() override { | |||
if (driver) | |||
return driver->getInputDeviceIds(); | |||
return {}; | |||
} | |||
void setDeviceId(int deviceId) override; | |||
std::string getDeviceName(int deviceId) override { | |||
if (driver) | |||
return driver->getInputDeviceName(deviceId); | |||
return ""; | |||
} | |||
std::vector<int> getChannels() override; | |||
virtual void onMessage(Message message) {} | |||
@@ -175,11 +206,20 @@ struct Output : Port { | |||
Output(); | |||
~Output(); | |||
void reset(); | |||
std::vector<int> getDeviceIds() override; | |||
std::string getDeviceName(int deviceId) override; | |||
std::vector<int> getDeviceIds() override { | |||
if (driver) | |||
return driver->getOutputDeviceIds(); | |||
return {}; | |||
} | |||
void setDeviceId(int deviceId) override; | |||
std::string getDeviceName(int deviceId) override { | |||
if (driver) | |||
return driver->getInputDeviceName(deviceId); | |||
return ""; | |||
} | |||
std::vector<int> getChannels() override; | |||
void sendMessage(Message message); | |||
@@ -190,6 +230,8 @@ void init(); | |||
void destroy(); | |||
/** Registers a new MIDI driver. Takes pointer ownership. */ | |||
void addDriver(int driverId, Driver* driver); | |||
std::vector<int> getDriverIds(); | |||
Driver* getDriver(int driverId); | |||
} // namespace midi | |||
@@ -80,7 +80,7 @@ static void appendAudioDeviceMenu(ui::Menu* menu, audio::Port* port) { | |||
item->port = port; | |||
item->deviceId = -1; | |||
item->text = "(No device)"; | |||
item->rightText = CHECKMARK(port->getDeviceId() == -1); | |||
item->rightText = CHECKMARK(item->deviceId == port->getDeviceId()); | |||
menu->addChild(item); | |||
} | |||
@@ -18,12 +18,12 @@ static void appendMidiDriverMenu(ui::Menu* menu, midi::Port* port) { | |||
if (!port) | |||
return; | |||
for (int driverId : port->getDriverIds()) { | |||
for (int driverId : midi::getDriverIds()) { | |||
MidiDriverValueItem* item = new MidiDriverValueItem; | |||
item->port = port; | |||
item->driverId = driverId; | |||
item->text = port->getDriverName(driverId); | |||
item->rightText = CHECKMARK(item->driverId == port->driverId); | |||
item->text = midi::getDriver(driverId)->getName(); | |||
item->rightText = CHECKMARK(item->driverId == port->getDriverId()); | |||
menu->addChild(item); | |||
} | |||
} | |||
@@ -36,7 +36,7 @@ struct MidiDriverChoice : LedDisplayChoice { | |||
appendMidiDriverMenu(menu, port); | |||
} | |||
void step() override { | |||
text = port ? port->getDriverName(port->driverId) : ""; | |||
text = (port && port->driver) ? port->getDriver()->getName() : ""; | |||
if (text.empty()) { | |||
text = "(No driver)"; | |||
color.a = 0.5f; | |||
@@ -74,7 +74,7 @@ static void appendMidiDeviceMenu(ui::Menu* menu, midi::Port* port) { | |||
item->port = port; | |||
item->deviceId = -1; | |||
item->text = "(No device)"; | |||
item->rightText = CHECKMARK(item->deviceId == port->deviceId); | |||
item->rightText = CHECKMARK(item->deviceId == port->getDeviceId()); | |||
menu->addChild(item); | |||
} | |||
@@ -83,7 +83,7 @@ static void appendMidiDeviceMenu(ui::Menu* menu, midi::Port* port) { | |||
item->port = port; | |||
item->deviceId = deviceId; | |||
item->text = port->getDeviceName(deviceId); | |||
item->rightText = CHECKMARK(item->deviceId == port->deviceId); | |||
item->rightText = CHECKMARK(item->deviceId == port->getDeviceId()); | |||
menu->addChild(item); | |||
} | |||
} | |||
@@ -96,7 +96,7 @@ struct MidiDeviceChoice : LedDisplayChoice { | |||
appendMidiDeviceMenu(menu, port); | |||
} | |||
void step() override { | |||
text = port ? port->getDeviceName(port->deviceId) : ""; | |||
text = (port && port->device) ? port->getDevice()->getName() : ""; | |||
if (text.empty()) { | |||
text = "(No device)"; | |||
color.a = 0.5f; | |||
@@ -121,7 +121,7 @@ struct MidiChannelValueItem : ui::MenuItem { | |||
midi::Port* port; | |||
int channel; | |||
void onAction(const event::Action& e) override { | |||
port->channel = channel; | |||
port->setChannel(channel); | |||
} | |||
}; | |||
@@ -134,7 +134,7 @@ static void appendMidiChannelMenu(ui::Menu* menu, midi::Port* port) { | |||
item->port = port; | |||
item->channel = channel; | |||
item->text = port->getChannelName(channel); | |||
item->rightText = CHECKMARK(item->channel == port->channel); | |||
item->rightText = CHECKMARK(item->channel == port->getChannel()); | |||
menu->addChild(item); | |||
} | |||
} | |||
@@ -147,7 +147,7 @@ struct MidiChannelChoice : LedDisplayChoice { | |||
appendMidiChannelMenu(menu, port); | |||
} | |||
void step() override { | |||
text = port ? port->getChannelName(port->channel) : "Channel 1"; | |||
text = port ? port->getChannelName(port->getChannel()) : "Channel 1"; | |||
} | |||
}; | |||
@@ -81,13 +81,18 @@ void Device::onCloseStream() { | |||
//////////////////// | |||
Port::Port() { | |||
setDriverId(-1); | |||
reset(); | |||
} | |||
Port::~Port() { | |||
setDriverId(-1); | |||
} | |||
void Port::reset() { | |||
setDriverId(-1); | |||
offset = 0; | |||
} | |||
void Port::setDriverId(int driverId) { | |||
// Unset device and driver | |||
setDeviceId(-1); | |||
@@ -16,6 +16,7 @@ struct CCMidiOutput : midi::Output { | |||
for (int n = 0; n < 128; n++) { | |||
lastValues[n] = -1; | |||
} | |||
Output::reset(); | |||
} | |||
void setValue(int value, int cc) { | |||
@@ -18,10 +18,10 @@ struct GateMidiOutput : midi::Output { | |||
vels[note] = 100; | |||
lastGates[note] = false; | |||
} | |||
Output::reset(); | |||
} | |||
void panic() { | |||
reset(); | |||
// Send all note off commands | |||
for (int note = 0; note < 128; note++) { | |||
// Note off | |||
@@ -30,6 +30,7 @@ struct GateMidiOutput : midi::Output { | |||
m.setNote(note); | |||
m.setValue(0); | |||
sendMessage(m); | |||
lastGates[note] = false; | |||
} | |||
} | |||
@@ -7,7 +7,7 @@ namespace core { | |||
struct MidiOutput : dsp::MidiGenerator<PORT_MAX_CHANNELS>, midi::Output { | |||
void onMessage(midi::Message message) override { | |||
midi::Output::sendMessage(message); | |||
Output::sendMessage(message); | |||
} | |||
void reset() { | |||
@@ -19,73 +19,84 @@ enum { | |||
CMD_OCTAVE_UP = -2, | |||
}; | |||
struct DeviceInfo { | |||
std::string name; | |||
std::map<int, int> keyMap; | |||
}; | |||
static const int deviceCount = 2; | |||
static const std::vector<std::map<int, int>> deviceKeyNote = { | |||
static const std::vector<DeviceInfo> deviceInfos = { | |||
{ | |||
{GLFW_KEY_GRAVE_ACCENT, CMD_OCTAVE_DOWN}, | |||
{GLFW_KEY_1, CMD_OCTAVE_UP}, | |||
{GLFW_KEY_Z, 0}, | |||
{GLFW_KEY_S, 1}, | |||
{GLFW_KEY_X, 2}, | |||
{GLFW_KEY_D, 3}, | |||
{GLFW_KEY_C, 4}, | |||
{GLFW_KEY_V, 5}, | |||
{GLFW_KEY_G, 6}, | |||
{GLFW_KEY_B, 7}, | |||
{GLFW_KEY_H, 8}, | |||
{GLFW_KEY_N, 9}, | |||
{GLFW_KEY_J, 10}, | |||
{GLFW_KEY_M, 11}, | |||
{GLFW_KEY_COMMA, 12}, | |||
{GLFW_KEY_L, 13}, | |||
{GLFW_KEY_PERIOD, 14}, | |||
{GLFW_KEY_SEMICOLON, 15}, | |||
{GLFW_KEY_SLASH, 16}, | |||
{GLFW_KEY_Q, 12}, | |||
{GLFW_KEY_2, 13}, | |||
{GLFW_KEY_W, 14}, | |||
{GLFW_KEY_3, 15}, | |||
{GLFW_KEY_E, 16}, | |||
{GLFW_KEY_R, 17}, | |||
{GLFW_KEY_5, 18}, | |||
{GLFW_KEY_T, 19}, | |||
{GLFW_KEY_6, 20}, | |||
{GLFW_KEY_Y, 21}, | |||
{GLFW_KEY_7, 22}, | |||
{GLFW_KEY_U, 23}, | |||
{GLFW_KEY_I, 24}, | |||
{GLFW_KEY_9, 25}, | |||
{GLFW_KEY_O, 26}, | |||
{GLFW_KEY_0, 27}, | |||
{GLFW_KEY_P, 28}, | |||
{GLFW_KEY_LEFT_BRACKET, 29}, | |||
{GLFW_KEY_EQUAL, 30}, | |||
{GLFW_KEY_RIGHT_BRACKET, 31}, | |||
"QWERTY keyboard (US)", | |||
{ | |||
{GLFW_KEY_GRAVE_ACCENT, CMD_OCTAVE_DOWN}, | |||
{GLFW_KEY_1, CMD_OCTAVE_UP}, | |||
{GLFW_KEY_Z, 0}, | |||
{GLFW_KEY_S, 1}, | |||
{GLFW_KEY_X, 2}, | |||
{GLFW_KEY_D, 3}, | |||
{GLFW_KEY_C, 4}, | |||
{GLFW_KEY_V, 5}, | |||
{GLFW_KEY_G, 6}, | |||
{GLFW_KEY_B, 7}, | |||
{GLFW_KEY_H, 8}, | |||
{GLFW_KEY_N, 9}, | |||
{GLFW_KEY_J, 10}, | |||
{GLFW_KEY_M, 11}, | |||
{GLFW_KEY_COMMA, 12}, | |||
{GLFW_KEY_L, 13}, | |||
{GLFW_KEY_PERIOD, 14}, | |||
{GLFW_KEY_SEMICOLON, 15}, | |||
{GLFW_KEY_SLASH, 16}, | |||
{GLFW_KEY_Q, 12}, | |||
{GLFW_KEY_2, 13}, | |||
{GLFW_KEY_W, 14}, | |||
{GLFW_KEY_3, 15}, | |||
{GLFW_KEY_E, 16}, | |||
{GLFW_KEY_R, 17}, | |||
{GLFW_KEY_5, 18}, | |||
{GLFW_KEY_T, 19}, | |||
{GLFW_KEY_6, 20}, | |||
{GLFW_KEY_Y, 21}, | |||
{GLFW_KEY_7, 22}, | |||
{GLFW_KEY_U, 23}, | |||
{GLFW_KEY_I, 24}, | |||
{GLFW_KEY_9, 25}, | |||
{GLFW_KEY_O, 26}, | |||
{GLFW_KEY_0, 27}, | |||
{GLFW_KEY_P, 28}, | |||
{GLFW_KEY_LEFT_BRACKET, 29}, | |||
{GLFW_KEY_EQUAL, 30}, | |||
{GLFW_KEY_RIGHT_BRACKET, 31}, | |||
}, | |||
}, | |||
{ | |||
{GLFW_KEY_KP_DIVIDE, CMD_OCTAVE_DOWN}, | |||
{GLFW_KEY_KP_MULTIPLY, CMD_OCTAVE_UP}, | |||
{GLFW_KEY_KP_0, 0}, | |||
{GLFW_KEY_KP_DECIMAL, 2}, | |||
{GLFW_KEY_KP_ENTER, 3}, | |||
{GLFW_KEY_KP_1, 4}, | |||
{GLFW_KEY_KP_2, 5}, | |||
{GLFW_KEY_KP_3, 6}, | |||
{GLFW_KEY_KP_4, 8}, | |||
{GLFW_KEY_KP_5, 9}, | |||
{GLFW_KEY_KP_6, 10}, | |||
{GLFW_KEY_KP_ADD, 11}, | |||
{GLFW_KEY_KP_7, 12}, | |||
{GLFW_KEY_KP_8, 13}, | |||
{GLFW_KEY_KP_9, 14}, | |||
}, | |||
"Numpad keyboard (US)", | |||
{ | |||
{GLFW_KEY_KP_DIVIDE, CMD_OCTAVE_DOWN}, | |||
{GLFW_KEY_KP_MULTIPLY, CMD_OCTAVE_UP}, | |||
{GLFW_KEY_KP_0, 0}, | |||
{GLFW_KEY_KP_DECIMAL, 2}, | |||
{GLFW_KEY_KP_ENTER, 3}, | |||
{GLFW_KEY_KP_1, 4}, | |||
{GLFW_KEY_KP_2, 5}, | |||
{GLFW_KEY_KP_3, 6}, | |||
{GLFW_KEY_KP_4, 8}, | |||
{GLFW_KEY_KP_5, 9}, | |||
{GLFW_KEY_KP_6, 10}, | |||
{GLFW_KEY_KP_ADD, 11}, | |||
{GLFW_KEY_KP_7, 12}, | |||
{GLFW_KEY_KP_8, 13}, | |||
{GLFW_KEY_KP_9, 14}, | |||
}, | |||
} | |||
}; | |||
@@ -94,13 +105,17 @@ struct InputDevice : midi::InputDevice { | |||
int octave = 5; | |||
std::map<int, int> pressedNotes; | |||
std::string getName() override { | |||
return deviceInfos[deviceId].name; | |||
} | |||
void onKeyPress(int key) { | |||
// Do nothing if no ports are subscribed | |||
if (subscribed.empty()) | |||
return; | |||
auto keyNote = deviceKeyNote[deviceId]; | |||
auto it = keyNote.find(key); | |||
if (it == keyNote.end()) | |||
auto keyMap = deviceInfos[deviceId].keyMap; | |||
auto it = keyMap.find(key); | |||
if (it == keyMap.end()) | |||
return; | |||
int note = it->second; | |||
@@ -171,11 +186,7 @@ struct Driver : midi::Driver { | |||
} | |||
std::string getInputDeviceName(int deviceId) override { | |||
if (deviceId == 0) | |||
return "QWERTY keyboard (US)"; | |||
else if (deviceId == 1) | |||
return "Numpad keyboard (US)"; | |||
return ""; | |||
return deviceInfos[deviceId].name; | |||
} | |||
midi::InputDevice* subscribeInput(int deviceId, midi::Input* input) override { | |||
@@ -10,7 +10,6 @@ namespace midi { | |||
static std::vector<std::pair<int, Driver*>> drivers; | |||
//////////////////// | |||
// Device | |||
//////////////////// | |||
@@ -49,21 +48,10 @@ void OutputDevice::unsubscribe(Output* output) { | |||
// Port | |||
//////////////////// | |||
std::vector<int> Port::getDriverIds() { | |||
std::vector<int> driverIds; | |||
for (auto& pair : drivers) { | |||
driverIds.push_back(pair.first); | |||
} | |||
return driverIds; | |||
Port::Port() { | |||
} | |||
std::string Port::getDriverName(int driverId) { | |||
for (auto& pair : drivers) { | |||
if (pair.first == driverId) { | |||
return pair.second->getName(); | |||
} | |||
} | |||
return ""; | |||
Port::~Port() { | |||
} | |||
void Port::setDriverId(int driverId) { | |||
@@ -72,50 +60,60 @@ void Port::setDriverId(int driverId) { | |||
driver = NULL; | |||
this->driverId = -1; | |||
// Set driver | |||
for (auto& pair : drivers) { | |||
if (pair.first == driverId) { | |||
driver = pair.second; | |||
this->driverId = driverId; | |||
break; | |||
} | |||
// Find driver by ID | |||
driver = midi::getDriver(driverId); | |||
if (driver) { | |||
this->driverId = driverId; | |||
} | |||
else { | |||
// Set first driver as default | |||
driver = drivers[0].second; | |||
this->driverId = drivers[0].first; | |||
} | |||
} | |||
void Port::setChannel(int channel) { | |||
this->channel = channel; | |||
} | |||
std::string Port::getChannelName(int channel) { | |||
if (channel == -1) | |||
if (channel < 0) | |||
return "All channels"; | |||
else | |||
return string::f("Channel %d", channel + 1); | |||
} | |||
void Port::setChannel(int channel) { | |||
this->channel = channel; | |||
} | |||
json_t* Port::toJson() { | |||
json_t* rootJ = json_object(); | |||
json_object_set_new(rootJ, "driver", json_integer(driverId)); | |||
std::string deviceName = getDeviceName(deviceId); | |||
if (!deviceName.empty()) | |||
json_object_set_new(rootJ, "deviceName", json_string(deviceName.c_str())); | |||
json_object_set_new(rootJ, "channel", json_integer(channel)); | |||
json_object_set_new(rootJ, "driver", json_integer(getDriverId())); | |||
if (device) { | |||
std::string deviceName = device->getName(); | |||
if (!deviceName.empty()) | |||
json_object_set_new(rootJ, "deviceName", json_string(deviceName.c_str())); | |||
} | |||
json_object_set_new(rootJ, "channel", json_integer(getChannel())); | |||
return rootJ; | |||
} | |||
void Port::fromJson(json_t* rootJ) { | |||
setDriverId(-1); | |||
json_t* driverJ = json_object_get(rootJ, "driver"); | |||
if (driverJ) | |||
setDriverId(json_integer_value(driverJ)); | |||
json_t* deviceNameJ = json_object_get(rootJ, "deviceName"); | |||
if (deviceNameJ) { | |||
std::string deviceName = json_string_value(deviceNameJ); | |||
// Search for device with equal name | |||
for (int deviceId : getDeviceIds()) { | |||
if (getDeviceName(deviceId) == deviceName) { | |||
setDeviceId(deviceId); | |||
break; | |||
if (driver) { | |||
json_t* deviceNameJ = json_object_get(rootJ, "deviceName"); | |||
if (deviceNameJ) { | |||
std::string deviceName = json_string_value(deviceNameJ); | |||
// Search for device ID with equal name | |||
for (int deviceId : getDeviceIds()) { | |||
if (getDeviceName(deviceId) == deviceName) { | |||
setDeviceId(deviceId); | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
@@ -138,25 +136,8 @@ Input::~Input() { | |||
} | |||
void Input::reset() { | |||
setDriverId(-1); | |||
channel = -1; | |||
// Set first driver as default | |||
if (drivers.size() >= 1) { | |||
setDriverId(drivers[0].first); | |||
} | |||
} | |||
std::vector<int> Input::getDeviceIds() { | |||
if (driver) { | |||
return driver->getInputDeviceIds(); | |||
} | |||
return {}; | |||
} | |||
std::string Input::getDeviceName(int deviceId) { | |||
if (driver) { | |||
return driver->getInputDeviceName(deviceId); | |||
} | |||
return ""; | |||
} | |||
void Input::setDeviceId(int deviceId) { | |||
@@ -164,12 +145,12 @@ void Input::setDeviceId(int deviceId) { | |||
if (driver && this->deviceId >= 0) { | |||
driver->unsubscribeInput(this->deviceId, this); | |||
} | |||
inputDevice = NULL; | |||
device = inputDevice = NULL; | |||
this->deviceId = -1; | |||
// Create device | |||
if (driver && deviceId >= 0) { | |||
inputDevice = driver->subscribeInput(deviceId, this); | |||
device = inputDevice = driver->subscribeInput(deviceId, this); | |||
this->deviceId = deviceId; | |||
} | |||
} | |||
@@ -212,25 +193,8 @@ Output::~Output() { | |||
} | |||
void Output::reset() { | |||
setDriverId(-1); | |||
channel = 0; | |||
// Set first driver as default | |||
if (drivers.size() >= 1) { | |||
setDriverId(drivers[0].first); | |||
} | |||
} | |||
std::vector<int> 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) { | |||
@@ -238,12 +202,12 @@ void Output::setDeviceId(int deviceId) { | |||
if (driver && this->deviceId >= 0) { | |||
driver->unsubscribeOutput(this->deviceId, this); | |||
} | |||
outputDevice = NULL; | |||
device = outputDevice = NULL; | |||
this->deviceId = -1; | |||
// Create device | |||
if (driver && deviceId >= 0) { | |||
outputDevice = driver->subscribeOutput(deviceId, this); | |||
device = outputDevice = driver->subscribeOutput(deviceId, this); | |||
this->deviceId = deviceId; | |||
} | |||
} | |||
@@ -257,14 +221,15 @@ std::vector<int> Output::getChannels() { | |||
} | |||
void Output::sendMessage(Message message) { | |||
if (!outputDevice) | |||
return; | |||
// Set channel | |||
if (message.getStatus() != 0xf) { | |||
message.setChannel(channel); | |||
} | |||
// DEBUG("sendMessage %02x %02x %02x", message.cmd, message.data1, message.data2); | |||
if (outputDevice) { | |||
outputDevice->sendMessage(message); | |||
} | |||
outputDevice->sendMessage(message); | |||
} | |||
@@ -287,6 +252,22 @@ void addDriver(int driverId, Driver* driver) { | |||
drivers.push_back(std::make_pair(driverId, driver)); | |||
} | |||
std::vector<int> getDriverIds() { | |||
std::vector<int> driverIds; | |||
for (auto& pair : drivers) { | |||
driverIds.push_back(pair.first); | |||
} | |||
return driverIds; | |||
} | |||
Driver* getDriver(int driverId) { | |||
for (auto& pair : drivers) { | |||
if (pair.first == driverId) | |||
return pair.second; | |||
} | |||
return NULL; | |||
} | |||
} // namespace midi | |||
} // namespace rack |
@@ -15,12 +15,14 @@ namespace rack { | |||
struct RtMidiInputDevice : midi::InputDevice { | |||
RtMidiIn* rtMidiIn; | |||
std::string name; | |||
RtMidiInputDevice(int driverId, int deviceId) { | |||
rtMidiIn = new RtMidiIn((RtMidi::Api) driverId, "VCV Rack"); | |||
assert(rtMidiIn); | |||
rtMidiIn->ignoreTypes(false, false, false); | |||
rtMidiIn->setCallback(midiInputCallback, this); | |||
name = rtMidiIn->getPortName(deviceId); | |||
rtMidiIn->openPort(deviceId, "VCV Rack input"); | |||
} | |||
@@ -29,6 +31,10 @@ struct RtMidiInputDevice : midi::InputDevice { | |||
delete rtMidiIn; | |||
} | |||
std::string getName() override { | |||
return name; | |||
} | |||
static void midiInputCallback(double timeStamp, std::vector<unsigned char>* message, void* userData) { | |||
if (!message) | |||
return; | |||
@@ -55,10 +61,12 @@ struct RtMidiInputDevice : midi::InputDevice { | |||
struct RtMidiOutputDevice : midi::OutputDevice { | |||
RtMidiOut* rtMidiOut; | |||
std::string name; | |||
RtMidiOutputDevice(int driverId, int deviceId) { | |||
rtMidiOut = new RtMidiOut((RtMidi::Api) driverId, "VCV Rack"); | |||
assert(rtMidiOut); | |||
name = rtMidiOut->getPortName(deviceId); | |||
rtMidiOut->openPort(deviceId, "VCV Rack output"); | |||
} | |||
@@ -67,6 +75,10 @@ struct RtMidiOutputDevice : midi::OutputDevice { | |||
delete rtMidiOut; | |||
} | |||
std::string getName() override { | |||
return name; | |||
} | |||
void sendMessage(midi::Message message) override { | |||
rtMidiOut->sendMessage(message.bytes, message.size); | |||
} | |||