Subject: Re: retry: NetBSD umidi driver shuns M-Audio / Midiman Midisport 2x4
To: tech-kern <tech-kern@NetBSD.org>
From: Chapman Flack <flack@cerias.purdue.edu>
List: tech-kern
Date: 09/02/2004 11:30:57
On 2 Sep 2004 Clemens Ladisch furnished exactly the information I needed :)

> MidiSport devices don't use the standard protocol, but it's very
> similar -- they use 4-byte packets, too, but the control byte is the
> last byte (instead of the first) and contains the number of data bytes
> (instead of the CIN) in the lower nibble.  See the functions
> snd_usbmidi_convert_to_midiman() and snd_usbmidi_in_midiman_complete()
> in the Linux driver.
> 
>  * There is one interrupt input endpoint for all input ports, one
>  * bulk output endpoint for even-numbered ports, and one for odd-
>  * numbered ports.  Both bulk output endpoints have corresponding
>  * input bulk endpoints (at indices 1 and 3) which aren't used.

Thank you Clemens!  I actually got it working last night (by finding the
linux driver with google and extracting the ideas from the code) but it's
good to see your message and confirm I understood correctly.  Oddly, the
version of the linux driver google found for me didn't seem to have the
helpful comment you reproduced above, but it was easy enough to see what
the code was doing.

I was able to express the endpoint assignments in terms of the existing
FIXED_EP quirk, and I added a separate MIDIMAN_GARBLE quirk for the
packet format.  The last bit of fun was that umidi expected bulk input
endpoints and explicitly rejected an interrupt endpoint, but the basic
logic seems usable with either kind; I just took out the test that rejected
an interrupt endpoint, and tweaked the very few other places in the code
that noticed the difference.

Also corrected a panic if a mididev's first open for writing is followed by
a close without writing anything, and a sign extension in passing a received
(signed) char to the int parameter of midi_in() which meant no received midi
command could ever possibly match the cases in midi_in's state machine - I
wonder how that ever passed any testing unless in somebody's toolchain
default char is unsigned.  :/

I'll send-pr as soon as my eyes uncross.

Testing with cat -u </dev/rmidiX >/dev/rmidiY as shown in the midi man page,
keyboard set for local off, bits can be lost when playing block chords on
keyboard - many near simultaneous attacks and releases.  The worst part
is, extraneous very high notes are heard, which suggests to me individual
bytes are being dropped, creating bogus packets.  I doubt this is any fault
of the Midisport and I mostly suspect the incredible overhead in the input
side of umidi->midi, where nice packetized commands are received from the
Midisport (but in reads no larger than the bare minimum) and passed up to
midi with *one function call per byte*, where the first thing midi does
is push them through a state machine to repacketize them.  Yuck.  But I
have to confirm whether I'm right about where the bottleneck is, and that'll
happen some other day.  Meanwhile output-playing seems to work fine, and
input works ok in less-demanding cases.

Also discovered the state machine in midi (not umidi) deliberately and
brazenly throws away all system exclusive messages - anything between
F0 and F7 just goes straight to the bit bucket.  So much for being able
to use this interface to receive bulk uploads from a keyboard ... probably
easier in the short run to disable umidi and write a userland program that
opens ugen.

-Chap


> All USB MIDI devices from ESI and Evolution, and at least some from
> Behringer, are fully audio class compliant.

Very good to know.