MIDI-IN questions

According to the 529 page spec I found:

The MIDI spec allows for a MIDI message to be sent without its Status byte (ie, just its
data bytes are sent) as long as the previous, transmitted message had the same Status. This is referred to as running status. Running status is simply a clever scheme to maximize the efficiency of MIDI transmission (by removing extraneous Status bytes). The basic philosophy of running status is that a device must always remember the last Status byte that it received (except for RealTime), and if it doesn't receive a Status byte when expected (on subsequent messages), it should assume that it's dealing with a running status situation.

Note that the only exception is RealTime. However:

Each RealTime Category message (ie, Status of 0xF8 to 0xFF) consists of only 1 byte, the Status. These messages are primarily concerned with timing/syncing functions which means that they must be sent and received at specific times without any delays. Because of this, MIDI allows a RealTime message to be sent at any time, even interspersed within some other MIDI message. For example, a RealTime message could be sent inbetween the two data bytes of a Note On message. A device should always be prepared to handle such a situation; processing the 1 byte RealTime message, and then subsequently resume processing the previously interrupted message as if the RealTime message had never occurred.

So it would appear you are right. Not only do 0xF8 to 0xFF not affect running status, they should be detected (and discarded or whatever) even in between reading other bytes.

Therefore my own MIDI decoder is wrong in that respect (although it worked with the devices I tested it on).

My relevant code was:

// get next byte from serial (blocks)
int getNext ()
  {

  if (lookAhead != noLookAhead)
    {
    int c = lookAhead;
    // finished with look ahead
    lookAhead = noLookAhead;
    return c;
    }
    
  while (midi.available () == 0)
    {}
  return midi.read ();
  }

...

void loop() 
{
  byte c = getNext ();

  if (((c & 0x80) == 0) && (lastCommand & 0x80))
    {
    lookAhead = c;
    c = lastCommand; 
    }
    
  // channel is in low order bits
  int channel = (c & 0x0F) + 1;
  
  // ignore stuff that keeps churning out
  if (c == 0xF8 ||  // timing clock
      c == 0xFE)    // active sensing
    return;  // too much information

However really it should be more like:

void RealTimeMessage (const byte msg)
  {
    
  } // end of RealTimeMessage

// get next byte from serial (blocks)
int getNext ()
  {

  if (lookAhead != noLookAhead)
    {
    int c = lookAhead;
    // finished with look ahead
    lookAhead = noLookAhead;
    return c;
    }
    
  while (true)
    {
    while (midi.available () == 0)
      {}
    byte c = midi.read ();
    if (c >= 0xF8)  // RealTime messages
      RealTimeMessage (c);
    else
      return c;
    }
  } // end of getNext

Then the test for 0xF8 later on could be omitted.

Of course, in the code above the variable "lookAhead" should really be called "runningStatus".