RX Serial Input 3 Byte Filtering/Truncation/Saving/Retransmitting

I’m looking to receive 3 byte messages via TX (MIDI CC), store in a buffer and retransmit them.

The other message being sent is 0xF8 - a timecode byte, which I need to ignore. It is very regular and annoying!

So far I am reading in bytes, checking whether I require them, then adding them to an array. When the array is full the index is reset and the bytes are sent.

This is working somewhat, but values are jumping around, and often 2 byte messages are transmitted, despite me requesting 3. Furthermore, the test message I send contain 2C as a constant byte 2, and a variable byte 3. Often it seems that byte 2 is transmitted as 28. This could possibly be due to bad MIDI?

The first byte should be 176, but when I add an if statement to filter this, I get nothing. This doesn’t bother me, however, as this is constant, so I can just substitute the first byte for 176 later.

Example of incoming message: 0xB0 0x2C 0x34

The ideal transmission flow is detailed below:

0xF8 IGNORED
0xF8 IGNORED
0xB0 ADD TO BUFFER, FIRST BYTE
0xF8 IGNORED
0X2C (Variable) ADD TO BUFFER, SECOND BYTE
0xF8 IGNORED
0xF8 IGNORED
0x34 (Variable) ADD TO BUFFER, THIRD BYTE
//Save Third Byte To Array
BUFFER FULL, TRANSMIT
0xF8 IGNORED
0xF8 IGNORED
0xF8 IGNORED

etc

byte commandByte;
byte noteByte;
byte velocityByte;

int c = 0;

byte buffer[2] = {0};

void setup() {
  Serial3.begin(31250);
  Serial2.begin(31250);

}

void checkMIDI() {
  if (Serial3.available()>3) {
    byte in = Serial3.read();
    if (in != 0xF8) {
      if (c < 1.5) {
        buffer[c] = in;
        c++;
      }
    }
    if (c > 1.5) {
      SendSysEx(176, buffer[0], buffer[1]);
      c = 0;
    }
  }
}
void loop() {
  checkMIDI();
}

void SendSysEx(int Chan, byte Par, byte Value) {
  Serial2.write(176);        
  Serial2.write(Par);        
  Serial2.write(Value);     
  Serial2.flush();
}

Attached is MIDI monitor output

Screen Shot 2015-05-07 at 14.00.42.png

Look at the examples in serial input basics. They read in all the data. Then you can figure out what parts you want to ignore.

...R

Thanks, that's a really great tutorial.

I'm struggling to implement it, however, as I do not know what my end byte will be, and my start byte is not working/a result of bad MIDI.

Also, the 0xF8 messages cause interference.

Haha nice one. I was pretty tired when I wrote that!

void checkMIDI() {
if (Serial3.available() > 3) {
byte in = Serial3.read();
if (in != 0xF8) {
if (c < 3) {
buffer

 = in;
        c++;
      }
    }
    if (c > 2) {
      SendSysEx(176, buffer[1], buffer[2]);
      c = 0;
    }
  }
}

Right now I'm just trying to work out why 2 bytes are sent sometimes instead of 3. Missing byte seems to be byte 2, with byte 3 taking it's place in the output. Any thoughts?

Problem: Made a buffer to take 3 byte messages and store the correct bytes individually. It is unreliable and poorly coded.

Building a unit that takes 3 byte MIDI CC messages and saves them in an array, where the 2nd byte is the index, and the 3rd byte is the value.

However, I’m not handling the inputted data very well or reliably

I’m building up a 3 byte input buffer using a for loop (c). When this is full I write this to the memory array, with byte 2 as the index and byte 3 as the value.

It’s my selfmade 3 byte input buffer that’s the problem. Using test messages 0xB00x2Cx0VARIABLE to check. Sometimes 2C is read as 28, and sometimes only 2 bytes are recieved. I’ve checked the MIDI being sent - it’s all sound.

Help would be greatly appreciated in forming a reliable method to get the correct MIDI CC notes (3 sucessive bytes). Code below.

I feel like I am taking the right approach but my sytax is not quite right.

void checkMIDI() {
  if (Serial3.available() > 3) {
    byte in = Serial3.read();
    if (in != 0xF8) {
      if (c < 3) {

        inbuffer[c] = in;
        c++;

      }
    }
    if (c > 2) {
      for (int i = 0; i < 50; i++) {
        if (inbuffer[1] == ccNum[i]) {
        patches[currentPatch][inbuffer[1]] = inbuffer[2];
          c = 0;
        }
      }
    }
  }
}

Problem: Made a buffer to take 3 byte messages and store the correct bytes individually. It is unreliable and poorly coded.

Building a unit that takes 3 byte MIDI CC messages and saves them in an array, where the 2nd byte is the index, and the 3rd byte is the value.

However, I’m not handling the inputted data very well or reliably.

I’m building up a 3 byte input buffer using a for loop (c). When this is full I write this to the memory array, with byte 2 as the index and byte 3 as the value.

