Well I was here once before and I’m back again this time with a new problem. Basically what I’m doing if feeding the Panda MIDI data from a computer to COM1. The Panda is then supported to process the data and play a square wave out of DIO2 corresponding to the freq of the MIDI note it was sent.
Basically a MIDI synthesizer/player, very simple at this point.
Now my current code works but it’s slow… If I give it a bunch of notes to process at once it misses notes and trips up. I had a similar peace of software running on an 8 bit 16MHz AVR for a long time and it out performs the 72MHZ 32 bit ARM by about double!
My question is can some one give some pointer on how to speed up the code. currently it only has 2 threads, one for processing the incoming serial data and another for playing square wave.
Any help would be a big help thanks,
My code:
MIDI class:
using System;
using System.IO.Ports;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
namespace FEZ_Panda_MIDI
{
static public class MIDI
{
private static SerialPort UART; //Serial port for incoming MIDI data
private static byte[] buffer = new byte[200]; //buffer for incomming data
private static byte[] data1 = new byte[16];
private static byte[] data2 = new byte[16];
private static string[] messageType = new string[16];
private static int newData = 0;
static public void Initialize(string port)
{
//Initialize the serial port and stuff
Thread ProcData = new Thread(processData);
ProcData.Start();
UART = new SerialPort(port, 31250);
UART.ReadTimeout = 0;
UART.ErrorReceived += new SerialErrorReceivedEventHandler(UART_ErrorReceived);
UART.Open();
UART.DataReceived += new SerialDataReceivedEventHandler(UART_DataReceived);
}
static private void UART_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
{
Debug.Print("COM Error: " + e.EventType.ToString());
}
static private void UART_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
newData = UART.Read(buffer, 0, buffer.Length); //Reda the data from the port
}
static private void processData()
{
int dataReceived;
int bufferIndex = 0;
byte message;
byte channel;
while (true)
{
dataReceived = newData;
newData = 0;
if (dataReceived != 0)
{
//loop through all of the data in the buffer
for (bufferIndex = 0; bufferIndex < dataReceived; bufferIndex++)
{
//check is current byte is a statis byte
if (buffer[bufferIndex] >= 128)
{
message = (byte)(buffer[bufferIndex] >> 4); //get high nibble (message type)
channel = (byte)(buffer[bufferIndex] & 15); //get low nibble (MIDI channel);
switch (message)
{
case 8: //Note off event
messageType[channel] = "NoteOff";
data1[channel] = buffer[bufferIndex + 1];
data2[channel] = buffer[bufferIndex + 2];
break;
case 9: //Note on event
//if the volocity is 0 treat it as a NoteOff
if (buffer[bufferIndex + 2] > 0)
{
messageType[channel] = "NoteOn";
}
else
{
messageType[channel] = "NoteOff";
}
data1[channel] = buffer[bufferIndex + 1];
data2[channel] = buffer[bufferIndex + 2];
break;
case 14: //pitch bend event
messageType[channel] = "PitchBend";
data1[channel] = buffer[bufferIndex + 1];
data2[channel] = buffer[bufferIndex + 2];
break;
}
}
}
}
}
}
static public string getType(byte channel)
{
return messageType[channel - 1];
}
static public byte getData1(byte channel)
{
return data1[channel - 1];
}
static public byte getData2(byte channel)
{
return data2[channel - 1];
}
}
}
Square wave playing class:
using System;
using System.Threading;
using System.IO.Ports;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.Hardware;
using GHIElectronics.NETMF.FEZ;
namespace FEZ_Panda_MIDI
{
class DRMIDI
{
OutputPort led;
private OutputCompare OC;
private Thread DRthread;
private byte Channel = 1;
private byte maxLimit = 127;
private byte minLimit = 0;
private string type = "";
private byte data1 = 0;
private byte data2 = 0;
private uint[] timing = new uint[2];
public void Initialize(FEZ_Pin.Digital pinNumber, byte Channel)
{
//Setup output compare and new thread
OC = new OutputCompare((Cpu.Pin)pinNumber, false, 2);
led = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, false);
DRthread = new Thread(run);
}
public void start()
{
//Start the thread for first time
if(DRthread.ThreadState == ThreadState.Unstarted)
DRthread.Start();
//Restart thread
if (DRthread.ThreadState == ThreadState.Suspended)
DRthread.Resume();
}
public void stop()
{
//disable the thread
if (DRthread.ThreadState == ThreadState.Running)
{
DRthread.Suspend();
OC.Set(false);
}
}
public void kill()
{
//kill the thread and take out the trash
DRthread.Abort();
OC.Set(false);
OC.Dispose();
}
public void run()
{
while (true)
{
//if the message is exatly the same as the previos then ignore it.
if (type == MIDI.getType(Channel) && data1 == MIDI.getData1(Channel) && data2 == MIDI.getData2(Channel))
{
//do nothing
}
else
{
type = MIDI.getType(Channel);
data1 = MIDI.getData1(Channel);
data2 = MIDI.getData2(Channel);
//Check which event has happened and take action
switch (type)
{
case "NoteOn":
playNote(data1);
break;
case "NoteOff":
stopNote(data1);
break;
case "PitchBend":
pitchBend(data1, data2);
break;
}
}
}
}
private void playNote(byte note)
{
int frequancy; //nore frequancy in Hz
int period; //period in uS
int onTime = 500; //on time in uS
int offTime;
//calculate the period of the note
frequancy = (int)(System.Math.Pow(2.0, ((float)(note - 57) / 12.0)) * 440.0);
period = (int)(1000000.0 * (1.0 / (float)frequancy));
offTime = period - onTime;
timing[0] = (uint)offTime;
timing[1] = (uint)onTime;
OC.Set(false, timing, 0, 2, true);
led.Write(true);
}
private void stopNote(byte note)
{
OC.Set(false);
led.Write(false);
}
private void pitchBend(byte MSB, byte LSB)
{
Debug.Print("Bending");
}
}
}
Main thread
using System;
using System.Threading;
using System.IO.Ports;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.Hardware;
using GHIElectronics.NETMF.FEZ;
namespace FEZ_Panda_MIDI
{
public class Program
{
public static void Main()
{
DRMIDI DRMIDI1 = new DRMIDI();
MIDI.Initialize("COM1");
DRMIDI1.Initialize(FEZ_Pin.Digital.Di2, 1);
DRMIDI1.start();
while (true)
{
}
}
public static void play(byte note)
{
}
public static void stop(byte note)
{
}
}
}