| @@ -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); | |||
| } | |||