Addendum to MIDI lab (Lab #9) CS150 / spring 2000 ----------------------------- Eylon Caspi To support a larger variety of MIDI keyboards (our gray ones and yours from home), you will need to extend your MIDI parser to support the "running status" convention. This addendum has been integrated into the check-off for Lab #10 (audio output) and must be completed in Lab #10's time frame. What is "running status?" From "The USENET MIDI Primer", For all of these messages, a convention called the "running status byte" may be used. If the transmitter wishes to send another message of the same type on the same channel, thus the same status byte, the status byte need not be resent. This convention allows a transmitter to compress the data stream by dropping status bytes. A command without a status byte implicitly uses whatever status byte was most recently sent. For example, playing a triad chord (3 notes together) may be encoded as a sequence of note-on commands, only the first of which has a status byte: 1001nnnn 0kkkkkkk 0vvvvvvv 0kkkkkkk 0vvvvvvv 0kkkkkkk 0vvvvvvv ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ (1st note) (2nd note) (3rd note) Similarly, the pressing and releasing of a key may be encoded as a note-on followed by a note-on with 0-volume and no status byte: 1001nnnn 0kkkkkkk 0vvvvvvv 0kkkkkkk 00000000 ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ (key press) (release) To support running status, your MIDI parser must be extended to do the following: (1) remember the most recent status byte (store in a register). (2) process a command beginning with a data byte if the most recent status byte was a note-on or note-off (3) ignore a command beginning with a data byte if the most recent status byte was not a note-on or note-off. If your parser was designed as a traditional state machine then the addition of running-status is relatively simple. You probably have a starting state which begins processing a command when it receives a note-on or note-off status byte. That state must now also respond to a data byte, either jumping ahead to process the new command (case (2) above) or ignoring the byte (case (3) above). If your parser is not a traditional FSM, you may need to be more ingenious. Alternatively, you may find it easier to just redesign the parser as an FSM. Status and data bytes are easy to differentiate. Status bytes have an MSB (most significant bit) of 1, while data bytes have an MSB of 0. There is one additional complication of which you should be aware but which we will handle for you. This is the "real-time messages," a collection of single-byte messages which may appear in the middle of other messages. Since we plan to ignore such messages, the easiest way to deal with them is to filter them out of the MIDI byte stream before they reach the parser. The parser can then remain blissfully unaware of pesky real-time messages. A Xilinx schematic to filter real-time messages will be provided in "U:\WVLIB\CS150\LAB9MIDI\". To use it, make yourself a copy of that directory, attach its library to your project, and connect the "RTFILTER" library component between your UART and MIDI parser (note, this filter delays the UART's DRDY and D[7:0] outputs by one 8MHz cycle; if your parser absolutely depends on UART output being synchronized with the 31.25kHz clock, use the "no delay" version "RTFILTND" instead). Of course, you are free to avoid the provided schematic and instead to modify your parser to ignore real-time messages. You might even save some area. From "The USENET MIDI Primer", REAL TIME MESSAGES. This is the final group of status bytes, 0xf8 - 0xff. These bytes are reserved for messages which are called "real-time" messages because they are allowed to be sent ANYPLACE. This includes in between data bytes of other messages. A receiver is supposed to be able to receive and process (or ignore) these messages and resume collection of the remaining data bytes for the message which was in progress. Realtime messages do not affect the "running status byte" which might be in effect. ? Do any devices REALLY insert these things in the middle of other messages? All of these messages have no data bytes following (or they could get interrupted themselves, obviously). The messages: 0xf8 timing clock 0xf9 undefined 0xfa start 0xfb continue 0xfc stop 0xfd undefined 0xfe active sensing 0xff system reset The above description suggests that the following are all valid ways to transmit note-on messages interspersed with "active sensing" bytes: (status 0xFE) 1001nnnn [0xFE] 0kkkkkkk 0vvvvvvv 1001nnnn 0kkkkkkk [0xFE] 0vvvvvvv 1001nnnn 0kkkkkkk 0vvvvvvv [0xFE] 0kkkkkkk 0vvvvvvv Note the use of running status in the last example. Your project needs to know about real-time messages for two reasons. First, many MIDI keyboards, including our gray ones, send periodic "active sensing" messages (status 0xFE). Second, MIDI sequencers, which play-back pre-recorded music, send timing messages (status 0xF8,0xFA,0xFB,0xFC). We may use a sequencer later in the semester to test your project with a pre-recorded MIDI message stream. Although your project needs to implement only the note-on and note-off commands, it must be smart enough to not be confused by real-time messages.