Go Down

Topic: How to receive two MIDI system exclusive messages  (Read 664 times) previous topic - next topic

13rock

I'm trying to receive two MIDI system exclusive messages from a Roland VR-09. The first message is:
 F0 41 10 62 12 00 00 03 01 7C F7
and the second message is:
 F0 41 10 62 12 00 00 03 00 7D F7
What I'm try to have happen is when the first message is received  pin 11 gets set to HIGH while pin 9 is set to LOW. Once the second message is received, pin 11 would be set to LOW and pin 9 would be set to HIGH. Simply, the pins would just toggle their status from LOW to HIGH or HIGH to LOW depending on the last received message.

Any help or suggestions would be greatly appreciated!

TheKikGen

#1
Mar 10, 2018, 12:42 pm Last Edit: Mar 10, 2018, 12:52 pm by TheKikGen
HI.  Had a quick look to your code. it cannot work :


Code: [Select]

 if (vrMess[] =  { 0xF0, 0x41, 0x10, 0x62, 0x12, 0x00, 0x00, 0x03, 0x01, 0x7C, 0xF7 })
{
   digitalWrite(dPin11, HIGH);
   digitalWrite(dPin9, LOW);
 }


1/ You must use the == to compare 2 values and not the = being an affectation operator
2/ You can't use arrays in that way : , initialize first arrays as const globals then use memcmp to compare them
3/ To reduce memory consumption, define a header first , then the last part of the sysex differing
4/ I'm not sure you are using correctly the MIDI library with sysex here. If you only need to parse SYSEX, simply use the Serial.read(), and wait for SOX (0xF0) to start storing bytes in your array and EOX (0xF7) to stop storing in your main loop.  Don't forget to set MIDI baud rate to 31250 in the setup section.


for example :

Code: [Select]
const byte sysExHeader[] = { 0xF0, 0x41, 0x10, 0x62, 0x12, 0x00, 0x00, 0x03 };
const byte sysEX1[]      = { 0x01, 0x7C };
const byte sysEX2[]      = { 0x00, 0x7D };

bool startSysEx = false;
bool sysExReceived = false;

byte mySysExArray[256];
unsigned  i = 0;

(...)
int readByte;

