Well some of you may know but I’ve been getting some help from the people on the forum regarding a MIDI player.
Well I got the bugs worked out and figured I would share the class with anyone else that would like some simple code to read MIDI data from the serial port and process it for use my the rest of the program.
As of now the code only recognizes:
NoteON
NoteOff
PitchBend
These are the 3 basics commands and the others could be added easily.
Here is the class:
/* Basic MIDI Reader class
* V1.0
* Eric Goodchild
* ericgoodchild@ gmail.com
*
* This class reads the basic MIDI commands NoteOn, NoteOff, and PitchBend and process them.
* Makeing them availible to the rest of the program.
*/
using System;
using System.IO.Ports;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
namespace FEZ_Panda_Application1
{
static public class MIDI
{
private static SerialPort UART; //Serial port for incoming MIDI data
private static byte[] Sbuffer = new byte[1]; //buffer for incomming data
private static byte data1;
private static byte data2;
private static byte messageType;
private static byte channel;
private static byte[] mPendingMessage = new byte[3];
private static byte buffer = 0;
private static byte mPendingMessageIndex = 0;
private static bool pendingMessage = false;
static public void initialize(string port)
{
//Initialize the serial port and stuff
UART = new SerialPort(port, 31250);
UART.ReadTimeout = 0;
UART.ErrorReceived += new SerialErrorReceivedEventHandler(UART_ErrorReceived);
UART.Open();
}
static private void UART_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
{
Debug.Print("COM Error: " + e.EventType.ToString());
}
static public bool read()
{
byte message = 0;
//check if buffer is full
if (UART.BytesToRead >= 128)
{
UART.Flush();
}
//Check if the buffer is empty
if (UART.BytesToRead <= 0)
{
return false;
}
else
{
UART.Read(Sbuffer, 0, 1); //read a byte from the buffer
buffer = Sbuffer[0];
//check if current byte is a statis byte and also if we are already working on a message
if (buffer >= 128 && !pendingMessage)
{
//if a statis byte is found start a new message
pendingMessage = true;
mPendingMessage[mPendingMessageIndex] = buffer;
mPendingMessageIndex++; //update the index
return read();
}
//add more data to an already started message
else if (pendingMessage)
{
//get the next byte of the message
mPendingMessage[mPendingMessageIndex] = buffer;
//check if we have all 3 bytes of the message
if (mPendingMessageIndex == 2)
{
pendingMessage = false;
mPendingMessageIndex = 0;
//now extract channel and message type
message = (byte)(mPendingMessage[0] >> 4); //get high nibble (message type)
channel = (byte)(mPendingMessage[0] & 15); //get low nibble (MIDI channel);
channel++;
//sort all the data into it's correct locations so it can be used outside of the MIDI class
messageType = message;
data1 = mPendingMessage[1];
data2 = mPendingMessage[2];
return true; //tell the rest of the program that there is data ready to us
}
else
{
//we don't have all the bytes yet
mPendingMessageIndex++; //update the message index
return read();
}
}
}
return false; //this should never be called but is needed to shut the compiler up
}
static public byte getType()
{
return messageType; //return message type
}
static public byte getData1()
{
return data1; //return data1
}
static public byte getData2()
{
return data2; //return data2
}
static public byte getChannel()
{
return channel; //return MIDI channel
}
}
}
Also a simple application I used to test it.
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.Hardware;
using GHIElectronics.NETMF.FEZ;
namespace FEZ_Panda_Application1
{
public class Program
{
private enum MIDItype
{
NoteOn = 9,
NoteOff = 8,
PitchBend = 14
}
public static void Main()
{
MIDI.initialize("COM1");
while (true)
{
if (MIDI.read())
{
switch (MIDI.getType())
{
case (byte)MIDItype.NoteOn:
Debug.Print("NoteOn CH: " + MIDI.getChannel() + " Data1: " + MIDI.getData1() + " Data2: " + MIDI.getData2());
break;
case (byte)MIDItype.NoteOff:
Debug.Print("NoteOff CH: " + MIDI.getChannel() + " Data1: " + MIDI.getData1() + " Data2: " + MIDI.getData2());
break;
case (byte)MIDItype.PitchBend:
Debug.Print("PitchBend CH: " + MIDI.getChannel() + " Data1: " + MIDI.getData1() + " Data2: " + MIDI.getData2());
break;
}
}
}
}
}
}
Any comments or suggestions are greatly appreciated.