Receive multiple midi notes (or "chords") to control in realtime RGB leds?

Hi everybody :wink:

I’m trying to control various RGB leds using the MIDI protocol. I don’t need DMX, SERIAL or i2c. I need pure MIDI, here is the problem… :confused:

I use 3 SPI-driven TLC5940 to get 48 precise PWM outputs.

I use an Arduino UNO (Atmega 328).

I use this hardware as a MIDI input (this one seems to work well) :

I use a USB to MIDI I/O cable and I try to drive the LED with Cubase.

I will use the MIDI like it :

NOTE ON:

Channel : 1 (I will use only one channel)

Note : 0…15 RED
16…31 GREEN
32…47 BLUE

Velocity : 0…255 : PWM Value of the desired output.

NOTE OFF:
Note : 0…15 RED
16…31 GREEN
32…47 BLUE

The PWM note value should have 0 (Shut down).0

I use the Arduino FortySevenEffects MIDI Library v4.2 :

My question and my problem is the following:

This example I show you work but with errors, sometimes, it looks like the data don’t arrive or have errors. With only one note in one channel, it works like a charm. But when I want to use notes at the same times (chord) it is where the situation is more difficult and errors occurs.

It is an hardware error?

Code error?

The midi baud rate isn’t sufficient to do this (yes, I think this is an absurd theory, but who knows…)

And mainly, is it possible to do this with arduino UNO?

Here is the code I made using the MIDI library:

#include <MIDI.h>
#include "Tlc5940.h"
MIDI_CREATE_DEFAULT_INSTANCE();

byte midirgb[48];

void setup() {
Tlc.init();
MIDI.begin();    
MIDI.setHandleNoteOn(MyHandleNoteOn);
MIDI.setHandleNoteOff(MyHandleNoteOff);
}

void MyHandleNoteOn(byte channel, byte pitch, byte velocity) { 
  if (pitch <= 47) {
  midirgb[pitch] = 255;
  }
}


void MyHandleNoteOff(byte channel, byte pitch, byte velocity) { 
  if (pitch <= 47) {
  midirgb[pitch] = 0;
  }
}

void loop() {
for (int i=0; i <= 47; i++){  
   MIDI.read();
   delayMicroseconds(100);
}

   

   Tlc.clear();
   for (int i=0; i <= 15; i++){
     RGBTLCSet256(i,midirgb[i],midirgb[i+16],midirgb[i+32]);
   }
   Tlc.update();  

   
}