It’s my selfmade 3 byte input buffer that’s the problem. Using test messages 0xB00x2Cx0VARIABLE to check. Sometimes 2C is read as 28, and sometimes only 2 bytes are recieved. I’ve checked the MIDI being sent - it’s all sound.

Help would be greatly appreciated in forming a reliable method to get the correct MIDI CC notes (3 sucessive bytes). Code below.

I feel like I am taking the right approach but my sytax is not quite right.

Note: 0xB0 is to be ignored. It is a pulsing clock byte and not needed.

void checkMIDI() {
  if (Serial3.available() > 3) {
    byte in = Serial3.read();
    if (in != 0xF8) {
      if (c < 3) {

        inbuffer[c] = in;
        c++;

      }
    }
    if (c > 2) {
      for (int i = 0; i < 50; i++) {
        if (inbuffer[1] == ccNum[i]) {
        patches[currentPatch][inbuffer[1]] = inbuffer[2];
          c = 0;
        }
      }
    }
  }
}

Thanks Riva!

That's outputting just the second byte, actually. But even then, it's not outputting a straight 0x2C message.

I'm starting to think there's something wrong with my MIDI in circuit...

I’m pretty new to C++ and the Arduino boards, but very familiar with the midi side of things.

I found a good tutorial Here look for the post by “paul soulsby” I tried it and it worked much better at dealing with the active sensing bytes.

I modified it to send out some serial messages (for debugging using PuTTY) and to light up a few LEDs for note, CC and pitch-bend etc.

byte headerByte = 0;
byte data1 = 0;
byte data2 = 0;
byte statusbuffer = 0;
boolean firstbyte;


void setup() {
  Serial.begin(31250);
  for (int thisPin = 2; thisPin < 13; thisPin++) {
    pinMode(thisPin, OUTPUT);
  }
}

void Flash(int Pin){
  digitalWrite(Pin,HIGH);
  delay(10);
  digitalWrite(Pin,LOW);
}

void MIDI_Poll() {
  if (Serial.available() > 0) {
    do {
      // read the incoming byte:
      headerByte = Serial.read();
      if (headerByte > 0xF7) {
        Flash(13);
        // this is where MIDI clock stuff is done
        //        switch (headerByte) {
        //        case 0xFE:
        //          Serial.println("Active Sensing!");
        //        }
      }
      else if (headerByte > 0xF0) {
        statusbuffer = 0;
        //sysex stuff done here
      }
      else if (headerByte > 0x7F) {
        statusbuffer = headerByte;
        firstbyte = true;
        data1 = 0;
        data2 = 0;
      }
      else if (statusbuffer != 0) {
        if (firstbyte == true) {
          // must be first byte
          data1 = headerByte;
          firstbyte = false;
        }
        else {
          // so must be second byte then
          data2 = headerByte;
          //process the message here
          
          
          if ((statusbuffer >> 4 ) == 0x9 && data2 != 0) {
            //MIDI note on subroutine
            Serial.print("Channel: ");
            Serial.print((statusbuffer & 0x0F) + 1, DEC);
            Serial.print(" Note: ");
            Serial.print(data1, DEC);
            Serial.print(" Velocity: ");
            Serial.print(data2, DEC);
            Serial.println();
            Flash(12);
            
          }
          else if (statusbuffer == 0x80 ||
                   (statusbuffer == 0x90 && data2 == 0)) {
            //MIDI note off subroutine
          }
          
          else if ((statusbuffer >> 4)  == 0xE) {
            //pitch bend wheel
            Serial.print("Channel: ");
            Serial.print((statusbuffer & 0x0F) + 1, DEC);
            Serial.print(" Pitch Bend: ");
            Serial.print(data1, DEC);
            Serial.print(data2, DEC);
            Serial.println();
            Flash(10);
          }
          else if ((statusbuffer >> 4) == 0xB) {
            //MIDI controller on subroutine
            Serial.print("Channel: ");
            Serial.print((statusbuffer & 0x0F) + 1, DEC);
            if (data1 == 1) {
              Serial.print(" Modulation:" );
            }
            if (data1 == 10) {
              Serial.print(" Pan:" );
            }
            if (data1 == 7) {
              Serial.print(" Volume:" );
            }
            if (data1 == 123) {
              Serial.print(" All notes off:" );
            }
            Serial.print(" Control: ");
            Serial.print(data1, DEC);
            Serial.print(" Value: ");
            Serial.print(data2, DEC);
            Serial.println();
            Flash(11);
          }
          //now clear them for next note
          data1 = 0;
          data2 = 0;
          firstbyte = true;
        }
      }
    } while (Serial.available() > 0);
  }
}

void loop() {
  MIDI_Poll();
}

Hi glocka