void setup() {
Serial.begin(31250);
(...)



void loop() {
(...)

/// Real time event are ignored (cf MIDI specs)
if ( ( readByte = Serial.read() )  >= 0 && readByte < 0xF8)  {

  if ( readByte == 0xF0)   {
         startSysEx = true;
         sysExReceived = false;
         i = 0;
         mySysExArray[i++] = readByte;        
  }  
  else
  if ( readByte == 0xF7 && startSysEx) {
   sysExReceived = true;
   startSysEx = false;
   mySysExArray[i++] = readByte;        
  }
  else
  if ( startSysEx && readByte <= 0x7F)  {
        mySysExArray[i++] = readByte;        
  }

  

if ( sysExReceived ) {

(...)

  if ( memcmp(mySysExArray, sysExHeader,sizeof(sysExHeader)) == 0)
  {

        if ( memcmp(&mySysExArray[8], sysEx1,sizeof(sysEx1)) == 0)
       {
            // Do something for SYSEX1
       }
       else
       if ( memcmp(&mySysExArray[8], sysEx2,sizeof(sysEx2)) == 0) {

      // Do something for SYSEX2
       }
  }

(...)


That could be optimized more to store only sysex msg concerning your Roland MIDI device, starting I suppose with 0xF0, 0x41, 0x10, 0x62. But the code is more complex.






PieterP

Something like this?

const uint8_t SysExStart = 0xF0;

const uint8_t SysExMatch_A[] = {0x41, 0x10, 0x62, 0x12, 0x00, 0x00, 0x03, 0x01, 0x7C};
const uint8_t SysExMatch_B[] = {0x41, 0x10, 0x62, 0x12, 0x00, 0x00, 0x03, 0x01, 0x7D};

const size_t buffersize = max(sizeof(SysExMatch_A), sizeof(SysExMatch_B));

template <size_t N> bool match(const uint8_t *cmp1, size_t length, const uint8_t (&cmp2)[N]) {
  if (length != N)
    return false;
  return memcmp(cmp1, cmp2, length) == 0;
}

void handleSysEx(const uint8_t *SysEx, size_t length) {
  if (match(SysEx, length, SysExMatch_A)) {
    digitalWrite(LED_BUILTIN, HIGH);
  } else if (match(SysEx, length, SysExMatch_B)) {
    digitalWrite(LED_BUILTIN, LOW);
  }
}

void setup() {
  Serial.begin(31250);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  static uint8_t SysExBuffer[buffersize];
  static size_t index = 0;
  static bool reading = false;
 
  if (Serial.available() > 0) {
    uint8_t data = Serial.read();
    if (reading) {
      if (data >= 0x80 && data < 0xF8) { // if it's a MIDI header
        handleSysEx(SysExBuffer, index);
        reading = false;
      } else {
        if (index == buffersize) { // SysEx is larger than buffer
          reading = false;
        } else {
          SysExBuffer[index] = data;
          index++;
        }
      }
    }   
    if (data == SysExStart) {
      index = 0;
      reading = true;
    }
  }
}


Pieter

PieterP

You can make it a bit more efficient by matching the bytes they have in common separately:
const uint8_t SysExHeader[] = {0x41, 0x10, 0x62, 0x12, 0x00, 0x00, 0x03, 0x01}; // The common bytes of all messages
const uint8_t SysExMatch_A[] = {0x7C};
const uint8_t SysExMatch_B[] = {0x7D};

const size_t buffersize = sizeof(SysExHeader) + max(sizeof(SysExMatch_A), sizeof(SysExMatch_B));

template <size_t N> bool match(const uint8_t *cmp1, size_t length, const uint8_t (&cmp2)[N]) {
  if (length != N)
    return false;
  return memcmp(cmp1, cmp2, length) == 0;
}
template <size_t N> bool matchHeader(const uint8_t *cmp1, size_t length, const uint8_t (&header)[N]) {
  if (length < N)
    return false;
  return memcmp(cmp1, header, N) == 0;
}

void handleSysEx(const uint8_t *SysEx, size_t length) {
  if (!matchHeader(SysEx, length, SysExHeader))
    return;
  SysEx += sizeof(SysExHeader);
  length -= sizeof(SysExHeader);
  if (match(SysEx, length, SysExMatch_A)) {
    digitalWrite(LED_BUILTIN, HIGH);
  } else if (match(SysEx, length, SysExMatch_B)) {
    digitalWrite(LED_BUILTIN, LOW);
  }
}

TheKikGen

Very elegant coding Pieter.  I like the match template !
A point concerning SYSEX : real time one byte midi events can be mixed within SYSEX,

so testing only the bit 7 in the following code is not enough...it works but it's not midi compliant.

if (data & 0x80) { // if it's a MIDI header
       handleSysEx(SysExBuffer, index);
       reading = false;

should be :

if ((data & 0x80) && data < 0xF8 )

or  :

if (data >= 0x80 && data < 0xF8 )

or

if ( data >= 0xF8 )  return;
if (data & 0x80) { // if it's a MIDI header
...

PieterP

A point concerning SYSEX : real time one byte midi events can be mixed within SYSEX,

so testing only the bit 7 in the following code is not enough...it works but it's not midi compliant.

if (data & 0x80) { // if it's a MIDI header
       handleSysEx(SysExBuffer, index);
       reading = false;

should be :

if ((data & 0x80) && data < 0xF8 )

or  :

if (data >= 0x80 && data < 0xF8 )

or

if ( data >= 0xF8 )  return;
if (data & 0x80) { // if it's a MIDI header
...

You are correct.

Go Up