From d563a9ceb9992f1b488a080379345ed4644c0fe9 Mon Sep 17 00:00:00 2001 From: Bernhard Wagner Date: Tue, 3 Feb 2026 10:26:20 +0100 Subject: [PATCH] Add indexed MIDI device selection and listing - Add devindex for choosing devices by index - Add list-index command - Update README usage text --- README.md | 4 +++- Source/ApplicationCommand.cpp | 14 ++++++++++++++ Source/ApplicationCommand.h | 2 ++ Source/ApplicationState.cpp | 19 +++++++++++++++++++ Source/ApplicationState.h | 4 ++-- 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 55f3ebf..b43e8da 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,10 @@ To use it, simply type "sendmidi" or "sendmidi.exe" on the command line and foll These are all the supported commands: ``` dev name Set the name of the MIDI output port + devindex index Set MIDI output port by index (see listi) virt (name) Use virtual MIDI port with optional name (Linux/macOS) list Lists the MIDI output ports + listi Lists the MIDI output ports with indices panic Sends all possible Note Offs and relevant panic CCs file path Loads commands from the specified program file dec Interpret the next numbers as decimals by default @@ -81,7 +83,7 @@ These are all the supported commands: Alternatively, you can use the following long versions of the commands: ``` - device virtual decimal hexadecimal channel octave-middle-c note-on note-off + device device-index virtual list-index decimal hexadecimal channel octave-middle-c note-on note-off poly-pressure control-change control-change-14 program-change channel-pressure pitch-bend midi-clock continue active-sensing reset system-exclusive system-exclusive-file time-code song-position song-select diff --git a/Source/ApplicationCommand.cpp b/Source/ApplicationCommand.cpp index fa1c970..7385fb7 100644 --- a/Source/ApplicationCommand.cpp +++ b/Source/ApplicationCommand.cpp @@ -55,11 +55,25 @@ void ApplicationCommand::execute(ApplicationState& state) std::cout << device.name << std::endl; } break; + case LIST_INDEX: + { + auto devices = MidiOutput::getAvailableDevices(); + for (int i = 0; i < devices.size(); ++i) + { + std::cout << i << " " << devices[i].name << std::endl; + } + break; + } case DEVICE: { state.openOutputDevice(opts_[0]); break; } + case DEVICE_INDEX: + { + state.openOutputDeviceByIndex(opts_[0].getIntValue()); + break; + } case VIRTUAL: { auto name = DEFAULT_VIRTUAL_NAME; diff --git a/Source/ApplicationCommand.h b/Source/ApplicationCommand.h index d0f2a9d..51086bb 100644 --- a/Source/ApplicationCommand.h +++ b/Source/ApplicationCommand.h @@ -24,8 +24,10 @@ enum CommandIndex { NONE, LIST, + LIST_INDEX, PANIC, DEVICE, + DEVICE_INDEX, VIRTUAL, TXTFILE, DECIMAL, diff --git a/Source/ApplicationState.cpp b/Source/ApplicationState.cpp index a4f72da..a095ddb 100644 --- a/Source/ApplicationState.cpp +++ b/Source/ApplicationState.cpp @@ -24,8 +24,10 @@ static const int DEFAULT_OCTAVE_MIDDLE_C = 3; ApplicationState::ApplicationState() { commands_.add({"dev", "device", DEVICE, 1, {"name"}, {"Set the name of the MIDI output port"}}); + commands_.add({"devindex", "device-index", DEVICE_INDEX, 1, {"index"}, {"Set MIDI output port by index (see listi)"}}); commands_.add({"virt", "virtual", VIRTUAL, -1, {"(name)"}, {"Use virtual MIDI port with optional name (Linux/macOS)"}}); commands_.add({"list", "", LIST, 0, {""}, {"Lists the MIDI output ports"}}); + commands_.add({"listi", "list-index", LIST_INDEX, 0, {""}, {"Lists the MIDI output ports with indices"}}); commands_.add({"panic", "", PANIC, 0, {""}, {"Sends all possible Note Offs and relevant panic CCs"}}); commands_.add({"file", "", TXTFILE, 1, {"path"}, {"Loads commands from the specified program file"}}); commands_.add({"dec", "decimal", DECIMAL, 0, {""}, {"Interpret the next numbers as decimals by default"}}); @@ -226,6 +228,23 @@ void ApplicationState::openOutputDevice(const String& name) } } +void ApplicationState::openOutputDeviceByIndex(int index) +{ + midiOut_ = nullptr; + auto devices = MidiOutput::getAvailableDevices(); + if (index >= 0 && index < devices.size()) + { + midiOut_ = MidiOutput::openDevice(devices[index].identifier); + if (midiOut_) + { + midiOutName_ = devices[index].name; + return; + } + } + std::cerr << "Couldn't open MIDI output port with index " << index << std::endl; + JUCEApplicationBase::getInstance()->setApplicationReturnValue(EXIT_FAILURE); +} + void ApplicationState::openInputDevice(const String& name) { midiIn_ = nullptr; diff --git a/Source/ApplicationState.h b/Source/ApplicationState.h index 546ee9a..d55e990 100644 --- a/Source/ApplicationState.h +++ b/Source/ApplicationState.h @@ -28,8 +28,9 @@ class ApplicationState : public MidiInputCallback, public ci::DeviceMessageHandl public: ApplicationState(); void initialise(JUCEApplicationBase& app); - + void openOutputDevice(const String& name); + void openOutputDeviceByIndex(int index); void openInputDevice(const String& name); void virtualDevice(const String& name); void parseFile(File file); @@ -82,4 +83,3 @@ class ApplicationState : public MidiInputCallback, public ci::DeviceMessageHandl uint32 lastTimeStampCounter_; int64_t lastTimeStamp_; }; -