Please post your complete program. If it is too big for the code tags, add it as an attachment.

   if (c > 2) {
      for (int i = 0; i < 50; i++) {
        if (inbuffer[1] == ccNum[i]) {
          patches[currentPatch][inbuffer[1]] = inbuffer[2];
          c = 0;
        }
      }

From the function you posted, it looks like your counter c is only reset when the if statement finds a match. Feels like it should be reset whether or not you find a match, otherwise you will overrun the array when more characters are received.

if (Serial3.available() > 3) {

Shouldn’t this be Serial3.available() >= 3? Also, when this is true, you only read one character (until more characters are received to take available back above 3). Looks like you will miss the last two characters received.

Regards

Ray

glocka: I'm struggling to implement it, however, as I do not know what my end byte will be, and my start byte is not working/a result of bad MIDI.

If you post your attempted implementation I may be able to help. I don't know Midi so can you provide an example of a Midi message ?

...R

Thanks for getting in touch, Robin.

Any example of a MIDI message is “B0 2C 44”
B0 - CC message on channel 1 (this will be constant)
2C - Parameter (cutoff in this case)
44 - Value

Here’s an example of the weird outputs I’m getting:

19:20:22.534 From Lexicon Win USB 1-2 In/Out Control 1 B0 2C 5E good!
19:20:22.543 From Lexicon Win USB 1-2 In/Out Control 1 B0 28 5C 2C has become 28?
19:20:22.544 From Lexicon Win USB 1-2 In/Out Control 1 B0 28 5A and again?
19:20:25.901 From Lexicon Win USB 1-2 In/Out SysEx F0 F7 ← Who are you
19:20:26.036 From Lexicon Win USB 1-2 In/Out SysEx F0 F7 ← where are my bytes?!
19:20:26.045 From Lexicon Win USB 1-2 In/Out Control 1 B0 2C 75 nice one!
19:20:26.054 From Lexicon Win USB 1-2 In/Out Control 1 B0 28 77 and again…
19:20:26.063 From Lexicon Win USB 1-2 In/Out Control 1 B0 2C 70 yeah!
19:20:26.072 From Lexicon Win USB 1-2 In/Out Control 1 B0 2C 71 woo!

The F7’s are causing lag on my monitor too. I’m guessing it’s because of the arduino summing bytes or something similar?

Below is the code.

byte c = 0;

byte buffer[2] = {0};

void setup() {
  Serial3.begin(31250);
  Serial2.begin(31250);
}
void loop() {
  checkMIDI();
}

void checkMIDI() {
  if (Serial3.available()>0) {
    byte in = Serial3.read();
    if (in != 0xF8) {
      buffer[c++] = in;
      if (c > 2) {
        SendSysEx(176, buffer[0], buffer[1]);
        c = 0;
      }
    }
  }
}

void SendSysEx(int Chan, byte Par, byte Value) {
  Serial2.write(Chan);        
  Serial2.write(Par);        
  Serial2.write(Value);     
  Serial2.flush();
}

Oh, and if necessary, here’s the circuit: http://www.notesandvolts.com/2015/02/midi-and-arduino-build-midi-input.html

I’ve built a few of the others floating round on the internet and this is working best.

Thanks again! G

Hackscribble: Please post your complete program.

The original poster has wasted your time. He decided it would be a good idea to start a second thread. In the same section. Despite the fact that he was actively getting help on his first thread.

@glocka, do not do that again. Threads merged.

Nice one mate, that's some bloody good code!

I'll let you know how I get on but it's looking promising!

Sorry for that. Can I delete threads?

I did get put on to a frankly brilliant piece of code in the end, check out Paul Soulsby's comment here: http://www.instructables.com/id/Send-and-Receive-MIDI-with-Arduino/?&sort=ACTIVE&limit=40&offset=40#DISCUSS

Genuinely a really elegant solution.

Sorry Robin. If you want to learn about MIDI some more PM me and I can shoot you some excellent resources.

glocka: Sorry Robin. If you want to learn about MIDI some more

I have no interest. I was just trying to help you with receiving data.

I presume you now have a solution.

...R

glocka: Sorry for that.

Just two hours earlier you had created yet another thread (merged). Apparently, you were not sorry enough to mention that fact so I could remove / merge THAT thread. You are really pissing me off. Are there any more threads I should know about?

[quote author=Coding Badly link=msg=2222900 date=1431075208] You are really pissing me off. Are there any more threads I should know about? [/quote] http://forum.arduino.cc/index.php?topic=321179.msg2221803#msg2221803

Forum user generally fall into three categories (the good, the bad & the a**hole) what category do you fit in?

Firmly an asshole it seems. Again, my apologies. You won't be hearing any more from me, other than answers to other's posts.

Please delete my threads off the surface of the earth lest I scorn myself again.

glocka: You won't be hearing any more from me, other than answers to other's posts.

Please delete my threads off the surface of the earth lest I scorn myself again.

A bit OTT. I would think you have been here long enough to either have read the 'How to use this forum' or seen other people posting the same question in several forums and being pulled up for it. For me who actively looks for threads that interest me in the hope of either learning something or helping someone it is annoying to find the same question being asked in several different threads/forums.

Chill out and stick around to ask questions to problems you have but ask them only once.

glocka: Forum user generally fall into three categories (the good, the bad & the a**hole) what category do you fit in?

If you are referring to @Coding Badly it might be useful to ask yourself how many people he has helped and then ask yourself how many people you have helped ? ? ?

...R