On Mon, 2020-03-16 at 13:03 +0100, Clemens Ladisch wrote:
Andreas Steinmetz wrote:
the snd_usbmidi_transmit_byte helper had to be converted to return output notification to allow for the 'repeat' shortcut.
Why not simply handle one MIDI byte per port in each iteration? It could be argued that single-byte MIDI commands are likely to be real- time messages and deserve to go first.
Actually the patch does exactly this. As soon as the helper signals that a message is complete the next port is processed. The "repeat" loop is just necessary to get a complete class compliant message for transfer as the helper processes one byte at a time. The range optimization is there to prevent O(2) performance cost if possible.
Current multi port MIDI interfaces do typically have 2^n output ports and 2^x as wMaxPacketSize where x>n.
The USB specification requires bulk endpoints to have a wMaxPacketSize value of 8/16/32/64 for full speed, or exactly 512 for high speed.
For the patch to properly work the wMaxPacketSize of the device must be large enough to allow for at least one MIDI event per port in a URB.
There are devices that handle only the first four bytes of a received packet (because Windows used to send only small packets), and one of them, the ESI M4U, actually has more than one port.
Again no problem as the patch is designed to prefer quirks over user settings to prevent malfunctioning devices. Quirk processing and thus size restrictions are processed after user selection.
My original idea for that FIXME was to use round robin until the packet is filled (or all ports are empty), and to store the next port index (where to start for the next packet) in the endpoint. This would be able to distribute the balancing over multiple packets.
The problem with "round robin until the packet is filled" is that in case of a large wMaxPacketSize there's then a huge latency. I just got for further internal testing an USB3 8x8 interface that uses a wMaxPacketSize of 512. In such a case a port doing a sysex transfer will delay another port then sending a realtime message by a minimum of 123ms per queued URB. Make that 7 URBs and you have a sysex queue of 860ms until the realtime message can be transmitted.
Regards, Clemens