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