Reading MIDI-SysEx

Hello everyone,

i want to get some data transferred to the arduino via midi in as sysex-messages. i didn't solder my own midi in-interface but (ab)used a midi-to-usb-interface (something like this: shiftmore. blogspot. com/2010/01/quick-and-dirty-arduino-midi-over-usb.html). since the serial port is blocked for midi in and out, i use a display for debugging. this is the 76-byte-sysex-message (and midi monitor says it gets transmitted exactly like this):

00  F0 7D 02 35 34 36 35 37  33 37 34 32 30 33 31 32
10  30 32 30 32 30 32 30 32  30 32 30 32 30 32 30 32
20  30 32 30 30 32 30 33 35  34 36 35 37 33 37 34 32  
30  30 33 32 32 30 32 30 32  30 32 30 32 30 32 30 32  
40  30 32 30 32 30 32 30 30  33 30 34 F7

and this is the arduino code:

void setup() {
  Serial.begin(31250);
  lcd.begin(16, 2);  
}

void loop() {  
  if (Serial.available() > 0)
  {
      int count = 0;
      while (Serial.available())
      {
        incomingByte = Serial.read();
        count++;
      }
      lcd.setCursor(0,0);
      lcd.print(count);
      lcd.print(" Bytes");
  }
}

and what i get:

11 Bytes

I have the feeling that a delay(20); within the while-loop makes things better, but not much. When i send the sysex-message two times (very fast!), i get 22 bytes.

Do you guys have an idea what to do or at least in which direction to think? Is it something like a timeout-buffer-overflow-issue? i'm new to arduino and maybe missing some point...

thanks in advance,

rokus

Serial data is transmitted relatively slow. It can be read from the serial buffer faster than it can be received into the serial buffer. Since you stop reading as soon as the buffer is (temporarily) empty, you are not getting a whole packet before you stop reading.

If you know that a packet will contain n bytes, wait for n bytes to be available before reading, or don't process the accumulated data (not that you are accumulating it) until n bytes have been received.

Even better is to send some start of packet and end of packet markers. This enables you to deal with packets even when part of a packet is lost in shipping.

Never actually programmed them myself, but all SysEx messages start with F0h + a byte indicating the manufacturer, and end with F7h.

Everything in between is dependent on the device sending the message, and is variable length.

So you want to be reading the first byte, checking if it is F0h and if so you start reading and buffering until you hit the F7h character.

thank you for the fast response. unfortunately i didn’t succed.
my new loop:

void loop() {  
  if (Serial.available() > 0 && Serial.read() == 0xF0)
  {
      delay(100);
      byte incomingByte = Serial.read(); // Manufacturer ID = 0x7D = Educational
      delay(100);
      byte nr = Serial.read();           // This * 36 is the size of what comes
      int count = 0;
      int errorcount = 0;

      for (int i = 0; i < (int)nr*36; ++i)
      {
        delay(300);                      // wait for data
        incomingByte = Serial.read();    // read data byte
        SysEx[i] = incomingByte;         // store in byte array
        if ((int)incomingByte == 255) errorcount++; // 255 == Error
        count++;
      }
      
      lcd.setCursor(0,0);
      lcd.print(count);
      lcd.print(" Bytes");              // Output: 72 Bytes
      lcd.setCursor(0,1);
      lcd.print(errorcount);
      lcd.print(" Errors");             // Output: 63 Errors
  }

After 9 bytes i only get 255. When i print every read value as int, i get “valid” but not correct data. Instead of 53, 52, 54, 53, 55, 51… i get 48, 50, 48, 48…

Guessing here since I have nothing here to allow me to test or play with this.

But I'd have gone for something like:

void loop()
{
  byte in = 0;
  byte count = 0;
  byte one = 0;
  byte manuf = 0;
    
  if (Serial.available() > 0)
  {
    one = Serial.read();
    if (one == 0xF0)
    {      
      waitForSerial();
      manuf = Serial.read();     
      while (in != 0xF7)
      {
        waitForSerial();
        in = Serial.read();
        count++;
      }      
      lcd.setCursor(0,0);
      lcd.print(count + " bytes in SysEx"); 
      //excluding start, manuf, and end bytes
    }
  }
}

void waitForSerial()
{
  while (Serial.available() == 0)
  {
  }
}

And if that works, expanded it to store the sysex data bytes in an array, and then process the message in a different function.

waitForSerial is a good idea, thanks for that. I never get out of the while-loop. It reads 9 bytes and then stops. when i send the same message again, it reads the next 9 bytes and idles again. when i change the sysex i send to something else, it reads again only the first few bytes of it (i tried "F0 00 20 3C 01 00 03 F7", taken from http://www.teknopipo.nl/archives/677 and got 1, then 3, then 2 bytes from each transmission). may it be that the usb-midi-interface i use drops the sysex once it checked the manufacturer id or some other data and came to the conclusion that its not meant for it? since a midi-to-usb is little more than an adapter it should forward everything, but what comes out of the computer seems right, how incoming data on the arduino is handled seems right, only thing in between is this interface.

What software(?) are you using to send the SysEx messages?

Your USB adapter shouldn't be changing the messages... and I doubt that the one you posted would be different. Have you tried it with any kind of midi hardware (other than the Arduino) e.g. keyboards etc.?

Oh, and out of interest - does this tutorial work using your adapter and duino - http://arduino.cc/en/Tutorial/Midi ?

the midi-example works.

i use a homebrew java program. i didn’t try it with any other hardware, because the sysex wouldn’t be understood by any other midi device except the one i program for it. but i sent it to midi monitor, looked at the data and it was correct. midi monitor also confirms every transmission of the sysex to the arduino.

maybe to clarify: i want to use the arduino as a midi controller. its display should show some data (title of a song) and this (and little more) data has to be transferred to the arduino. the only way to transfer data “freely” via midi is sysex.

The only other thing I can think to check at this point is that you're definitely sending F0 and F7 etc. as numbers (i.e. 240 and 247) and not character strings (i.e. 70 48 (Ascii F0))

Failing that, I don't know mate. I'm tempted to build the circuit myself to work on it, but it'd probably be the weekend before I got the time to try that.

never mind. i didn't solve this but i'm transferring my data via CC messages.

byte[] msg = {(byte)0xB0, (byte)SOMEDATA1, (byte)SOMEDATA2};

this works right away. sysex is treated as an orphan in many interfaces, devices and libraries, so i stay with more standard midi messages. it's not what i wanted but it works.

one last thing (for all you who google for midi in arduino sysex): easy on the serial line! even with my CC-messages i had problems to get consistent messages. i have a delay of 100ms between every CC-command i send. even with the waitforserial-thing i only get like 5 or 6 bytes without it.