I've been working on a largish increment in MIDI support for NetBSD.
I notice in OpenBSD manpages that the MIDI support there is derived
from older NetBSD code, and from FreeBSD archives that the support
there is in a sort of indeterminate state at the moment. So you might
find the NetBSD patches to be of interest. I have not yet had the
chance to patch the manpages and improve the documentation (that's
in the works), but you can get an idea what's developing (and links
to the patches so far) from the relevant NetBSD PRs:
i don't understand completely the new cable number quirks; you say that the
midiman 2x4 have 4 jacks, that can be written (arbitrary?) on 2 endpoints.
Isn't this specified in any descriptors?
i really like your path to improve the umidi(4) transmit output throughput,
i'll try it soon on openbsd;
last year, there have been changes in the midi(4) driver of openbsd. In
order to fix similar problems, openbsd used a very simple approach:
currently, the midi(4) driver parses data as-is to the user-land, supposing
that the user application have to decode (and thus to check for
inconsistencies) the input stream. Inside the kernel, input midi stream is
parsed only if the sequencer is opened and output stream is parsed in the
umidi(4) driver in order to build packets.
Alexandre Ratchov wrote:
> i don't understand completely the new cable number quirks; you say that the
> midiman 2x4 have 4 jacks, that can be written (arbitrary?) on 2 endpoints.
> Isn't this specified in any descriptors?
For devices that conform to the actual "USB Device Class Specification
for MIDI Devices," there are indeed endpoint and jack descriptors that
can be retrieved from the device that completely specify how it should
be used. The Midisport 2x4 is an example of a device that is marketed
as a MIDI adapter for USB, but it does not conform to the USB MIDI spec,
does not identify itself as UISUBCLASS_MIDISTREAM, and does not supply
standard descriptors that specify the jack mappings. It has a generic
USB interface descriptor so you can learn it has five endpoints, at
addrs 2, 4, 81, 82, and 84, but as for what those endpoints are for,
well, that just has to be known to the driver by entries in the quirk
table. As it turns out, the output ports are split even/odd between
endpoints 2 and 4, all data from both input ports appears on endpoint
81, and I haven't the foggiest idea what 82 and 84 are meant for. :)
The other weird thing about this device is that you can send data for
any of the four output ports to either endpoint 2 or 4 and the data
will go to the right port regardless ... but if you're not using the
designed endpoint for that port, flow control doesn't work.
Of course this device is just one example of a nonstandard USB MIDI
device; other devices if nonstandard could be arbitrarily different,
and the current quirk macros are just what's sufficient to handle
the currently supported quirky devices.
> currently, the midi(4) driver parses data as-is to the user-land, supposing
> that the user application have to decode (and thus to check for
> inconsistencies) the input stream. Inside the kernel, input midi stream is
> parsed only if the sequencer is opened and output stream is parsed in the
> umidi(4) driver in order to build packets.
As you can see, I've taken the approach of concentrating the midi parsing
in midi(4) and removing it from umidi(4) and the sequencer, and providing
some guarantees that can simplify the user application as well. Though
the MIDI protocol is pretty simple, the special cases for running status,
system common and realtime messages, and note-on/note-off equivalence
make it just tricky enough that incomplete/incorrect implementations are
common (for example, the state machine in umidi would build incorrect
packets if a realtime message appeared interleaved with a longer message).
So it seemed a good idea to centralize that functionality. It's now done
in a finite state machine with 20 states, only 3 bytes of side storage,
and very few loads/stores/compares on most paths, so the cost of doing
it in kernel is quite small. A benefit for the user application is that
all reads from the rmidi device are in canonicalized form, realtime
messages cannot appear within other messages (except sysex) and as long
as the read request is big enough for at least one complete message,
every read will end at a message boundary so the user app does not need
to parse across read buffers. This will not adversely affect applications
that already do such processing, but can be less likely to expose bugs
Protocol errors found by the state machine are counted using event
counters (readable with vmstat -e) - on the input side that can be
quite useful in diagnosing either electrically poor connections, or
faulty low-level drivers. On the output side, write(2) will return
an error if invalid MIDI is written - this may expose bugs in
applications that generate MIDI streams, but that's the idea.
Another reason for centralizing the message assembly and moving it
out of umidi(4) is that other transports for MIDI over other media
are being defined, such as MIDI over 1394, and they will be likely
to need the same functionality.