Virtual Ports with node-midi

Hi, I’d like to setup more virtual ports, like the touchosc and midi-through ports, if possible in realtime. I’ve built a nodejs stepsequencer application that sends midi via node-midi and rtmidi to the touchosc or midi-through ports in modep. This just works fine, touchosc and midi-through showed up in the list of available midi ports.

I have 2 questions:

  1. With node-midi you can open virtual ports like this:
const midi = require('midi');
const input = new midi.Input();
input.openVirtualPort("PORT 1");
const output = new midi.Output();
output.openVirtualPort("PORT 1");

These ports show up in aconnect -loi:

patch@patchbox:~ $ aconnect -loi
client 0: 'System' [type=Kernel]
    0 'Timer           '
    1 'Announce        '
	Connecting To: 146:0
client 14: 'Midi Through' [type=Kernel]
    0 'Midi Through Port-0'
	Connecting To: 146:0[real:8], 135:0
	Connected From: 146:0, 136:0[real:0]
client 20: 'FL STUDIO FIRE' [type=Kernel,card=1]
    0 'FL STUDIO FIRE MIDI 1'
	Connecting To: 146:0[real:8], 137:0
	Connected From: 146:0, 138:0[real:0]
client 28: 'pisound' [type=Kernel,card=3]
    0 'pisound MIDI PS-0BDMMR3'
	Connecting To: 146:0[real:8], 139:0
	Connected From: 146:0, 140:0[real:0]
client 128: 'touchosc' [type=User,pid=485]
    0 'touchosc        '
	Connecting To: 146:0[real:8], 141:0
	Connected From: 146:0, 142:0[real:0]
client 131: 'RtMidi Input Client' [type=User,pid=1624]
    0 'PORT 1          '
	Connected From: 146:0
client 132: 'RtMidi Output Client' [type=User,pid=1624]
    0 'PORT 1          '
	Connecting To: 146:0[real:8]
client 133: 'RtMidi Input Client' [type=User,pid=1624]
    0 'PORT 2          '
	Connected From: 146:0
client 134: 'RtMidi Output Client' [type=User,pid=1624]
    0 'PORT 2          '
	Connecting To: 146:0[real:8]

But they don’t show up in modep’s list of available midi ports. I tried to connect ports with aconnect x:0 y:0 but this didn’t work, at least the way I did it.

Can someone help me to solve this?

  1. How to setup ports like the midi-through one that you implemented?

Thanks,
Jean

The MOD software ignores non-hardware MIDI ports. Fortunately, when creating a new ALSA virtual MIDI port, you may specify the ‘Hardware’ flag, so it shows up in MOD. We’ve wrote a tiny utility just for this purpose called amidithru, it should already be available on your system. :slight_smile:

Here’s how touchosc2midi is implemented, so it appears in MOD UI:

https://github.com/BlokasLabs/modep-touchosc2midi/tree/master

Yes, thanks a lot! amidithru creates midi ports that are visible in both, modep and node-midi.

amidithru 'MIDI 1'

This results in:

client 129: 'MIDI 1' [type=User,pid=497]
    0 'MIDI 1          '
	Connecting To: 137:0[real:0]
	Connected From: 137:0

In node-midi the virtual ports are recognized as hardware ports and now have to be opened with a port number.

const input = new midi.Input();
input.openPort([PORT_NUMBER]);

I’ll wrap this to nodejs so i can execute amidithru in realtime.

For now, having 8 virtual ports (MIDI 1, MIDI 2, … , MIDI 8) showing up in MOD UI. I was expecting them to be listed in alphabetic order form MIDI 1 to MIDI 8, but in MOD UI they are listed randomly. On boot I’m calling 8 services like /etc/systemd/system/virtual-midi-port-[PORT_NUMBER].service:

[Unit]
Description=amidithru service for virtual midi port
After=sound.target
Wants=sound.target

[Service]
ExecStart=/usr/bin/amidithru 'MIDI [PORT_NUMBER]'
User=patch
Group=patch
Restart=always
RestartSec=2

[Install]
WantedBy=multi-user.target
systemctl enable virtual-midi-port-1 virtual-midi-port-2 virtual-midi-port-3 virtual-midi-port-4 virtual-midi-port-5 virtual-midi-port-6 virtual-midi-port-7 virtual-midi-port-8

Guess this is a first come first serve scenario. Is there a way to to sort those ports alphabetically or by custom index?

1 Like

I wonder if it depends on the order the services are started in. You could try and make service N to depend on service N-1, to keep the order of startup strict.

I think you have to use After= to ensure the other services are fully up before next one is started.

Tried following without success with my 8 service files :

In /etc/systemd/system/virtual-midi-port-[PORT_NUMBER].service :                                                                

[Unit]
Description=amidithru service for virtual midi port
After=sound.target /etc/systemd/system/virtual-midi-port-[PORT_NUMBER - 1].service
Wants=sound.target

[Service]
ExecStart=/usr/bin/amidithru 'MIDI [PORT_NUMBER]'
User=patch
Group=patch
Restart=always
RestartSec=2

[Install]
WantedBy=multi-user.target

Not sure if I’m calling it right like this:
After=sound.target /etc/systemd/system/virtual-midi-port-[PORT_NUMBER - 1].service

Port index/position might just not be related to the boot order. I’ll investigate this :male_detective:

@Giedrius Thanks a lot!

I see MOD UI sorts the MIDI devices list here:

You may try to figure out the logic there, and adapt to it, or try to modify the sorting logic to your needs.

I think you may be able to find host.py somewhere in /usr/ and edit it. Restarting modep-mod-ui service would probably be necessary for changes to take effect.

@Giedrius thanks! Sorting in /usr/lib/python3/dist-packages/mod/host.py only affected the ports list (the one with with the checkboxes). But it pointed to the right api for jack :nerd_face:

Sorting hardware ports directly at the source in /usr/lib/python3/dist-packages/modtools/utils.py. Change the get_jack_hardware_ports def to:

def get_jack_hardware_ports(isAudio, isOutput):
    port_data = charPtrPtrToStringList(utils.get_jack_hardware_ports(isAudio, isOutput))
    sorted = {}
    sorting = []
    ports = []
    for port_id in port_data:
      port_alias = get_jack_port_alias(port_id)
      sorted[port_alias] = port_id
      sorting.append(port_alias)
    sorting.sort()
    for port_alias in sorting:
      ports.append(sorted[port_alias])
    return ports

Still have to find a solution for the ajax part after clicking save in the ports list. Not sure from where it gets the ports data for updating the pedalboard gui. Unluckily, not from get_jack_hardware_ports. I’ll post it here.

For now it sorts hardware ports alphabetically on load, both, the graphical input/output ports and the ports list with checkboxes.

1 Like

Opened a new thread for the solved sorting part under: Sort Hardwareports by Alphanumerical Order

1 Like

Here the nodejs wrapper for amidithru. No need for the systemctl part as before. This directly works in realtime, both, in modep and nodejs:

const {exec} = require("child_process");
addVirtualPort(name, onport){
  exec("amidithru '" + name + "'", onport);
}
 addVirtualPort("MY MIDI PORT 1", (err)=>{console.log(err)});
1 Like