@@ -16,8 +16,8 @@ namespace audio { | |||||
// Driver | // Driver | ||||
//////////////////// | //////////////////// | ||||
struct Port; | |||||
struct Device; | struct Device; | ||||
struct Port; | |||||
struct Driver { | struct Driver { | ||||
virtual ~Driver() {} | virtual ~Driver() {} | ||||
@@ -95,7 +95,9 @@ struct Device { | |||||
//////////////////// | //////////////////// | ||||
struct Port { | struct Port { | ||||
/** The first channel index of the device to process. */ | |||||
int offset = 0; | int offset = 0; | ||||
/** Maximum number of channels to process. */ | |||||
int maxChannels = 8; | int maxChannels = 8; | ||||
// private | // private | ||||
@@ -107,6 +109,7 @@ struct Port { | |||||
Port(); | Port(); | ||||
virtual ~Port(); | virtual ~Port(); | ||||
void reset(); | |||||
Driver* getDriver() { | Driver* getDriver() { | ||||
return driver; | return driver; | ||||
@@ -18,6 +18,9 @@ struct Message { | |||||
uint8_t size = 3; | uint8_t size = 3; | ||||
uint8_t bytes[3] = {}; | uint8_t bytes[3] = {}; | ||||
uint8_t getSize() { | |||||
return size; | |||||
} | |||||
void setSize(uint8_t size) { | void setSize(uint8_t size) { | ||||
assert(size <= 3); | assert(size <= 3); | ||||
this->size = size; | this->size = size; | ||||
@@ -91,6 +94,9 @@ struct Driver { | |||||
struct Device { | struct Device { | ||||
virtual ~Device() {} | virtual ~Device() {} | ||||
virtual std::string getName() { | |||||
return ""; | |||||
} | |||||
}; | }; | ||||
struct InputDevice : Device { | struct InputDevice : Device { | ||||
@@ -112,31 +118,47 @@ struct OutputDevice : Device { | |||||
//////////////////// | //////////////////// | ||||
struct Port { | struct Port { | ||||
int driverId = -1; | |||||
int deviceId = -1; | |||||
/* For MIDI output, the channel to output messages. | /* For MIDI output, the channel to output messages. | ||||
For MIDI input, the channel to filter. | For MIDI input, the channel to filter. | ||||
Set to -1 to allow all MIDI channels (for input). | Set to -1 to allow all MIDI channels (for input). | ||||
Zero indexed. | Zero indexed. | ||||
*/ | */ | ||||
int channel = -1; | int channel = -1; | ||||
// private | |||||
int driverId = -1; | |||||
int deviceId = -1; | |||||
/** Not owned */ | /** Not owned */ | ||||
Driver* driver = NULL; | 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); | void setDriverId(int driverId); | ||||
Device* getDevice() { | |||||
return device; | |||||
} | |||||
virtual std::vector<int> getDeviceIds() = 0; | virtual std::vector<int> getDeviceIds() = 0; | ||||
virtual std::string getDeviceName(int deviceId) = 0; | |||||
int getDeviceId() { | |||||
return deviceId; | |||||
} | |||||
virtual void setDeviceId(int deviceId) = 0; | virtual void setDeviceId(int deviceId) = 0; | ||||
virtual std::string getDeviceName(int deviceId) = 0; | |||||
virtual std::vector<int> getChannels() = 0; | virtual std::vector<int> getChannels() = 0; | ||||
std::string getChannelName(int channel); | |||||
int getChannel() { | |||||
return channel; | |||||
} | |||||
void setChannel(int channel); | void setChannel(int channel); | ||||
std::string getChannelName(int channel); | |||||
json_t* toJson(); | json_t* toJson(); | ||||
void fromJson(json_t* rootJ); | void fromJson(json_t* rootJ); | ||||
@@ -149,11 +171,20 @@ struct Input : Port { | |||||
Input(); | Input(); | ||||
~Input(); | ~Input(); | ||||
void reset(); | 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; | void setDeviceId(int deviceId) override; | ||||
std::string getDeviceName(int deviceId) override { | |||||
if (driver) | |||||
return driver->getInputDeviceName(deviceId); | |||||
return ""; | |||||
} | |||||
std::vector<int> getChannels() override; | std::vector<int> getChannels() override; | ||||
virtual void onMessage(Message message) {} | virtual void onMessage(Message message) {} | ||||
@@ -175,11 +206,20 @@ struct Output : Port { | |||||
Output(); | Output(); | ||||
~Output(); | ~Output(); | ||||
void reset(); | 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; | void setDeviceId(int deviceId) override; | ||||
std::string getDeviceName(int deviceId) override { | |||||
if (driver) | |||||
return driver->getInputDeviceName(deviceId); | |||||
return ""; | |||||
} | |||||
std::vector<int> getChannels() override; | std::vector<int> getChannels() override; | ||||
void sendMessage(Message message); | void sendMessage(Message message); | ||||
@@ -190,6 +230,8 @@ void init(); | |||||
void destroy(); | void destroy(); | ||||
/** Registers a new MIDI driver. Takes pointer ownership. */ | /** Registers a new MIDI driver. Takes pointer ownership. */ | ||||
void addDriver(int driverId, Driver* driver); | void addDriver(int driverId, Driver* driver); | ||||
std::vector<int> getDriverIds(); | |||||
Driver* getDriver(int driverId); | |||||
} // namespace midi | } // namespace midi | ||||
@@ -80,7 +80,7 @@ static void appendAudioDeviceMenu(ui::Menu* menu, audio::Port* port) { | |||||
item->port = port; | item->port = port; | ||||
item->deviceId = -1; | item->deviceId = -1; | ||||
item->text = "(No device)"; | item->text = "(No device)"; | ||||
item->rightText = CHECKMARK(port->getDeviceId() == -1); | |||||
item->rightText = CHECKMARK(item->deviceId == port->getDeviceId()); | |||||
menu->addChild(item); | menu->addChild(item); | ||||
} | } | ||||
@@ -18,12 +18,12 @@ static void appendMidiDriverMenu(ui::Menu* menu, midi::Port* port) { | |||||
if (!port) | if (!port) | ||||
return; | return; | ||||
for (int driverId : port->getDriverIds()) { | |||||
for (int driverId : midi::getDriverIds()) { | |||||
MidiDriverValueItem* item = new MidiDriverValueItem; | MidiDriverValueItem* item = new MidiDriverValueItem; | ||||
item->port = port; | item->port = port; | ||||
item->driverId = driverId; | 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); | menu->addChild(item); | ||||
} | } | ||||
} | } | ||||
@@ -36,7 +36,7 @@ struct MidiDriverChoice : LedDisplayChoice { | |||||
appendMidiDriverMenu(menu, port); | appendMidiDriverMenu(menu, port); | ||||
} | } | ||||
void step() override { | void step() override { | ||||
text = port ? port->getDriverName(port->driverId) : ""; | |||||
text = (port && port->driver) ? port->getDriver()->getName() : ""; | |||||
if (text.empty()) { | if (text.empty()) { | ||||
text = "(No driver)"; | text = "(No driver)"; | ||||
color.a = 0.5f; | color.a = 0.5f; | ||||
@@ -74,7 +74,7 @@ static void appendMidiDeviceMenu(ui::Menu* menu, midi::Port* port) { | |||||
item->port = port; | item->port = port; | ||||
item->deviceId = -1; | item->deviceId = -1; | ||||
item->text = "(No device)"; | item->text = "(No device)"; | ||||
item->rightText = CHECKMARK(item->deviceId == port->deviceId); | |||||
item->rightText = CHECKMARK(item->deviceId == port->getDeviceId()); | |||||
menu->addChild(item); | menu->addChild(item); | ||||
} | } | ||||
@@ -83,7 +83,7 @@ static void appendMidiDeviceMenu(ui::Menu* menu, midi::Port* port) { | |||||
item->port = port; | item->port = port; | ||||
item->deviceId = deviceId; | item->deviceId = deviceId; | ||||
item->text = port->getDeviceName(deviceId); | item->text = port->getDeviceName(deviceId); | ||||
item->rightText = CHECKMARK(item->deviceId == port->deviceId); | |||||
item->rightText = CHECKMARK(item->deviceId == port->getDeviceId()); | |||||
menu->addChild(item); | menu->addChild(item); | ||||
} | } | ||||
} | } | ||||
@@ -96,7 +96,7 @@ struct MidiDeviceChoice : LedDisplayChoice { | |||||
appendMidiDeviceMenu(menu, port); | appendMidiDeviceMenu(menu, port); | ||||
} | } | ||||
void step() override { | void step() override { | ||||
text = port ? port->getDeviceName(port->deviceId) : ""; | |||||
text = (port && port->device) ? port->getDevice()->getName() : ""; | |||||
if (text.empty()) { | if (text.empty()) { | ||||
text = "(No device)"; | text = "(No device)"; | ||||
color.a = 0.5f; | color.a = 0.5f; | ||||
@@ -121,7 +121,7 @@ struct MidiChannelValueItem : ui::MenuItem { | |||||
midi::Port* port; | midi::Port* port; | ||||
int channel; | int channel; | ||||
void onAction(const event::Action& e) override { | 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->port = port; | ||||
item->channel = channel; | item->channel = channel; | ||||
item->text = port->getChannelName(channel); | item->text = port->getChannelName(channel); | ||||
item->rightText = CHECKMARK(item->channel == port->channel); | |||||
item->rightText = CHECKMARK(item->channel == port->getChannel()); | |||||
menu->addChild(item); | menu->addChild(item); | ||||
} | } | ||||
} | } | ||||
@@ -147,7 +147,7 @@ struct MidiChannelChoice : LedDisplayChoice { | |||||
appendMidiChannelMenu(menu, port); | appendMidiChannelMenu(menu, port); | ||||
} | } | ||||
void step() override { | 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() { | Port::Port() { | ||||
setDriverId(-1); | |||||
reset(); | |||||
} | } | ||||
Port::~Port() { | Port::~Port() { | ||||
setDriverId(-1); | setDriverId(-1); | ||||
} | } | ||||
void Port::reset() { | |||||
setDriverId(-1); | |||||
offset = 0; | |||||
} | |||||
void Port::setDriverId(int driverId) { | void Port::setDriverId(int driverId) { | ||||
// Unset device and driver | // Unset device and driver | ||||
setDeviceId(-1); | setDeviceId(-1); | ||||
@@ -16,6 +16,7 @@ struct CCMidiOutput : midi::Output { | |||||
for (int n = 0; n < 128; n++) { | for (int n = 0; n < 128; n++) { | ||||
lastValues[n] = -1; | lastValues[n] = -1; | ||||
} | } | ||||
Output::reset(); | |||||
} | } | ||||
void setValue(int value, int cc) { | void setValue(int value, int cc) { | ||||
@@ -18,10 +18,10 @@ struct GateMidiOutput : midi::Output { | |||||
vels[note] = 100; | vels[note] = 100; | ||||
lastGates[note] = false; | lastGates[note] = false; | ||||
} | } | ||||
Output::reset(); | |||||
} | } | ||||
void panic() { | void panic() { | ||||
reset(); | |||||
// Send all note off commands | // Send all note off commands | ||||
for (int note = 0; note < 128; note++) { | for (int note = 0; note < 128; note++) { | ||||
// Note off | // Note off | ||||
@@ -30,6 +30,7 @@ struct GateMidiOutput : midi::Output { | |||||
m.setNote(note); | m.setNote(note); | ||||
m.setValue(0); | m.setValue(0); | ||||
sendMessage(m); | sendMessage(m); | ||||
lastGates[note] = false; | |||||
} | } | ||||
} | } | ||||
@@ -7,7 +7,7 @@ namespace core { | |||||
struct MidiOutput : dsp::MidiGenerator<PORT_MAX_CHANNELS>, midi::Output { | struct MidiOutput : dsp::MidiGenerator<PORT_MAX_CHANNELS>, midi::Output { | ||||
void onMessage(midi::Message message) override { | void onMessage(midi::Message message) override { | ||||
midi::Output::sendMessage(message); | |||||
Output::sendMessage(message); | |||||
} | } | ||||
void reset() { | void reset() { | ||||
@@ -19,73 +19,84 @@ enum { | |||||
CMD_OCTAVE_UP = -2, | CMD_OCTAVE_UP = -2, | ||||
}; | }; | ||||
struct DeviceInfo { | |||||
std::string name; | |||||
std::map<int, int> keyMap; | |||||
}; | |||||
static const int deviceCount = 2; | 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; | int octave = 5; | ||||
std::map<int, int> pressedNotes; | std::map<int, int> pressedNotes; | ||||
std::string getName() override { | |||||
return deviceInfos[deviceId].name; | |||||
} | |||||
void onKeyPress(int key) { | void onKeyPress(int key) { | ||||
// Do nothing if no ports are subscribed | // Do nothing if no ports are subscribed | ||||
if (subscribed.empty()) | if (subscribed.empty()) | ||||
return; | 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; | return; | ||||
int note = it->second; | int note = it->second; | ||||
@@ -171,11 +186,7 @@ struct Driver : midi::Driver { | |||||
} | } | ||||
std::string getInputDeviceName(int deviceId) override { | 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 { | midi::InputDevice* subscribeInput(int deviceId, midi::Input* input) override { | ||||
@@ -10,7 +10,6 @@ namespace midi { | |||||
static std::vector<std::pair<int, Driver*>> drivers; | static std::vector<std::pair<int, Driver*>> drivers; | ||||
//////////////////// | //////////////////// | ||||
// Device | // Device | ||||
//////////////////// | //////////////////// | ||||
@@ -49,21 +48,10 @@ void OutputDevice::unsubscribe(Output* output) { | |||||
// Port | // 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) { | void Port::setDriverId(int driverId) { | ||||
@@ -72,50 +60,60 @@ void Port::setDriverId(int driverId) { | |||||
driver = NULL; | driver = NULL; | ||||
this->driverId = -1; | 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) { | std::string Port::getChannelName(int channel) { | ||||
if (channel == -1) | |||||
if (channel < 0) | |||||
return "All channels"; | return "All channels"; | ||||
else | else | ||||
return string::f("Channel %d", channel + 1); | return string::f("Channel %d", channel + 1); | ||||
} | } | ||||
void Port::setChannel(int channel) { | |||||
this->channel = channel; | |||||
} | |||||
json_t* Port::toJson() { | json_t* Port::toJson() { | ||||
json_t* rootJ = json_object(); | 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; | return rootJ; | ||||
} | } | ||||
void Port::fromJson(json_t* rootJ) { | void Port::fromJson(json_t* rootJ) { | ||||
setDriverId(-1); | |||||
json_t* driverJ = json_object_get(rootJ, "driver"); | json_t* driverJ = json_object_get(rootJ, "driver"); | ||||
if (driverJ) | if (driverJ) | ||||
setDriverId(json_integer_value(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() { | void Input::reset() { | ||||
setDriverId(-1); | |||||
channel = -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) { | void Input::setDeviceId(int deviceId) { | ||||
@@ -164,12 +145,12 @@ void Input::setDeviceId(int deviceId) { | |||||
if (driver && this->deviceId >= 0) { | if (driver && this->deviceId >= 0) { | ||||
driver->unsubscribeInput(this->deviceId, this); | driver->unsubscribeInput(this->deviceId, this); | ||||
} | } | ||||
inputDevice = NULL; | |||||
device = inputDevice = NULL; | |||||
this->deviceId = -1; | this->deviceId = -1; | ||||
// Create device | // Create device | ||||
if (driver && deviceId >= 0) { | if (driver && deviceId >= 0) { | ||||
inputDevice = driver->subscribeInput(deviceId, this); | |||||
device = inputDevice = driver->subscribeInput(deviceId, this); | |||||
this->deviceId = deviceId; | this->deviceId = deviceId; | ||||
} | } | ||||
} | } | ||||
@@ -212,25 +193,8 @@ Output::~Output() { | |||||
} | } | ||||
void Output::reset() { | void Output::reset() { | ||||
setDriverId(-1); | |||||
channel = 0; | 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) { | void Output::setDeviceId(int deviceId) { | ||||
@@ -238,12 +202,12 @@ void Output::setDeviceId(int deviceId) { | |||||
if (driver && this->deviceId >= 0) { | if (driver && this->deviceId >= 0) { | ||||
driver->unsubscribeOutput(this->deviceId, this); | driver->unsubscribeOutput(this->deviceId, this); | ||||
} | } | ||||
outputDevice = NULL; | |||||
device = outputDevice = NULL; | |||||
this->deviceId = -1; | this->deviceId = -1; | ||||
// Create device | // Create device | ||||
if (driver && deviceId >= 0) { | if (driver && deviceId >= 0) { | ||||
outputDevice = driver->subscribeOutput(deviceId, this); | |||||
device = outputDevice = driver->subscribeOutput(deviceId, this); | |||||
this->deviceId = deviceId; | this->deviceId = deviceId; | ||||
} | } | ||||
} | } | ||||
@@ -257,14 +221,15 @@ std::vector<int> Output::getChannels() { | |||||
} | } | ||||
void Output::sendMessage(Message message) { | void Output::sendMessage(Message message) { | ||||
if (!outputDevice) | |||||
return; | |||||
// Set channel | // Set channel | ||||
if (message.getStatus() != 0xf) { | if (message.getStatus() != 0xf) { | ||||
message.setChannel(channel); | message.setChannel(channel); | ||||
} | } | ||||
// DEBUG("sendMessage %02x %02x %02x", message.cmd, message.data1, message.data2); | // 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)); | 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 midi | ||||
} // namespace rack | } // namespace rack |
@@ -15,12 +15,14 @@ namespace rack { | |||||
struct RtMidiInputDevice : midi::InputDevice { | struct RtMidiInputDevice : midi::InputDevice { | ||||
RtMidiIn* rtMidiIn; | RtMidiIn* rtMidiIn; | ||||
std::string name; | |||||
RtMidiInputDevice(int driverId, int deviceId) { | RtMidiInputDevice(int driverId, int deviceId) { | ||||
rtMidiIn = new RtMidiIn((RtMidi::Api) driverId, "VCV Rack"); | rtMidiIn = new RtMidiIn((RtMidi::Api) driverId, "VCV Rack"); | ||||
assert(rtMidiIn); | assert(rtMidiIn); | ||||
rtMidiIn->ignoreTypes(false, false, false); | rtMidiIn->ignoreTypes(false, false, false); | ||||
rtMidiIn->setCallback(midiInputCallback, this); | rtMidiIn->setCallback(midiInputCallback, this); | ||||
name = rtMidiIn->getPortName(deviceId); | |||||
rtMidiIn->openPort(deviceId, "VCV Rack input"); | rtMidiIn->openPort(deviceId, "VCV Rack input"); | ||||
} | } | ||||
@@ -29,6 +31,10 @@ struct RtMidiInputDevice : midi::InputDevice { | |||||
delete rtMidiIn; | delete rtMidiIn; | ||||
} | } | ||||
std::string getName() override { | |||||
return name; | |||||
} | |||||
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) | if (!message) | ||||
return; | return; | ||||
@@ -55,10 +61,12 @@ struct RtMidiInputDevice : midi::InputDevice { | |||||
struct RtMidiOutputDevice : midi::OutputDevice { | struct RtMidiOutputDevice : midi::OutputDevice { | ||||
RtMidiOut* rtMidiOut; | RtMidiOut* rtMidiOut; | ||||
std::string name; | |||||
RtMidiOutputDevice(int driverId, int deviceId) { | RtMidiOutputDevice(int driverId, int deviceId) { | ||||
rtMidiOut = new RtMidiOut((RtMidi::Api) driverId, "VCV Rack"); | rtMidiOut = new RtMidiOut((RtMidi::Api) driverId, "VCV Rack"); | ||||
assert(rtMidiOut); | assert(rtMidiOut); | ||||
name = rtMidiOut->getPortName(deviceId); | |||||
rtMidiOut->openPort(deviceId, "VCV Rack output"); | rtMidiOut->openPort(deviceId, "VCV Rack output"); | ||||
} | } | ||||
@@ -67,6 +75,10 @@ struct RtMidiOutputDevice : midi::OutputDevice { | |||||
delete rtMidiOut; | delete rtMidiOut; | ||||
} | } | ||||
std::string getName() override { | |||||
return name; | |||||
} | |||||
void sendMessage(midi::Message message) override { | void sendMessage(midi::Message message) override { | ||||
rtMidiOut->sendMessage(message.bytes, message.size); | rtMidiOut->sendMessage(message.bytes, message.size); | ||||
} | } | ||||