void RGBTLCSet256(byte ledstrip, byte r, byte g, byte b)
{
  if (ledstrip==0){
   Tlc.set(15, map(r,0,255,0,4095));
   Tlc.set(14, map(g,0,255,0,4095));
   Tlc.set(13, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==1){
   Tlc.set(12, map(r,0,255,0,4095));
   Tlc.set(11, map(g,0,255,0,4095));
   Tlc.set(10, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==2){
   Tlc.set(9, map(r,0,255,0,4095));
   Tlc.set(8, map(g,0,255,0,4095));
   Tlc.set(7, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==3){
   Tlc.set(6, map(r,0,255,0,4095));
   Tlc.set(5, map(g,0,255,0,4095));
   Tlc.set(4, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==4){
   Tlc.set(3, map(r,0,255,0,4095));
   Tlc.set(2, map(g,0,255,0,4095));
   Tlc.set(1, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==5){
   Tlc.set(0, map(r,0,255,0,4095));
   Tlc.set(31, map(g,0,255,0,4095));
   Tlc.set(30, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==6){
   Tlc.set(29, map(r,0,255,0,4095));
   Tlc.set(28, map(g,0,255,0,4095));
   Tlc.set(27, map(b,0,255,0,4095)); 
  }
  
 if (ledstrip==7){
   Tlc.set(26, map(r,0,255,0,4095));
   Tlc.set(25, map(g,0,255,0,4095));
   Tlc.set(24, map(b,0,255,0,4095)); 
  }

 if (ledstrip==8){
   Tlc.set(23, map(r,0,255,0,4095));
   Tlc.set(22, map(g,0,255,0,4095));
   Tlc.set(21, map(b,0,255,0,4095)); 
  }
  
 if (ledstrip==9){
   Tlc.set(20, map(r,0,255,0,4095));
   Tlc.set(19, map(g,0,255,0,4095));
   Tlc.set(18, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==10){
   Tlc.set(17, map(r,0,255,0,4095));
   Tlc.set(16, map(g,0,255,0,4095));
   Tlc.set(47, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==11){
   Tlc.set(46, map(r,0,255,0,4095));
   Tlc.set(45, map(g,0,255,0,4095));
   Tlc.set(44, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==12){
   Tlc.set(43, map(r,0,255,0,4095));
   Tlc.set(42, map(g,0,255,0,4095));
   Tlc.set(41, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==13){
   Tlc.set(40, map(r,0,255,0,4095));
   Tlc.set(39, map(g,0,255,0,4095));
   Tlc.set(38, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==14){
   Tlc.set(37, map(r,0,255,0,4095));
   Tlc.set(36, map(g,0,255,0,4095));
   Tlc.set(35, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==15){
   Tlc.set(34, map(r,0,255,0,4095));
   Tlc.set(33, map(g,0,255,0,4095));
   Tlc.set(32, map(b,0,255,0,4095)); 
  }    
}

Here is the code I made without library (pure serial) and the result is worstest…

#include "Tlc5940.h"

byte midirgb[48];

//These are the midi commands to interact with the arduino

byte midi_on = 0x90;
byte midi_off = 0x80;
byte location_byte;
byte in_note;
byte in_volume;

void check_midi()
 {
   while (Serial.available() >= 3)//when three bytes available
   {
     if (Serial.available())
     {
       location_byte = Serial.read();//read first byte
       in_note = Serial.read();//read next byte
       in_volume = Serial.read();//read final byte
     }
   }
 }

void setup() {
Tlc.init();
Serial.begin(31250);
}

void loop() {

/*  
for (int i=0; i <= 47; i++){ 
midirgb[i] = 0; 
}
*/

for (int i=0; i <= 47; i++){ 

  check_midi();
  
  if (location_byte == midi_on)
  {
  midirgb[in_note] = in_volume; 
  } else {
  midirgb[in_note] = 0; 
  }

}



   Tlc.clear();
   for (int i=0; i <= 15; i++){
     RGBTLCSet256(i,midirgb[i],midirgb[i+16],midirgb[i+32]);
   }
   Tlc.update();  
   
}


void RGBTLCSet256(byte ledstrip, byte r, byte g, byte b)
{
  if (ledstrip==0){
   Tlc.set(15, map(r,0,255,0,4095));
   Tlc.set(14, map(g,0,255,0,4095));
   Tlc.set(13, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==1){
   Tlc.set(12, map(r,0,255,0,4095));
   Tlc.set(11, map(g,0,255,0,4095));
   Tlc.set(10, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==2){
   Tlc.set(9, map(r,0,255,0,4095));
   Tlc.set(8, map(g,0,255,0,4095));
   Tlc.set(7, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==3){
   Tlc.set(6, map(r,0,255,0,4095));
   Tlc.set(5, map(g,0,255,0,4095));
   Tlc.set(4, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==4){
   Tlc.set(3, map(r,0,255,0,4095));
   Tlc.set(2, map(g,0,255,0,4095));
   Tlc.set(1, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==5){
   Tlc.set(0, map(r,0,255,0,4095));
   Tlc.set(31, map(g,0,255,0,4095));
   Tlc.set(30, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==6){
   Tlc.set(29, map(r,0,255,0,4095));
   Tlc.set(28, map(g,0,255,0,4095));
   Tlc.set(27, map(b,0,255,0,4095)); 
  }
  
 if (ledstrip==7){
   Tlc.set(26, map(r,0,255,0,4095));
   Tlc.set(25, map(g,0,255,0,4095));
   Tlc.set(24, map(b,0,255,0,4095)); 
  }

 if (ledstrip==8){
   Tlc.set(23, map(r,0,255,0,4095));
   Tlc.set(22, map(g,0,255,0,4095));
   Tlc.set(21, map(b,0,255,0,4095)); 
  }
  
 if (ledstrip==9){
   Tlc.set(20, map(r,0,255,0,4095));
   Tlc.set(19, map(g,0,255,0,4095));
   Tlc.set(18, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==10){
   Tlc.set(17, map(r,0,255,0,4095));
   Tlc.set(16, map(g,0,255,0,4095));
   Tlc.set(47, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==11){
   Tlc.set(46, map(r,0,255,0,4095));
   Tlc.set(45, map(g,0,255,0,4095));
   Tlc.set(44, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==12){
   Tlc.set(43, map(r,0,255,0,4095));
   Tlc.set(42, map(g,0,255,0,4095));
   Tlc.set(41, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==13){
   Tlc.set(40, map(r,0,255,0,4095));
   Tlc.set(39, map(g,0,255,0,4095));
   Tlc.set(38, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==14){
   Tlc.set(37, map(r,0,255,0,4095));
   Tlc.set(36, map(g,0,255,0,4095));
   Tlc.set(35, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==15){
   Tlc.set(34, map(r,0,255,0,4095));
   Tlc.set(33, map(g,0,255,0,4095));
   Tlc.set(32, map(b,0,255,0,4095)); 
  }    
}

Here is attached the Cubase file I use.

Thanks for your help and sharing your experience :wink:

Test midi cubase.zip (9.23 KB)

It is an hardware error?

No.

Code error?

Possibly

The midi baud rate isn’t sufficient to do this

No.

And mainly, is it possible to do this with arduino UNO?

Yes.

Looking at the code it is poor. When you write the same lines over and over it is time to learn about for loops and arrays.
However I think your problem is this:-

void check_midi()
 {
   while (Serial.available() >= 3)//when three bytes available
   {
     if (Serial.available())
     {
       location_byte = Serial.read();//read first byte
       in_note = Serial.read();//read next byte
       in_volume = Serial.read();//read final byte
     }
   }
 }

What you are saying is if there are 3 or more bytes in the buffer keep taking them out in groups of three. So what happens when there are 4 bytes in the buffer. You read one message, then right over the top of that one you read one byte of the next message and then the next two bytes read an empty buffer returning 0xff and now your messages are out of sync and you get the bytes in the wrong place.

The other thing is that your keyboard could be switching to using the running status mode when it has a lot of keys to send at once and that code is not set up for running status mode.

Thanks for your help Grumpy_Mike.

I modified the code but I follow to get bad results…

Here is the serial code modified :

#include "Tlc5940.h"

byte midirgb[48];

//These are the midi commands to interact with the arduino

byte midi_on = 0x90;
byte midi_off = 0x80;
byte location_byte;
byte in_note;
byte in_volume;

void check_midi()
 {

     if (Serial.available())
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
     }
 }

void setup() {
Tlc.init();
Serial.begin(31250);
}

void loop() {

/*
for (int i=0; i <= 47; i++){ 
midirgb[i] = 0; 
}
*/


  check_midi();
  
  if (location_byte == midi_on)
  {
  midirgb[in_note] = in_volume; 
  } else {
  midirgb[in_note] = 0; 
  }


   Tlc.clear();
   for (int i=0; i <= 15; i++){
     RGBTLCSet256(i,midirgb[i],midirgb[i+16],midirgb[i+32]);
   }
   Tlc.update();  
   
}


void RGBTLCSet256(byte ledstrip, byte r, byte g, byte b)
{
  if (ledstrip==0){
   Tlc.set(15, map(r,0,255,0,4095));
   Tlc.set(14, map(g,0,255,0,4095));
   Tlc.set(13, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==1){
   Tlc.set(12, map(r,0,255,0,4095));
   Tlc.set(11, map(g,0,255,0,4095));
   Tlc.set(10, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==2){
   Tlc.set(9, map(r,0,255,0,4095));
   Tlc.set(8, map(g,0,255,0,4095));
   Tlc.set(7, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==3){
   Tlc.set(6, map(r,0,255,0,4095));
   Tlc.set(5, map(g,0,255,0,4095));
   Tlc.set(4, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==4){
   Tlc.set(3, map(r,0,255,0,4095));
   Tlc.set(2, map(g,0,255,0,4095));
   Tlc.set(1, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==5){
   Tlc.set(0, map(r,0,255,0,4095));
   Tlc.set(31, map(g,0,255,0,4095));
   Tlc.set(30, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==6){
   Tlc.set(29, map(r,0,255,0,4095));
   Tlc.set(28, map(g,0,255,0,4095));
   Tlc.set(27, map(b,0,255,0,4095)); 
  }
  
 if (ledstrip==7){
   Tlc.set(26, map(r,0,255,0,4095));
   Tlc.set(25, map(g,0,255,0,4095));
   Tlc.set(24, map(b,0,255,0,4095)); 
  }

 if (ledstrip==8){
   Tlc.set(23, map(r,0,255,0,4095));
   Tlc.set(22, map(g,0,255,0,4095));
   Tlc.set(21, map(b,0,255,0,4095)); 
  }
  
 if (ledstrip==9){
   Tlc.set(20, map(r,0,255,0,4095));
   Tlc.set(19, map(g,0,255,0,4095));
   Tlc.set(18, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==10){
   Tlc.set(17, map(r,0,255,0,4095));
   Tlc.set(16, map(g,0,255,0,4095));
   Tlc.set(47, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==11){
   Tlc.set(46, map(r,0,255,0,4095));
   Tlc.set(45, map(g,0,255,0,4095));
   Tlc.set(44, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==12){
   Tlc.set(43, map(r,0,255,0,4095));
   Tlc.set(42, map(g,0,255,0,4095));
   Tlc.set(41, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==13){
   Tlc.set(40, map(r,0,255,0,4095));
   Tlc.set(39, map(g,0,255,0,4095));
   Tlc.set(38, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==14){
   Tlc.set(37, map(r,0,255,0,4095));
   Tlc.set(36, map(g,0,255,0,4095));
   Tlc.set(35, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==15){
   Tlc.set(34, map(r,0,255,0,4095));
   Tlc.set(33, map(g,0,255,0,4095));
   Tlc.set(32, map(b,0,255,0,4095)); 
  }    
}

I made a video (sorry for the accent, I’m french :slight_smile: ) to explain what exactly is the problem:

The error is sometimes the midi data isn’t correctly interpreted by the Arduino.

Unfortunatlty, I don’t have a MIDI hardware keyboard (Only a Korg KaossPad 3 with one midi output, but it is useless in this case…) and only have a cubase sequencer with USB to midi converter… I think this configuration isn’t working in running status, but in “normal midi” mode.

Regards :wink:

You have still got exactly the same error in your thinking.

void check_midi()
 {

     if (Serial.available())
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
     }
 }

That is saying that if you have at lease one byte in the serial buffer then read three bytes. That is simply not going to work. Try

void check_midi()
 {

     if (Serial.available()>2)
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
     }
 }

Ohhh good! The result is a lot better!

I made another video:

https://www.youtube.com/watch?v=3Px7J1F1Orw&feature=youtu.be

Sometimes the data don't come totally to the Arduino and some leds don't turn on, the same problem I have using the MIDI Library. Of course, I totally prefer obtaining a working result without any midi library :)

The logic is still a bit wrong. You have nothing to say that a new note has been received and so you could be setting things based on the previous note.

I have tried adding this logic into a few routines but I haven’t tested it.

boolean newNote = false;

void check_midi()
 {

     if (Serial.available()>2)
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
       if(location_byte == midi_on || location_byte == midi_off) newNote = true; 
     }
 }

void setup() {
Tlc.init();
Serial.begin(31250);
}

void loop() {
check_midi();
if(newNote){ 
  if (location_byte == midi_on) midirgb[in_note] = in_volume;
  if (location_byte == midi_off) midirgb[in_note] = 0;
   Tlc.clear();
   for (int i=0; i <= 15; i++){
     RGBTLCSet256(i,midirgb[i],midirgb[i+16],midirgb[i+32]);
   }
   Tlc.update(); 
   newNote = false;
  }
}

Your code still assumes that you have received nothing but three byte MIDI messages, if your box throws out any two byte or single byte messages the the whole thing will get thrown out of “flunter”

Hi thanks for your answer :)

Unfortunatly, I obtain the same result as the video : sometime the data ins't totally interpreted :(

This is the USB to MIDI converter I use, this is one of the good ones with optocoupler as input (no modification like this is needed - http://www.arvydas.co.uk/2013/07/cheap-usb-midi-cable-some-self-assembly-may-be-required/

|500x375

Are you sure that this is correct?

byte midirgb[48];

That implies that the highest MIDI note is 47 which is B on octave -2. Any higher number will write outside the array and stamp on other variables and changes them. Have you tried setting this array size to 128?

Hi :)

I tried to put byte midirgb[128] but nothing changes.

This array is only here to "translate" the midi DATA to RGB DATA.

I use 16 RGB leds so 16x3 = 48 maximum.

Here this is the explaination of how works this array.

|500x84

I tried to put byte midirgb[128] but nothing changes.

OK but:-

I use 16 RGB leds so 16x3 = 48 maximum.

That is not true. In your code you have:-

midirgb[in_note] = in_volume;

That means you can use ANY array index that is a in_note value, which is the second parameter of a note on / note off MIDI message. So that array needs to be 128 bytes in length.
Maybe you are not doing in the code what you think you are doing.

Yes, I understand what you mean, my explaination was a little bit confusing :grinning:

The midi messages i will send will be always included between 0 and 47 value. I will never send a note > a 47.

According to this table it is note -1C ti 2B.

Here is the interpretation I do:

Finally I left the variable to 128, but no didn’t noticied any positive change :drooling_face:

I tried this :

#include "Tlc5940.h"

byte midirgb[128];

//These are the midi commands to interact with the arduino

byte midi_on = 0x90;
byte midi_off = 0x80;
byte location_byte;
byte in_note;
byte in_volume;
boolean newNote = false;

void check_midi()
 {

     if (Serial.available()>2)
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
       if(location_byte == midi_on || location_byte == midi_off) newNote = true; 
     }
 }

void setup() {
Tlc.init();
Serial.begin(31250);
}

void loop() {

for (int i=0; i <= 47; i++){  
check_midi();
if(newNote){ 
  if (location_byte == midi_on) midirgb[in_note] = in_volume;
  if (location_byte == midi_off) midirgb[in_note] = 0;
   newNote = false;
  }
}

   Tlc.clear();
   for (int i=0; i <= 15; i++){
     RGBTLCSet256(i,midirgb[i],midirgb[i+16],midirgb[i+32]);
   }
   Tlc.update(); 
  
}

void RGBTLCSet256(byte ledstrip, byte r, byte g, byte b)
{
  if (ledstrip==0){
   Tlc.set(15, map(r,0,255,0,4095));
   Tlc.set(14, map(g,0,255,0,4095));
   Tlc.set(13, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==1){
   Tlc.set(12, map(r,0,255,0,4095));
   Tlc.set(11, map(g,0,255,0,4095));
   Tlc.set(10, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==2){
   Tlc.set(9, map(r,0,255,0,4095));
   Tlc.set(8, map(g,0,255,0,4095));
   Tlc.set(7, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==3){
   Tlc.set(6, map(r,0,255,0,4095));
   Tlc.set(5, map(g,0,255,0,4095));
   Tlc.set(4, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==4){
   Tlc.set(3, map(r,0,255,0,4095));
   Tlc.set(2, map(g,0,255,0,4095));
   Tlc.set(1, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==5){
   Tlc.set(0, map(r,0,255,0,4095));
   Tlc.set(31, map(g,0,255,0,4095));
   Tlc.set(30, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==6){
   Tlc.set(29, map(r,0,255,0,4095));
   Tlc.set(28, map(g,0,255,0,4095));
   Tlc.set(27, map(b,0,255,0,4095)); 
  }
  
 if (ledstrip==7){
   Tlc.set(26, map(r,0,255,0,4095));
   Tlc.set(25, map(g,0,255,0,4095));
   Tlc.set(24, map(b,0,255,0,4095)); 
  }

 if (ledstrip==8){
   Tlc.set(23, map(r,0,255,0,4095));
   Tlc.set(22, map(g,0,255,0,4095));
   Tlc.set(21, map(b,0,255,0,4095)); 
  }
  
 if (ledstrip==9){
   Tlc.set(20, map(r,0,255,0,4095));
   Tlc.set(19, map(g,0,255,0,4095));
   Tlc.set(18, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==10){
   Tlc.set(17, map(r,0,255,0,4095));
   Tlc.set(16, map(g,0,255,0,4095));
   Tlc.set(47, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==11){
   Tlc.set(46, map(r,0,255,0,4095));
   Tlc.set(45, map(g,0,255,0,4095));
   Tlc.set(44, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==12){
   Tlc.set(43, map(r,0,255,0,4095));
   Tlc.set(42, map(g,0,255,0,4095));
   Tlc.set(41, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==13){
   Tlc.set(40, map(r,0,255,0,4095));
   Tlc.set(39, map(g,0,255,0,4095));
   Tlc.set(38, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==14){
   Tlc.set(37, map(r,0,255,0,4095));
   Tlc.set(36, map(g,0,255,0,4095));
   Tlc.set(35, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==15){
   Tlc.set(34, map(r,0,255,0,4095));
   Tlc.set(33, map(g,0,255,0,4095));
   Tlc.set(32, map(b,0,255,0,4095)); 
  }    
}

Putting a loop to leave a good time to the arduino to unfill the serial buffer (in case it was it the error) but without any success…

Do you think it can be a serial buffer problem? What do you think about the Serial.flush() instruction?

https://www.arduino.cc/en/Serial/Flush

What do you think about the Serial.flush() instruction?

It is not what you need. It waits until the buffer is empty when sending serial data. You are only receiving data so it is irrelevant.

The Serial input buffer is 64 bytes long, if this is getting over run then it might cause the problems you are seeing.

To test this I would use the on board LED connected to pin 13. Set this pin as an output in the setup function and write a LOW to it to turn it off. Then in the loop function as the first line have this statement:-

if (Serial.available()>60)digitalWrite(13, HIGH);

If the buffer peaks above this value then you know it is over running.

I tested it, and there isn’t any serial buffer overload.

Here is the code :

#include "Tlc5940.h"

byte midirgb[128];

//These are the midi commands to interact with the arduino

byte midi_on = 0x90;
byte midi_off = 0x80;
byte location_byte;
byte in_note;
byte in_volume;
boolean newNote = false;

void check_midi()
{

     if (Serial.available()>2)
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
     }

     
  if (Serial.available()>60) {
    for (int i=0; i <= 47; i++){
      midirgb[i] = 255; 
    }
  } else {
    for (int i=0; i <= 47; i++){
      midirgb[i] = 0; 
    }
  }
}

void setup() {
Tlc.init();
Serial.begin(31250);
}

void loop() {

check_midi();

   Tlc.clear();
   for (int i=0; i <= 15; i++){
     RGBTLCSet256(i,midirgb[i],midirgb[i+16],midirgb[i+32]);
   }
   Tlc.update(); 
  
}

void RGBTLCSet256(byte ledstrip, byte r, byte g, byte b)
{
  if (ledstrip==0){
   Tlc.set(15, map(r,0,255,0,4095));
   Tlc.set(14, map(g,0,255,0,4095));
   Tlc.set(13, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==1){
   Tlc.set(12, map(r,0,255,0,4095));
   Tlc.set(11, map(g,0,255,0,4095));
   Tlc.set(10, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==2){
   Tlc.set(9, map(r,0,255,0,4095));
   Tlc.set(8, map(g,0,255,0,4095));
   Tlc.set(7, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==3){
   Tlc.set(6, map(r,0,255,0,4095));
   Tlc.set(5, map(g,0,255,0,4095));
   Tlc.set(4, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==4){
   Tlc.set(3, map(r,0,255,0,4095));
   Tlc.set(2, map(g,0,255,0,4095));
   Tlc.set(1, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==5){
   Tlc.set(0, map(r,0,255,0,4095));
   Tlc.set(31, map(g,0,255,0,4095));
   Tlc.set(30, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==6){
   Tlc.set(29, map(r,0,255,0,4095));
   Tlc.set(28, map(g,0,255,0,4095));
   Tlc.set(27, map(b,0,255,0,4095)); 
  }
  
 if (ledstrip==7){
   Tlc.set(26, map(r,0,255,0,4095));
   Tlc.set(25, map(g,0,255,0,4095));
   Tlc.set(24, map(b,0,255,0,4095)); 
  }

 if (ledstrip==8){
   Tlc.set(23, map(r,0,255,0,4095));
   Tlc.set(22, map(g,0,255,0,4095));
   Tlc.set(21, map(b,0,255,0,4095)); 
  }
  
 if (ledstrip==9){
   Tlc.set(20, map(r,0,255,0,4095));
   Tlc.set(19, map(g,0,255,0,4095));
   Tlc.set(18, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==10){
   Tlc.set(17, map(r,0,255,0,4095));
   Tlc.set(16, map(g,0,255,0,4095));
   Tlc.set(47, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==11){
   Tlc.set(46, map(r,0,255,0,4095));
   Tlc.set(45, map(g,0,255,0,4095));
   Tlc.set(44, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==12){
   Tlc.set(43, map(r,0,255,0,4095));
   Tlc.set(42, map(g,0,255,0,4095));
   Tlc.set(41, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==13){
   Tlc.set(40, map(r,0,255,0,4095));
   Tlc.set(39, map(g,0,255,0,4095));
   Tlc.set(38, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==14){
   Tlc.set(37, map(r,0,255,0,4095));
   Tlc.set(36, map(g,0,255,0,4095));
   Tlc.set(35, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==15){
   Tlc.set(34, map(r,0,255,0,4095));
   Tlc.set(33, map(g,0,255,0,4095));
   Tlc.set(32, map(b,0,255,0,4095)); 
  }    
}

So I assume with this part

     if (Serial.available()>2)
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
     }

regulary I empty the buffer and it will have always free space.

Conclusion : The problem I have isn’t related with buffer size :frowning:

Idea : I will try this without TLC5940 but sending a feedback on a software serial port and monitorizing it with a serial monitor to see exactly what’s happening…

Good! Here are the results :smiley:

Firstly, this is the hardware setup:

Secondly, this is the code :

#include <SoftwareSerial.h>

byte midi_on = 0x90;
byte midi_off = 0x80;
byte location_byte;
byte in_note;
byte in_volume;
boolean newNote = false;

SoftwareSerial FWSerial(3, 4); // RX, TX

void check_midi()
 {

     if (Serial.available()>2)
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
       if(location_byte == midi_on || location_byte == midi_off) newNote = true; 
     }
 }

void setup() {
pinMode(13, OUTPUT);
Serial.begin(31250);
FWSerial.begin(19200);
}

void loop() {
check_midi();
if(newNote){ 

  if (location_byte == midi_on){
    FWSerial.print("ON:");
    FWSerial.print(in_note,DEC);
    FWSerial.print(" - ");
    FWSerial.println(in_volume,DEC);
  }

  if (location_byte == midi_off){
    FWSerial.print("OFF:");
    FWSerial.print(in_note,DEC);
    FWSerial.print(" - ");
    FWSerial.println(in_volume,DEC);    
  }  

 newNote = false;
  
}
}

Third : The results (and now we know where is the problem :smiling_imp: )

http://s8.postimg.org/ckciz4kat/results.png

Analysis :

  • When the system works correctly, first I receve all the note OFF then I receive the notes ON.
  • When the system gets buggy, we can see I receive two times the note off then two times the note ON, that explains why the interpretation isn’t correct!

What do you think is the cause of this?

Regards.

That looks most odd. So it is your sequencer that is sending the extra stuff!

Not sure however why your code can't cope with this. I did notice that your code refreshes all the LEDs for every note you receive when all you need to do is to refresh the strip that corresponds to the note just received.

What I would do is to write it so that you only refresh the one strip per note. The code should be a lot shorter as well.

Finally…

I solved it!

Cubase was the error.

With Ableton it works like a charm.

Here is the video:

Here is the working code with TLC5940 and Ableton:

#include "Tlc5940.h"

byte midirgb[128];

//These are the midi commands to interact with the arduino

byte midi_on = 0x90;
byte midi_off = 0x80;
byte location_byte;
byte in_note;
byte in_volume;
boolean newNote = false;

void check_midi()
 {

     if (Serial.available()>2)
     {
       location_byte = Serial.read(); //read first byte
       in_note = Serial.read();       //read next byte
       in_volume = Serial.read();     //read final byte
       if(location_byte == midi_on || location_byte == midi_off) newNote = true; 
     }
 }

void setup() {
Tlc.init();
Serial.begin(31250);
}

void loop() {

for (int i=0; i <= 47; i++){  
check_midi();
if(newNote){ 
  if (location_byte == midi_on) midirgb[in_note] = in_volume;
  if (location_byte == midi_off) midirgb[in_note] = 0;
   newNote = false;
  }
}

   Tlc.clear();
   for (int i=0; i <= 15; i++){
     RGBTLCSet256(i,midirgb[i],midirgb[i+16],midirgb[i+32]);
   }
   Tlc.update(); 
  
}

void RGBTLCSet256(byte ledstrip, byte r, byte g, byte b)
{
  if (ledstrip==0){
   Tlc.set(15, map(r,0,255,0,4095));
   Tlc.set(14, map(g,0,255,0,4095));
   Tlc.set(13, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==1){
   Tlc.set(12, map(r,0,255,0,4095));
   Tlc.set(11, map(g,0,255,0,4095));
   Tlc.set(10, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==2){
   Tlc.set(9, map(r,0,255,0,4095));
   Tlc.set(8, map(g,0,255,0,4095));
   Tlc.set(7, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==3){
   Tlc.set(6, map(r,0,255,0,4095));
   Tlc.set(5, map(g,0,255,0,4095));
   Tlc.set(4, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==4){
   Tlc.set(3, map(r,0,255,0,4095));
   Tlc.set(2, map(g,0,255,0,4095));
   Tlc.set(1, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==5){
   Tlc.set(0, map(r,0,255,0,4095));
   Tlc.set(31, map(g,0,255,0,4095));
   Tlc.set(30, map(b,0,255,0,4095)); 
  }
  
  if (ledstrip==6){
   Tlc.set(29, map(r,0,255,0,4095));
   Tlc.set(28, map(g,0,255,0,4095));
   Tlc.set(27, map(b,0,255,0,4095)); 
  }
  
 if (ledstrip==7){
   Tlc.set(26, map(r,0,255,0,4095));
   Tlc.set(25, map(g,0,255,0,4095));
   Tlc.set(24, map(b,0,255,0,4095)); 
  }

 if (ledstrip==8){
   Tlc.set(23, map(r,0,255,0,4095));
   Tlc.set(22, map(g,0,255,0,4095));
   Tlc.set(21, map(b,0,255,0,4095)); 
  }
  
 if (ledstrip==9){
   Tlc.set(20, map(r,0,255,0,4095));
   Tlc.set(19, map(g,0,255,0,4095));
   Tlc.set(18, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==10){
   Tlc.set(17, map(r,0,255,0,4095));
   Tlc.set(16, map(g,0,255,0,4095));
   Tlc.set(47, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==11){
   Tlc.set(46, map(r,0,255,0,4095));
   Tlc.set(45, map(g,0,255,0,4095));
   Tlc.set(44, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==12){
   Tlc.set(43, map(r,0,255,0,4095));
   Tlc.set(42, map(g,0,255,0,4095));
   Tlc.set(41, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==13){
   Tlc.set(40, map(r,0,255,0,4095));
   Tlc.set(39, map(g,0,255,0,4095));
   Tlc.set(38, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==14){
   Tlc.set(37, map(r,0,255,0,4095));
   Tlc.set(36, map(g,0,255,0,4095));
   Tlc.set(35, map(b,0,255,0,4095)); 
  }  
  
 if (ledstrip==15){
   Tlc.set(34, map(r,0,255,0,4095));
   Tlc.set(33, map(g,0,255,0,4095));
   Tlc.set(32, map(b,0,255,0,4095)); 
  }    
}

Thanks a lot for your help :slight_smile: :slight_smile: :slight_smile: