MIDI with Lumps

Thomas Hudson thudson at cygnus.com
Sat Mar 27 19:25:15 CET 1999


The Dark force of dance wrote:
> 
> So that only leaves my crappy software. I'll have to re-write it. You see I
> was trying to be smart. What I figured was that instead of dealing with
> each byte as they came in, I could stuff them all in a buffer, wait till
> there was 3 or more bytes in the buffer and then go hunting for a  #B0H.
> Finding a B0 would then mean that there would be 2 more bytes containing
> data and they could all be processed at the same time. 

Except that a system realtime message can interrupt any other message without
reseting running status. Also, if the previous message was #B0H, the status
byte won't be resent.

I have some C++ code I've been working on for parsing a midi stream. The
"Spray'something'" calls simply deliver each type of message on to whatever
wants to process them. This is only the parser method. If you need the
entire class let me know. You may be able to adapt this:


void MidiParser::parseMidi()
{
  uchar next = readByte();
  if (isStatus(next))
    {
      // If we receive a system realtime, we process immediately and
      // then continue with out normally scheduled programming
      if (isSystemRealTime(next))
	SpraySystemRealTime(next,NOW);

      // Set the sysex flag to start saving data bytes.
      else if (isSystemExclusive(next))
	_in_sysex = true;

      // Any other channelized status byte
      else
	{
	  // Receiving any status byte other than SysRealTime terminates
	  // a System Exclusive message
	  if (_in_sysex)
	    SpraySystemExclusive(_sysex_buf,_data_count);
	  
	  _running_status = next & 0xf0; // Strip off channel
	  _channel = next & 0x0f; // Save channel here
	  _data_count = 0; // Reset data count
	}
    }
  else // data byte
    {
      if (_in_sysex)
	{
	  if (_sysex_size == _data_count)
	    {
	      _sysex_size *= 2;
	      _sysex_buf = (uchar*)realloc(_sysex_buf,_sysex_size);
	    }
	  _sysex_buf[_data_count++] = next;
	}
      else
	{
	  // Add data byte to buffer and check counts for each message type
	  _data_buf[_data_count++] = next;
	  
	  switch (_running_status)
	    {
	    case NOTE_ON:
	      if (_data_count == 2)
		{
		  SprayNoteOn(_channel,_data_buf[0],_data_buf[1]);
		  _data_count = 0;
		}
	      break;
	      
	    case NOTE_OFF:
	      if (_data_count == 2)
		{
		  SprayNoteOff(_channel,_data_buf[0],_data_buf[1]);
		  _data_count = 0;
		}
	      break;
	      
	    case KEY_PRESSURE:
	      if (_data_count == 2)
		{
		  SprayKeyPressure(_channel,_data_buf[0],_data_buf[1]);
		  _data_count = 0;
		}
	      break;
	      
	    case CONTROL_CHANGE:
	      if (_data_count == 2)
		{
		  SprayControlChange(_channel,_data_buf[0],_data_buf[1]);
		  _data_count = 0;
		}
	      break;
	      
	    case PROGRAM_CHANGE:
	      if (_data_count == 1)
		{
		  SprayProgramChange(_channel,_data_buf[0]);
		  _data_count = 0;
		}
	      break;
	      
	    case CHANNEL_PRESSURE:
	      if (_data_count == 1)
		{
		  SprayChannelPressure(_channel,_data_buf[0]);
		  _data_count = 0;
		}
	      break;
	      
	    case PITCH_BEND:
	      if (_data_count == 2)
		{
		  SprayPitchBend(_channel,_data_buf[0],_data_buf[1]);
		  _data_count = 0;
		}
	      break;
	      
	    case SYSTEM_COMMON:	
	      if (_data_count  == 2)
		{
		  SpraySystemCommon(_running_status & _channel, _data_buf[0],_data_buf[2]);
		  _data_count = 0;
		  _running_status = 0;
		}
	      break;

	    default: // shouldn't get here
	      cout << "Status = " << _running_status; << endl;
	      for (int i = 0; i < _data_count; ++i)
		cout << " data[" << i << "] = " << _data_buf[i] << endl;
		  
	      break;
	    }
	}
    }
}

Hope this helps.

Thomas



More information about the Synth-diy mailing list