Midi and Timer Interupts

I have trying to create my own midi synth from scratch, I don't want to turn to the library as I want to understand everything that is going on under the hood. I had quite a comprehensive synth coming on, but I've gone right back to basics so I can get everything to work as I desire it to.

The first question is about the midi bytes. I am using my Arturia Minibrute to send midi messages to the arduino and I'm using serial.print to read them. I collect 3 bytes every time and print them, as my understanding is that every action sends 2 or 3 bytes. For some reason, every time I press a key or let go of a key, I get 6 bytes.

If I press and let go of say, middle C, I get these bytes (I've added anotation of the bytes that I understand):

144 // Note ON
255 // ?
255 // ?
60 // Note Number
62 // Velocity
255 // ?

128 // Note Off
255 // ?
255 // ?
60 // Note Number
0 // Velocity
255 // ?

Why on earth am I getting all those "255"'s in the midi data? I wondered if the collection of the serial data was being slow or glitchy, but i have been playing with it for a while, and the bytes are consistently arranged in that order.

Cheers for your help in advance, Pete

Ok, I realise that my second question was more a programming question that an audio one, so I'm going to repost that part there, anyone know why i'm getting the midi data i'm getting?

Pete

No midi wizards out there? ive googled the hell out of this problem andfound nothing. By all accouts i should only recieve 3 bytes of data per command max, not 6.

My only other hope is to email arturia and ask them if this is normal

My guess is that you aren’t reading the Serial port properly but without seeing your code there’s no way to know for sure. Please post it in code tags.

Pete

Ah Pete! You're a sight for sore eyes! This issue has been haunting me for a feww weeks now. Here's the code:

byte incomingByte = 0;                                       // midi related parameters
byte incomingByte1 = 0;
byte incomingByte2 = 0;

void setup()
{
  Serial1.begin(31250);                                      // Start seria1 at midi baude rate
}

void loop()
{
  if (Serial1.available() > 0) 
  {
    incomingByte = Serial1.read();                              // read the incoming midi bytes
    incomingByte1 = Serial1.read();
    incomingByte2 = Serial1.read();
    Serial.println(incomingByte);                               // print the incoming midi bytes
    Serial.println(incomingByte1);
    Serial.println(incomingByte2);
    if (incomingByte == 144)                                    // 144 = channel 1 note on
    {
      Serial.println("On");
    }
    else if (incomingByte == 128)                               // 128 = channel 1 note off
    {
      Serial.println("Off");
    }
    Serial.println();
  }
}

The midi data all comes in the configuration mentioned above aside from it's bundled into groups of 3 and has the words on and off as the code above would sugest. So with the on's and off's included, it looks like this:

144
255
255
On

60
62
255

128
255
255
Off

60
0
255

...besides the odd mistake if lots of midi data comes in really fast. The mistake still shows the same numbers in the same order, but starts the sets of numbers from a different line.

If this condition is true:

  if (Serial1.available() > 0)

it only guarantees you that there is at least one byte ready to be read.
To read three at a time you would need:

  if (Serial1.available() >= 3)

However, the MIDI protocol has messages which aren't 3 bytes long so you could get out of sync with the incoming data.

Pete

However, the MIDI protocol has messages which aren't 3 bytes long so you could get out of sync with the incoming data.

that's a good point! that could explain the mistakes maybe. I'll have to specifically test a load of 2 byte messages to see what happens.

If this condition is true:
Code: [Select]

if (Serial1.available() > 0)

it only guarantees you that there is at least one byte ready to be read.

another fair observation! could this maybe mean that the first byte of data (like the 144 note on or 128 note off byte) comes into the buffer, and the serial available picks it up and reads 3 bytes from the buffer before the second and third midi byte arrive?

if that is the case, it seems odd that the junk bytes are always 255, unless the buffers bits default to 1's? Weird! Anyway, I'll have a play with that aswell. I'm thinking 2 solutions to that would be:

  1. putting a very brief delay/timer between the serial available and the serial read
  2. read and act upon the bytes one at a time, like if i recieve a 144 (note on), then read the next byte to determine which pitch, and once I have processed that read the next byte for velocity etc.

I'll post the outcome.

Cheers for your help man!

Pete

Aha! just found my answer here:

this guys also getting junk 255 bits from the serial buffer. Here's the answer he got:

    if (Serial.available() > 0) {

byte low = Serial.read();
            byte high = Serial.read();
            //...




This is a bug in your code. Very likely to trip, serial ports are not that fast. So high odds that Serial.available() only returns 1. You'll read the low byte okay but Serial.read() will then return -1 if there is no data to read. Which makes high equal to 0xff. The simple fix is:


if (Serial.available() >= 2)

So it's cos each empty byte is set to -1 that you get the 255.

Again, thanks for your help Pete!

Pete

Ok, so I have finally got this working! I would of got it working sooner, but it seems I've fried the RX1 pins on not just 1, but both of my mega2560s! OOPS! I can only imagine I did this trying to get the SPI working a while back :S

Anyways, I've switched to the RX2 pin, and the fix was indeed using:

if (Serial.available() > 2)

instead of:

if (Serial.available() > 0)

So now I have a new problem, as predicted earlier in this thread, is that occassionally the midi bytes get out of sync. It doesn't happen when I am just recieving note on and note off messages, but does happen when recieving aftertouch messages.

I can for now just tell my arduino to discard the aftertouch messages alltogether (and any other problematic messages), and that would probably make it read the bytes without error, but eventually I'm gonna want to use the other messages.

The only other thing I can think to do to help avoid the error is to list all known 2 byte messages and get the arduino to decifer the first byte to decide if it needs to read two or three bytes. Is that overcomplicating matters do you think?

I am also going to try:

if (Serial.available() > 1) or if (Serial.available() >= 2)

as was the suggestion I found and posted in my last post, just incase it works. But I'm fairly sure that will just glitch out for all the 3 byte messages.

Cheers in advance for your help, Pete

You need to parse the MIDI stream correctly or you'll always have problems with missing messages.
The first byte of a normal MIDI message always has the high-order bit set and the two or three bytes that follow will not have that bit set. This allows you to easily determine where a MIDI message starts. (I'm ignoring the fun that is involved with SYSEX and other messages).
So, you start by looking for a byte with the high order bit set. Once you have that you can look at it to determine how many bytes must follow this kind of message because this byte tells you whether you have a Note On, Program Change or whatever and each of those message types has a known number of bytes following. Now you can read the required number of data bytes and act upon the message. Then go back and look for a byte with the high order bit set again.

So it's cos each empty byte is set to -1 that you get the 255

No. There are no 'empty' bytes. If Serial.read() returns -1 it is an error. You have to check Serial.available() to make sure a byte is available before you do Serial.read().
The "simple fix" mentioned in the message you quoted is only simple if you are always expecting to read bytes in pairs. The MIDI messages you are reading can be one, two or three bytes long (and SYSEX is a whole bigger problem to handle) so the simple fix does not apply to you. You have to handle variable length messages properly.

Pete

You have to handle variable length messages properly.

That's what I suspected. So make a note of how many bytes each command has is the most important thing. I don't nessacarily need to watch for the most significant bit so long as my code determines how many bytes each command will have. Though I suppose that being able to determine the beggining of each message would be useful to allow the arduino to "re-allign" the midi messages incase they go out of sync for some reason.

No. There are no 'empty' bytes. If Serial.read() returns -1 it is an error. You have to check Serial.available() to make sure a byte is available before you do Serial.read().

Yes I know, this is in reference to my original code that read 3 serial bytes when there was only 1 serial available (my original mistake). This meant I was reading the first byte and two empty bytes when the first byte came in (as the second and third midi bytes had not arrived yet), then reading the last two data bytes and an empty byte straight after. Just to clarify, the "empty"" bytes are from the empty space in the serial buffer directly after the available bytes.

Cheers for your help guys, I should be back on track now.

Pete