Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,13 @@ To use it, simply type "receivemidi" or "receivemidi.exe" on the command line an
These are all the supported commands:
```
dev name Set the name of the MIDI input port
devindex index Set MIDI input port by index (see listi)
virt (name) Use virtual MIDI port with optional name (Linux/macOS)
pass name Set name of MIDI output port for MIDI pass-through
passindex index Set MIDI output port by index (see listo)
list Lists the MIDI input ports
listi Lists the MIDI input ports with indices
listo Lists the MIDI output ports
file path Loads commands from the specified program file
dec Interpret the next numbers as decimals by default
hex Interpret the next numbers as hexadecimals by default
Expand Down Expand Up @@ -101,7 +105,7 @@ These are all the supported commands:

Alternatively, you can use the following long versions of the commands:
```
device virtual pass-through decimal hexadecimal channel timestamp
device device-index virtual pass-through pass-through-index list-index list-output decimal hexadecimal channel timestamp
note-numbers octave-middle-c note-on note-off poly-pressure control-change
control-change-14 nrpn-full rpn-full program-change channel-pressure
pitch-bend system-realtime continue active-sensing reset system-common
Expand Down
4 changes: 4 additions & 0 deletions Source/ApplicationCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ enum CommandIndex
{
NONE,
LIST,
LIST_INDEX,
LIST_OUTPUT,
DEVICE,
DEVICE_INDEX,
VIRTUAL,
PASSTHROUGH,
PASSTHROUGH_INDEX,
TXTFILE,
DECIMAL,
HEXADECIMAL,
Expand Down
118 changes: 111 additions & 7 deletions Source/ApplicationState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,13 @@ inline float sign(float value)
ApplicationState::ApplicationState()
{
commands_.add({"dev", "device", DEVICE, 1, {"name"}, {"Set the name of the MIDI input port"}});
commands_.add({"devindex", "device-index", DEVICE_INDEX, 1, {"index"}, {"Set MIDI input port by index (see listi)"}});
commands_.add({"virt", "virtual", VIRTUAL, -1, {"(name)"}, {"Use virtual MIDI port with optional name (Linux/macOS)"}});
commands_.add({"pass", "pass-through", PASSTHROUGH, 1, {"name"}, {"Set name of MIDI output port for MIDI pass-through"}});
commands_.add({"passindex", "pass-through-index", PASSTHROUGH_INDEX, 1, {"index"}, {"Set MIDI output port by index (see listo)"}});
commands_.add({"list", "", LIST, 0, {""}, {"Lists the MIDI input ports"}});
commands_.add({"listi", "list-index", LIST_INDEX, 0, {""}, {"Lists the MIDI input ports with indices"}});
commands_.add({"listo", "list-output", LIST_OUTPUT, 0, {""}, {"Lists the MIDI output ports"}});
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"}});
commands_.add({"hex", "hexadecimal", HEXADECIMAL, 0, {""}, {"Interpret the next numbers as hexadecimals by default"}});
Expand Down Expand Up @@ -153,6 +157,17 @@ void ApplicationState::initialise(JUCEApplicationBase& app)
bool ApplicationState::isMidiInDeviceAvailable(const String& name)
{
auto devices = MidiInput::getAvailableDevices();
if (midiInIdentifier_.isNotEmpty())
{
for (int i = 0; i < devices.size(); ++i)
{
if (devices[i].identifier == midiInIdentifier_)
{
return true;
}
}
return false;
}
for (int i = 0; i < devices.size(); ++i)
{
if (devices[i].name == name)
Expand All @@ -172,7 +187,7 @@ void ApplicationState::timerCallback()
fullMidiInName_ = String();
midiIn_ = nullptr;
}
else if ((midiInName_.isNotEmpty() && midiIn_ == nullptr))
else if ((midiIn_ == nullptr) && (midiInName_.isNotEmpty() || midiInIdentifier_.isNotEmpty()))
{
if (tryToConnectMidiInput())
{
Expand Down Expand Up @@ -237,13 +252,35 @@ void ApplicationState::openInputDevice(const String& name)
{
midiIn_ = nullptr;
midiInName_ = name;
midiInIdentifier_.clear();

if (!tryToConnectMidiInput())
{
std::cerr << "Couldn't find MIDI input port \"" << name << "\", waiting" << std::endl;
}
}

void ApplicationState::openInputDeviceByIndex(int index)
{
midiIn_ = nullptr;
midiInName_.clear();
fullMidiInName_.clear();
midiInIdentifier_.clear();

auto devices = MidiInput::getAvailableDevices();
if (index >= 0 && index < devices.size())
{
midiInIdentifier_ = devices[index].identifier;
if (tryToConnectMidiInput())
{
return;
}
}

std::cerr << "Couldn't open MIDI input port with index " << index << std::endl;
JUCEApplicationBase::getInstance()->setApplicationReturnValue(EXIT_FAILURE);
}

std::unique_ptr<MidiOutput> ApplicationState::openOutputDevice(const String& name)
{
std::unique_ptr<MidiOutput> output;
Expand Down Expand Up @@ -282,6 +319,23 @@ std::unique_ptr<MidiOutput> ApplicationState::openOutputDevice(const String& nam
return output;
}

std::unique_ptr<MidiOutput> ApplicationState::openOutputDeviceByIndex(int index)
{
auto devices = MidiOutput::getAvailableDevices();
if (index >= 0 && index < devices.size())
{
auto output = MidiOutput::openDevice(devices[index].identifier);
if (output)
{
return output;
}
}

std::cerr << "Couldn't open MIDI output port with index " << index << std::endl;
JUCEApplicationBase::getInstance()->setApplicationReturnValue(EXIT_FAILURE);
return nullptr;
}

void ApplicationState::parseParameters(StringArray& parameters)
{
for (String param : parameters)
Expand Down Expand Up @@ -614,24 +668,42 @@ bool ApplicationState::tryToConnectMidiInput()
String midi_input_name;

auto devices = MidiInput::getAvailableDevices();
for (int i = 0; i < devices.size(); ++i)
if (midiInIdentifier_.isNotEmpty())
{
if (devices[i].name == midiInName_)
for (int i = 0; i < devices.size(); ++i)
{
midi_input = MidiInput::openDevice(devices[i].identifier, this);
midi_input_name = devices[i].name;
break;
if (devices[i].identifier == midiInIdentifier_)
{
midi_input = MidiInput::openDevice(devices[i].identifier, this);
midi_input_name = devices[i].name;
break;
}
}
}

if (midi_input == nullptr)
if (midi_input == nullptr && midiInName_.isNotEmpty())
{
for (int i = 0; i < devices.size(); ++i)
{
if (devices[i].name == midiInName_)
{
midi_input = MidiInput::openDevice(devices[i].identifier, this);
midi_input_name = devices[i].name;
midiInIdentifier_ = devices[i].identifier;
break;
}
}
}

if (midi_input == nullptr && midiInName_.isNotEmpty())
{
for (int i = 0; i < devices.size(); ++i)
{
if (devices[i].name.containsIgnoreCase(midiInName_))
{
midi_input = MidiInput::openDevice(devices[i].identifier, this);
midi_input_name = devices[i].name;
midiInIdentifier_ = devices[i].identifier;
break;
}
}
Expand All @@ -655,17 +727,44 @@ void ApplicationState::executeCommand(ApplicationCommand& cmd)
case NONE:
break;
case LIST:
{
for (auto&& device : MidiInput::getAvailableDevices())
{
std::cout << device.name << std::endl;
}
JUCEApplicationBase::getInstance()->systemRequestedQuit();
break;
}
case LIST_INDEX:
{
auto devices = MidiInput::getAvailableDevices();
for (int i = 0; i < devices.size(); ++i)
{
std::cout << i << " " << devices[i].name << std::endl;
}
JUCEApplicationBase::getInstance()->systemRequestedQuit();
break;
}
case LIST_OUTPUT:
{
auto devices = MidiOutput::getAvailableDevices();
for (int i = 0; i < devices.size(); ++i)
{
std::cout << i << " " << devices[i].name << std::endl;
}
JUCEApplicationBase::getInstance()->systemRequestedQuit();
break;
}
case DEVICE:
{
openInputDevice(cmd.opts_[0]);
break;
}
case DEVICE_INDEX:
{
openInputDeviceByIndex(cmd.opts_[0].getIntValue());
break;
}
case VIRTUAL:
{
#if (JUCE_LINUX || JUCE_MAC)
Expand Down Expand Up @@ -697,6 +796,11 @@ void ApplicationState::executeCommand(ApplicationCommand& cmd)
midiPass_ = openOutputDevice(cmd.opts_[0]);
break;
}
case PASSTHROUGH_INDEX:
{
midiPass_ = openOutputDeviceByIndex(cmd.opts_[0].getIntValue());
break;
}
case TXTFILE:
{
String path(cmd.opts_[0]);
Expand Down
3 changes: 3 additions & 0 deletions Source/ApplicationState.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class ApplicationState : public MidiInputCallback, public Timer
void executeCurrentCommand();
void handleVarArgCommand();
void openInputDevice(const String& name);
void openInputDeviceByIndex(int index);
std::unique_ptr<MidiOutput> openOutputDeviceByIndex(int index);
void parseParameters(StringArray& parameters);
void parseFile(File file);
void handleIncomingMidiMessage(MidiInput*, const MidiMessage& msg) override;
Expand Down Expand Up @@ -87,6 +89,7 @@ class ApplicationState : public MidiInputCallback, public Timer
bool rawdump_;

String midiInName_;
String midiInIdentifier_;
std::unique_ptr<MidiInput> midiIn_;
String fullMidiInName_;

Expand Down