The firmware consists of mainly three parts
The firmware does a little blinking with the LEDs, but this is an item aside.
The description is covered in all its details in the appendix of the USB-MIDI specification. There are only minor modification of this descriptor:
As usual for the Audio Class, logical wires are exposed in the descriptor. See the figure below for a visualization of the class specific interface and class specific endpoint descriptors:
USB-MIDI specifies a form of packaging, that requieres stream parsing. The following document goes through the process of transforming from midi to usb-midi format, starting with a description of the midi format, to which we cannot give reference.
Authorized information about the Midi format is not freely available, this summary is based on material collected from the net. So the format described here may or may not be Midi, but it is definitely the format on which the parsing algorithm of the firmware is based.
Since the firmware does not have to interprete the stream beyond separating the messages, the parameter meanings are not detailed.
Find authorized information at <http://www.midi.org> while having your credit card available. Find authorized information about the usb-midi format at <http://www.usb.org>.
A Midi stream is a concatenation of individual messages, which are intrinsically self-separating by design. The framing of the midi stream is done distinguising octets into two classes by their most significant bit.
Data Byte: 0x00 .. 0x7f Cntl Byte: 0x80 .. 0xff
Control bytes always start a new message while the following data bytes belongs to them. An exception are the control bytes of Real Time Messages, which can be inserted freely everywhere, even inside other messages, without effect on the context.
Control { Data }
Trailing data bytes are ignored as well as those at the start of the stream. Messages with an insufficent number of data byte are ignored either.
These messages use "running status", i.e. additinal corresponding data bytes may follow without the introducing control byte.
8c {nn vv} Note Off (nn=Pitch, vv=Velocity) 9c {nn vv} Note On (nn=Pitch, vv=Velocity) Ac {nn vv} Key Pressure (nn=Pitch, vv=Pressure) Bc {nn vv} Parameter (nn=Parameter, vv=Setting) Cc {pp} Program (pp=Program) Dc {pp} Ch. Pressure (pp=Pressure) Ec {aa bb} Pitch Wheel (aabb=Value, 14bit, lsb first)
The lower nibble (c) contains the channel number.
Note on with velocity zero means note off.
USB-MIDI requieres to insert the control bytes omitted by the "running status" preceeding their data.
F1 pn MTC Midi Time Code (p=Part, n=Nibble) F2 aa bb Song position (14 bit value, lsb first) F3 nn Song select (nn = song number) <F4> - undefined - <F5> - undefined - F6 tune request F7 EOX (optional terminator for system exclusive messages)
The EOX message is only transmitted if immediately following (i.e. "terminating") a System Exclusive Message. It is undefined else.
These are messages only meaningful to particular devices. They should be ignored by others. To this end, the first byte in the body, if any, is a vendor id. Some vendor ids are used for midi extensions, too.
F0 {dd} [F7] variable number of data
Though the terminating F7 is optionally by design and early specification, each system exclusive message has to be followed by a F7 system common message, now. It has to be appended even if the originating device does not produce it.
They may be inserted anywhere, even inside other messages, and do not effect "running status", there.
F8 timing clock <F9> - undefined - FA start FB continue FC stop <FD> - undefined - FE active sensing FF system reset
The system reset message should not be send on power on.
USB-MIDI requieres to reorder the Real Time Messages occuring within other messages.
The USB-MIDI first inserts the omitted control byte in all running status message. Further an F7 message is inserted after the last data byte of a system explicit message, if not already present in the stream. It is further considered part of the messages data, and not treated as a control byte anymore.
The messages are then separated and eventually split into parts of at most three bytes. From length and content of these blocks a four bit code index number (cin) is then derived and added together with a cable number as the first byte to each block.
One can derive the block length from then cin, so at this point it is save to extend the blocks by appending zero bytes to become packages of four byte length each.
Since the cin does not add a single bit of information to the content beside the number of inserted zero bytes, it can be droped after their removal. The parsing is then undone by concatenating the parts to form the midi stream. Because the stream was modified for USB-MIDI inserting the running status bytes here is the place to omit them, hoping to gain the original stream again.
To summarize the possible modifications of the stream:
The USB-MIDI specification allows to send raw midi bytes, one per pack, using cin F in cases one wants a preserved stream content.