Midi IN velocity value to led output VU meter

Hi everyone,

i've been playing with midi out for a while, and everything works fine. :slight_smile:

so now for midi in... i've been struggling with this some more, but after some time i found some solutions.

for an example, i can press a button and my traktor pro starts playing while returning the signal and turning on a led while the songs is being played.

so far so good. there is only one last bump in the road and that's the VU meter.

i thought this wouldn't be a problem cause traktor gives me the ability to send midi values between 0 to 127, but i just cant get the coding right...

i tried changing different examples from this forum, but no luck so far...

this is what i'm doing right now: (i know it's pretty verbose)

byte incomingByte;
byte note;
byte velocity;
byte check;

int ledA = 10;  
int ledB = 9;  
int ledC = 8;  
int ledD = 7;  
int ledE = 6;
int ledF = 5;
int ledG = 4;

void setup()   {                

pinMode(ledA, OUTPUT);     
pinMode(ledB, OUTPUT);     
pinMode(ledC, OUTPUT);     
pinMode(ledD, OUTPUT);     
pinMode(ledE, OUTPUT);   
pinMode(ledF, OUTPUT);   
pinMode(ledG, OUTPUT);   
Serial.begin(31250);

}


void loop ()
{
     
 if (Serial.available() > 0)
 {
  incomingByte = Serial.read();
  delayMicroseconds(400);
   
      note = Serial.read();
      delayMicroseconds(400);
      velocity = Serial.read();
        
          if ((note== 0)&&(velocity>=0)) 
          { digitalWrite(ledA,HIGH);}
           else{ digitalWrite(ledA, LOW);}

         if ((note== 0)&&(velocity>=20))
          { digitalWrite(ledA,HIGH);
        digitalWrite(ledB,HIGH);}
          
         else{
          digitalWrite(ledA, LOW);
          digitalWrite(ledB,LOW);}

         if ((note== 0)&&(velocity>=40))
          { digitalWrite(ledA,HIGH);
        digitalWrite(ledB,HIGH);
        digitalWrite(ledC,HIGH);}
          
          else{
          digitalWrite(ledA, LOW);
          digitalWrite(ledB,LOW);
        digitalWrite(ledC,LOW);}

         if ((note== 0)&&(velocity>=60))
          {digitalWrite(ledA,HIGH);
        digitalWrite(ledB,HIGH);
        digitalWrite(ledC,HIGH);
        digitalWrite(ledD,HIGH);}
          
           else{
          digitalWrite(ledA, LOW);
          digitalWrite(ledB,LOW);
        digitalWrite(ledC,LOW);
        digitalWrite(ledD,LOW);}

         if ((note== 0)&&(velocity>=80))
          {digitalWrite(ledA,HIGH);
        digitalWrite(ledB,HIGH);
        digitalWrite(ledC,HIGH);
        digitalWrite(ledD,HIGH);
        digitalWrite(ledE,HIGH);}
          else{
          digitalWrite(ledA, LOW);
          digitalWrite(ledB,LOW);
        digitalWrite(ledC,LOW);
        digitalWrite(ledD,LOW);
        digitalWrite(ledE,LOW);}

         if ((note== 0)&&(velocity>=90))
          { digitalWrite(ledA,HIGH);
        digitalWrite(ledB,HIGH);
        digitalWrite(ledC,HIGH);
        digitalWrite(ledD,HIGH);
        digitalWrite(ledE,HIGH);
        digitalWrite(ledF,HIGH);}
           else{
          digitalWrite(ledA, LOW);
          digitalWrite(ledB,LOW);
        digitalWrite(ledC,LOW);
        digitalWrite(ledD,LOW);
        digitalWrite(ledE,LOW);
        digitalWrite(ledF,LOW);
}

         if ((note== 0)&&(velocity>=100))
          {  digitalWrite(ledA,HIGH);
        digitalWrite(ledB,HIGH);
        digitalWrite(ledC,HIGH);
        digitalWrite(ledD,HIGH);
        digitalWrite(ledE,HIGH);
        digitalWrite(ledF,HIGH);
        digitalWrite(ledG,HIGH);}
           else{
          digitalWrite(ledA, LOW);
          digitalWrite(ledB,LOW);
        digitalWrite(ledC,LOW);
        digitalWrite(ledD,LOW);
        digitalWrite(ledE,LOW);
        digitalWrite(ledF,LOW);
        digitalWrite(ledG,LOW);}


}

well the leds light up, but it has to much latency... it continues to light up few seconds after the music stopped..
also the leds have such a short period of being on, you barely see they work...

but thanx, i'll try looking into the velocity some more..

ehm,, well that would be a small language problem...

i'll try to explain it again.

about the latency:
it continues to light up few seconds after the music stopped.. and i just found out, that the midi activity led on my cakewalk interface is still lit, although the music is stopped....

edit

I've spend some time looking into this problem. i tried a little arduino code to read note 0 at velocity 127 (corresponding to the PLAY button), and this works without or very little latency. it seems to be the program that gradually fades out the vu meter when i stop the music.

byte incomingByte;
byte note;
byte velocity;
byte check;
int statusLed = 13;


void setup()
{
  //start serial with midi baudrate 31250 or 38400 for debugging
  Serial.begin(31250);

}


void loop ()
{

  if (Serial.available() > 0)
  {
    incomingByte = Serial.read();
    delayMicroseconds(400);                   //with out the delay it doesn't work, although i know it should

    if (incomingByte== 144)
    {
      note = Serial.read();
        delayMicroseconds(400);               //with out the delay it doesn't work, although i know it should
      velocity = Serial.read();
         if ((note== 0)&&(velocity==127) )
          { // note on
        digitalWrite(statusLed,HIGH);
          }
    else if ((note== 0)&&(velocity==0) )
    { // note off
  digitalWrite(statusLed,LOW);

      
    }
   
  }
}

}

about the vu meter in general:
the led's light up, but not as bright as i would expect... and i think that's because they are lit for a to short period..

basically my code just makes all the leds blink... so i tried this: (but still not working..)

if (velocity >= 0 || velocity<=30)
          {  
          digitalWrite(ledA,HIGH);
          }

if (velocity >= 30 || velocity<=50)
          {  
          digitalWrite(ledA,HIGH);
          digitalWrite(ledB,HIGH);
          }

etc, etc.

I just found a way to check the values my program is sending..Midi Monitor..

23:06:57.238      From 1      Note On      1      C-2      125
23:06:57.273      From 1      Note On      1      C-2      126
23:06:57.320      From 1      Note On      1      C-2      127
23:06:57.354      From 1      Note On      1      C-2      120
23:06:57.400      From 1      Note On      1      C-2      114
23:06:57.435      From 1      Note On      1      C-2      116
23:06:57.467      From 1      Note On      1      C-2      110
23:06:57.517      From 1      Note On      1      C-2      103
23:06:57.540      From 1      Note On      1      C-2      97
23:06:57.598      From 1      Note On      1      C-2      91
23:06:57.644      From 1      Note On      1      C-2      85
23:06:57.679      From 1      Note On      1      C-2      125
23:06:57.714      From 1      Note On      1      C-2      127
23:06:57.760      From 1      Note On      1      C-2      125
23:06:57.796      From 1      Note On      1      C-2      119
23:06:57.842      From 1      Note On      1      C-2      116
23:06:57.877      From 1      Note On      1      C-2      110
23:06:57.900      From 1      Note On      1      C-2      104
23:06:57.958      From 1      Note On      1      C-2      98
23:06:57.993      From 1      Note On      1      C-2      91
23:06:58.039      From 1      Note On      1      C-2      85
23:06:58.074      From 1      Note On      1      C-2      116
23:06:58.120      From 1      Note On      1      C-2      110
23:06:58.155      From 1      Note On      1      C-2      124
23:06:58.202      From 1      Note On      1      C-2      127
23:06:58.260      From 1      Note On      1      C-2      121
23:06:58.318      From 1      Note On      1      C-2      115
23:06:58.353      From 1      Note On      1      C-2      109
23:06:58.399      From 1      Note On      1      C-2      103
23:06:58.434      From 1      Note On      1      C-2      96
23:06:58.480      From 1      Note On      1      C-2      90
23:06:58.515      From 1      Note On      1      C-2      84
23:06:58.562      From 1      Note On      1      C-2      85
23:06:58.596      From 1      Note On      1      C-2      79
23:06:58.620      From 1      Note On      1      C-2      127
23:06:58.712      From 1      Note On      1      C-2      126
23:06:58.759      From 1      Note On      1      C-2      120
23:06:58.794      From 1      Note On      1      C-2      114
23:06:58.840      From 1      Note On      1      C-2      108
23:06:58.875      From 1      Note On      1      C-2      102
23:06:58.921      From 1      Note On      1      C-2      96
23:06:58.956      From 1      Note On      1      C-2      90
23:06:58.982      From 1      Note On      1      C-2      83

so no problems there...

this morning i started again on this coding problem.. after lying awake at night about what the heck is wrong with this... so i tried to simplify... but it still doesn't give the desired effect..

byte incomingByte;
byte note;
byte velocity;

int ledA = 9;
int ledB = 8;
int ledC = 7;
int ledD = 6;
int ledE = 5;
int statusled = 13;

void setup()
{
  //start serial with midi baudrate 31250 or 38400 for debugging
  Serial.begin(31250);
  
  pinMode(ledA, OUTPUT);     
  pinMode(ledB, OUTPUT);     
  pinMode(ledC, OUTPUT);     
  pinMode(ledD, OUTPUT);     
  pinMode(ledE, OUTPUT);             
  pinMode(statusled, OUTPUT);   
}


void loop ()
{

  if (Serial.available() > 0)
  {
    incomingByte = Serial.read();
   delayMicroseconds(400);

    if (incomingByte== 144)
    {               
        digitalWrite(statusled,HIGH);               
      note = Serial.read();

      delayMicroseconds(400);

      velocity = Serial.read();

         if (velocity >= 0 )
          { 
        digitalWrite(ledA,HIGH);
          }
    
         if(velocity >= 20 )
          { 
        digitalWrite(ledB,HIGH);
          }
    
         if(velocity >= 40)
          { 
        digitalWrite(ledC,HIGH);
          }
    
         if(velocity >= 70 )
          { 
        digitalWrite(ledD,HIGH);
          }
    
         if(velocity >= 100 )
          { 
        digitalWrite(ledE,HIGH);
          }
    
  digitalWrite(ledA,LOW);
  digitalWrite(ledB,LOW);
  digitalWrite(ledC,LOW);
  digitalWrite(ledD,LOW);
  digitalWrite(ledE,LOW);
   
  }
  
  else{digitalWrite(statusled, LOW);}

  }
}

sorry for this bump...

i tried reading a single midi note with a fixed velocity, with led feedback, this gives no trouble

i tried to read a single midi note with a changing velocity , with led feedback, i just can't get it to work

the most significant changes since my first post can be read in the reply above this one...

can somebody please give me another hint?

Every time you do a
note = Serial.read();
you need to check there is data in the buffer to read. This is only happening one place in your code not every time.
It might be better to do:-
if(Serial.available() > 2)

so you know you have at least the three bytes for a MIDI not input before you start pulling bytes out.
I think if you do this you will find that you can take those delays out.

Thanx Mike! if (Serial.available() > 2) took care of the delay stuff :slight_smile:

and thanx richard for pointing me to the led without delay example, but about the led without delay example, i just cant seem to grasp what really happens within the code...
i'll ask a friend to translate the comments for me, maybe that would help..

what i did found out was the MAP function! :slight_smile: this takes care for part of the if statements,

so i came up with this code (below) and this code works although the refresh rate is still a bit slow. i guess i have to find another way to get rid of the other if statements..

byte incomingByte;
byte note;
byte velocity;

int statusled = 13;

  int ledx=3;  

  int val =0;

void setup()
{
  //start serial with midi baudrate 31250 or 38400 for debugging
  Serial.begin(31250);
  
  pinMode(9, OUTPUT);     
  pinMode(8, OUTPUT);     
  pinMode(7, OUTPUT);     
  pinMode(6, OUTPUT);     
  pinMode(5, OUTPUT);             
  pinMode(4, OUTPUT);             
  pinMode(3, OUTPUT);            
  pinMode(statusled, OUTPUT);   
}


void loop ()
{

  if (Serial.available() > 2)
  { digitalWrite(statusled,HIGH);      
    incomingByte = Serial.read();

   if (incomingByte== 144)
    {               
                
      note = Serial.read();
       if (note == 1)
        {
      velocity = Serial.read();
          val = map(velocity, 0, 110, 3, 9);
         if (velocity >= 1 )
          { 
         while  (ledx < val+1)  
            {
           digitalWrite(ledx,HIGH);
           ledx++;
             }
          }
          ledx=3;



         if (velocity <= 1 )
          { 
        digitalWrite(3,LOW);
          }
    
         if(velocity <= 18 )
          { 
        digitalWrite(4,LOW);
          }
    
         if(velocity <= 36)
          { 
        digitalWrite(5,LOW);
          }
    
         if(velocity <= 54 )
          { 
        digitalWrite(6,LOW);
          }
    
         if(velocity <= 65 )
          { 
        digitalWrite(7,LOW);
          }
         if(velocity <= 80 )
          { 
        digitalWrite(8,LOW);
          }        
          if(velocity <= 120 )
          { 
        digitalWrite(9,LOW);
          }
  }
  }
  
  else{digitalWrite(statusled, LOW);}

  }
}

Unless you are only playing simple melody lines with one note at a time, it is not clear how you intend to deal with multiple notes?

well i only need one VU meter, that would be the master VU meter. so i only need to read one note, the only thing important is the velocity...

I don't like this bit of code, it has the potential for wraping round and causing a delay:-

while  (ledx < val+1)  
        {
         digitalWrite(ledx,HIGH);
         ledx++;
         }

Try replacing it with:-

for(int i= 3; i<10; i++) {
   digitalWrite(i,HIGH);
}
while  (ledx < val+1)
        {
         digitalWrite(ledx,HIGH);
         ledx++;
         }

replaced with:

for(int i= 3; i<10; i++) {
   digitalWrite(i,HIGH);
}

just replaced it, but i can't really tell the difference when looking at the output.

although when looking very close with my room lights out, i see the upper leds (highest velocity value) blink very very shortly.

could you explain, why WHILE could give a delay?

why WHILE could give a delay?

Because it relies on two variables, and incrementing them. So if any of the variables were to get out of alignment it could cause a lot of looping in that function. The structure I gave is a simple limited function and is much better programming practice.

i see the upper leds (highest velocity value) blink very very shortly.

As outputting a LOW on the pin is the only way to turn on the LED (is this correct) then trace where this is happening.
Post your whole code as you have it now and I will have a look.

As outputting a LOW on the pin is the only way to turn on the LED (is this correct) then trace where this is happening.
Post your whole code as you have it now and I will have a look.

for(int i= 2; i<10; i++) {
   digitalWrite(i,HIGH);
}

i've changed 3 to 2 because i added a led...this is how the code looks now:

byte incomingByte;
byte note;
byte velocity;

int statusled = 13;
int ledx=2;  
int val =0;
  
void setup()
{
  Serial.begin(31250);
  pinMode(9, OUTPUT);    
  pinMode(8, OUTPUT);    
  pinMode(7, OUTPUT);    
  pinMode(6, OUTPUT);    
  pinMode(5, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(statusled, OUTPUT);  
}


void loop ()
{

  if (Serial.available() > 2)
  { 
    digitalWrite(statusled,HIGH);
    incomingByte = Serial.read();

   if (incomingByte== 144)
    {              
                
      note = Serial.read();
       if (note == 1)
        {
      velocity = Serial.read();
          val = map(velocity, 0, 110, 2, 9);
         if (velocity >= 1 )
          {
for(int i= 2; i<10; i++) {
   digitalWrite(i,HIGH);
}
 
      
          }
         



         if (velocity <= 1 )
          {
        digitalWrite(2,LOW);
          }
    
         if(velocity <= 18 )
          {
        digitalWrite(3,LOW);
          }
    
         if(velocity <= 36)
          {
        digitalWrite(4,LOW);
          }
    
         if(velocity <= 54 )
          {
        digitalWrite(5,LOW);
          }
    
         if(velocity <= 65 )
          {
        digitalWrite(6,LOW);
          }
         if(velocity <= 80 )
          {
        digitalWrite(7,LOW);
          }
            if(velocity <= 100 )
          {
        digitalWrite(8,LOW);
          }        
          if(velocity <= 120 )
          {
        digitalWrite(9,LOW);
          }
  }
  }
  
  else{digitalWrite(statusled, LOW);}

  }
}

and this is a bit off topic:

to night I got this completely different idea, what if i was to use PWM output. using the MAP statement, like:

velocity = Serial.read();
val = map(velocity, 0, 127, 0, 255);

so the velocity would correspond with the voltage output.

to drive a lm3914/lm3915?
http://www.datasheetcatalog.org/datasheet/nationalsemiconductor/DS007970.PDF

wouldn't this be much simpler?

See if this makes any difference to what you see:-

byte incomingByte;
byte note;
byte velocity;

int statusled = 13;
int ledx=2;  
int val =0;
  
void setup()
{
  Serial.begin(31250);
  pinMode(9, OUTPUT);    
  pinMode(8, OUTPUT);    
  pinMode(7, OUTPUT);    
  pinMode(6, OUTPUT);    
  pinMode(5, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(statusled, OUTPUT);  
}

void loop ()
{
  if (Serial.available() > 2)
  {
    digitalWrite(statusled,HIGH);
    incomingByte = Serial.read();
   if (incomingByte == 144) 
    {                      
    note = Serial.read();
     if (note == 1)
      {
    velocity = Serial.read();
        val = map(velocity, 0, 110, 2, 9);
       if (velocity >= 1 ) {
              for(int i= 2; i<10; i++) {  // turn all LEDs off
               digitalWrite(i,HIGH);
               }    
       if (velocity <= 1 ) digitalWrite(2,LOW); // this will never switch becaus you only get here if velocity is >1    
          if(velocity <= 18 ) digitalWrite(3,LOW);
       if(velocity <= 36) digitalWrite(4,LOW);
       if(velocity <= 54 )digitalWrite(5,LOW);
       if(velocity <= 65 ) digitalWrite(6,LOW);
       if(velocity <= 80 ) digitalWrite(7,LOW);
           if(velocity <= 100 ) digitalWrite(8,LOW);      
       if(velocity <= 120 ) digitalWrite(9,LOW);
    }
  }  
  else {digitalWrite(statusled, LOW);}  // to do if note not = to 1
   }
  } // end of reading MIDI input
 } // end of loop

wouldn't this be much simpler?

No, this means generating an analogue voltage from the arduino.

thought it would be a good idea to show a small movie of what it is doing with your code Mike:

with the FOR statement as it is now, i don't have to use the MAP statement.

i used the MAP statement with the WHILE to put the leds on, according to the velocity at that moment.

but your approach of putting all led's on, read velocity and then put leds off, is a good one, i think

but maybe i could use the velocityMAP to turn them off a more accurate way?

well these are quick thoughts, have to get to work....

thanx so far!

OK not sure what you expect but they are doing what I would expect. Note that your code only updates the LEDs when a new note comes along so the delay you are seeing is the delay before the next note comes in. You are also not catching the note off command just relying on the note on with zero velocity. This is what some units send but not all.

but your approach of putting all led's on, read velocity and then put leds off, is a good one, i think

It's not my approach it's yours, I just tidied up the code, that is what you were trying to do wasn't it?
If not I would flip it round, that is, turn all the LEDs off in the for loop and then turn the LEDs you want lit on with the if statements. That will stop the ghost LEDs. However, as I haven't got your wiring I don't know if a LOW on the digital output turns the LED on or off. I did ask earlier but you didn't respond.

needle,
im trying to replicate your setup...
are you using this serial-midi converter? cheers!
-sj

and this is a bit off topic:

to night I got this completely different idea, what if i was to use PWM output. using the MAP statement, like:

Code:
velocity = Serial.read();
val = map(velocity, 0, 127, 0, 255);

so the velocity would correspond with the voltage output.

to drive a lm3914/lm3915?
HTTP 301 This page has been moved

wouldn't this be much simpler?

this is what first came to mind when i saw this thread.

you can use a RC circuit to convert the PWM to analog voltage that the lm39xx understands.

as far as which is more efficient / elegant code wise, i don't know as im still a n0ob.... the way i pictured it was to assign a timer to the pwm generation, main loop reads and maps the values. this should be both fast and accurate if it works the way i think it does. again, idk for sure....
-sj

the way i pictured it was to assign a timer to the pwm generation,

I am not sure what you mean by this.

The main problem with this approach is that first of all you need the liner part not the log one. Then you have the problem of smoothing the PWM output so that it doesn't jitter the LEDs yet is not smoothed too much that the response is damped. See the later part of this page for a discussion of simple filters in PWM circuits:- http://www.thebox.myzen.co.uk/Tutorial/PWM.html

Finally you have no control over the display if you want to change it, for example suppose you want just a single LED lit depending on the peak voltage. In software this would be simple but if you use one of these chips it would be impossible.

In general I am all for using hardware but only when it brings something to the party, it has to earn it's keep.

i was referring to using a specific timer for generating the pwm independent of the main code. ie: pg. 113 - 165 of the atmega manual.

the lm3914 is linear. the lm3915 is log. i have this working at the moment with a lm3915 as thats all i have on hand.

i believe traktor has the ability to toggle linear and logarithmic outputs via the "blend" function.

i agree that this limits your ability to light the bar graph anyway you please, but i can't think of too many other ways i would like my bar graphs to light up. dot & bar modes can still be toggled via software as could intensity.

so im having the same issue... led's lag well behind real time and stay lit well beyond hitting pause. one thing i noticed is that the activity led on the ftdi dongle is showing data flowing after hitting pause as well. this would lead me to believe that the issue is closer related to the serial-midi conversion software im using rather than the arduino. anywho, heres the code. i by no means recommend this as a viable solution! pretty much worthless as a VU meter as of now, but i think its a viable option worth further exploration.

byte incomingByte;
byte note;
byte velocity;

int statusled = 13;
int val =0;

int ledPin = 9;

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

void loop () {
  if (Serial.available()) {
    velocity = Serial.read();
    val = map(velocity, 0, 127, 255, 0);
    analogWrite(ledPin, val);
  }
}

Hi Sonicj, nice to have more input on this subject.

are you using this serial-midi converter? cheers!

i use a Cakewalk (roland) um-2g to send and receive midi trough usb.

so:

traktor pro sends note --> um2-g translates --> arduino receives

im trying to replicate your setup...

i guess you already know by now, but i'll try to make a drawing in Fritzing:

anywho, heres the code. i by no means recommend this as a viable solution!

Quite.

What makes you think that code picks up the velocity byte out of a MIDI message. See the code posted earlier.

i have this working at the moment with a lm3915 as thats all i have on hand.

could you show us your wiring or schematics? maybe your code would make more sense to me.

i believe traktor has the ability to toggle linear and logarithmic outputs via the "blend" function.

i currently use the blend function, this makes traktor ouput the velocity on one note.

if you put the blend function off, you would have to read multiple notes, to know velocity.

so for both ideas, the blend function should be on! just because this let's us read just one note and it's velocity.