midir icon indicating copy to clipboard operation
midir copied to clipboard

Long port names on Linux

Open sourcebox opened this issue 2 years ago • 2 comments

When using Linux, the returned port name is much longer than with Windows/macOS. These long names force me to reserve more space in the GUI than needed just because of Linux users, which are a minority.

Example:

  • Windows/macOS: Arturia KeyStep 32
  • Linux: Arturia KeyStep 32:Arturia KeyStep 32 MIDI 1 20:0

It is obvious that the second part "Arturia KeyStep 32 MIDI 1" including the port info needs to be returned, but the first part seems to be redundant. When using amidi --list-devices the result is also "Arturia KeyStep 32 MIDI 1", the so called "client name" is omitted there.

I already thought about manually splitting the parts using the colon as delimiter, but I think the colon is a valid character inside the port name, so this method is not 100% safe, even if I'm not aware of any device that's named in such manner.

sourcebox avatar Apr 17 '22 11:04 sourcebox

It is usually the case that the client name will be contained in the port name, and I agree that this redundancy is bad, but I don't think this will always be the case. E.g. if you open a virtual port, you can give it any name, it doesn't need to contain the client name again. It looks like amidi --list-devices uses the snd_rawmidi API (https://github.com/bear24rw/alsa-utils/blob/2d105e0f18a82783ea69e2dbe9da7aeb7d3c1346/amidi/amidi.c#L139-L155), so I'm not sure how that would behave for such virtual ports. Maybe you could investigate some more? If we could be sure that the port name (as obtained by snd_seq_port_info_get_name) is always sufficient, I'm willing to remove the client name (obtained by snd_seq_client_info_get_name). Some ALSA expertise would be much appreciated.

Boddlnagg avatar Apr 25 '22 17:04 Boddlnagg

I've seen that virtual ports are handled differently. My current strategy is to remove the client part in case that it's identical to the start of the port name. I'm using this somewhat hacky function:

fn cleanup_port_name(port_name: String) -> String {
    #[cfg(target_os = "linux")]
    {
        if let Some((client_name, remainder)) = port_name.split_once(':') {
            if remainder.starts_with(client_name) {
                return remainder.to_owned();
            }
        }
        port_name
    }

    #[cfg(not(target_os = "linux"))]
    port_name
}

If the port name is intended to be shown to end users, it can maybe formatted a bit nicer like putting the client name in brackets (if shown) instead of using colons as delimiters. I guess most end users have no idea what the client name is.

I also thought about an addtional function e.g. port_info() that would return a tuple or struct containing the individual parts like (client_name, port_name, port_no) but this is probably not reasonable because the backends will not all return the same information so it's not cross-platform compatible.

sourcebox avatar Apr 25 '22 21:04 sourcebox