MIDI Player

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. :slight_smile:

Would be a good thing to post on code.tinyclr.com :slight_smile:

Yep :slight_smile:

Ok I added it to tinyclr, I also did another updated on it so if anyone wants to use it, use the version in the link below. :wink:

[url]http://code.tinyclr.com/project/322/midi-reader-library/[/url]

Nice! In your video what is that MIDI application you are using?

The application I’m using is FL studios 9