Micro Pro Midi Foot Controller - problems with buttons and Midi

Hi there,

I recently started a project making a simple foot pedal with 9 push buttons (like these: Elektronik und Technik bei reichelt elektronik günstig bestellen...=2&ARTICLE=19988&GROUPID=3277&artnr=T+250A+WS ) and a Arduino Pro Micro (like that: https://www.sparkfun.com/products/12640 ).
It is supposed to controll a Looper, a DAW, virtual Instruments, whatever (probably in the future).
I connected the buttons to GROUND and directly to the digital PINs using INPUT_PULLUP instead of physical resistors. As simple as it could be.

But as I am new to coding and don't have too much time learning about all those things (even though I'm actually enjoying it), I just came along with some problems:

It seems that the buttons send more than just one signal as they should. They send one when pressed, and one when releasing. Sometimes probably even more. I'm not shure.

But also I have some trouble with connecting the whole thing as a MIDI Device and using it in a DAW (Cakewalk SONAR in my case), for example.
So if I run Hairless Midi (before that having started LoopMidi with a new LoopMidi Port) and press some buttons, I can see input and it seems to be correct. Ecxept of errors like in that example:

+9.014 - Warning: got a status byte when we were expecting 2 more data bytes, sending possibly incomplete MIDI message 0x81
+9.014 - Serial In: Ch 2: Note %2 off velocity %3
+9.014 - Serial In: Ch 1: Note 40 on velocity 127
+9.014 - Warning: got a status byte when we were expecting 1 more data bytes, sending possibly incomplete MIDI message 0x90

I have an USB audio interface (Focusrite Scarlett 2i4) which I use as my soundcard in the DAW. Choosing loopMIDI for the MIDI IN and MIDI OUT in Hairless Midi gives me those errors above and I can't get any MIDI signal in my DAW. Choosing Microsoft GS Wavetable Synth for the MIDI OUT I can hear a piano with a quite big latency (around half a second probably), where I also can hear that the buttons trigger more than once.

Being new to programming, I really would appreciate any help and be very thankful!

Read the rules, post the code correctly.
Your problems

  1. buttons sending more than one press - it is called contact bounce, they all do that. If it is a problem then Google Arduino debounce.

  2. you are talking to Hairless at the wrong speed. You are using 9600 baud, Hairless expects something much faster.

OK sorry for posting the code the wrong way. I tried with different baud rate too, like 31250 baud (as i have changed i
n the code below) and changed it to 38400 in Hairless Midi, but same results.

It seems like I will have to work a lot on this... I'm not shure if I should keep that code and work on it or start from the beginning and if I should probably include the Arduino Midi Library or not.
I want to make it as simple as it can be, but for me as a beginner in programming this seems to be more work than I can possibly do in my freetime.
I am trying to understand the debouncing, but I am not shure how to include in my code...

If there are any suggestions, I would be really happy!
Thanks so far!

int button2 = LOW;
int button2Old = LOW;
int button3 = LOW;
int button3Old = LOW;
int button4 = LOW;
int button4Old = LOW;
int button5 = LOW;
int button5Old = LOW;
int button6 = LOW;
int button6Old = LOW;
int button7 = LOW;
int button7Old = LOW;
int button8 = LOW;
int button8Old = LOW;
int button9 = LOW;
int button9Old = LOW;
int button10 = LOW;
int button10Old = LOW;


void setup() {
 Serial.begin(31250);
 pinMode(2, INPUT_PULLUP);
 pinMode(3, INPUT_PULLUP);
 pinMode(4, INPUT_PULLUP);
 pinMode(5, INPUT_PULLUP);
 pinMode(6, INPUT_PULLUP);
 pinMode(7, INPUT_PULLUP);
 pinMode(8, INPUT_PULLUP);
 pinMode(9, INPUT_PULLUP);
 pinMode(10, INPUT_PULLUP);
}

void loop(){
 button2 = digitalRead(2);
 
 if (button2 == HIGH && button2Old == LOW) {
 Serial.write(144); // 1001 0000 = Note On Kanal 1
 Serial.write(36); //Note C1
 Serial.write(127);
 button2Old = button2;
 }
 if (button2 == LOW && button2Old == HIGH) {
 Serial.write(144); // 1001 0000 = Note On Kanal 1
 Serial.write(36); //Note C1
 Serial.write(0-127);
 button2Old = button2;
 } 
 
 button3 = digitalRead(3);
 
 if (button3 == HIGH && button3Old == LOW) {
 Serial.write(144); 
 Serial.write(38); 
 Serial.write(127);
 button3Old = button3;
 }
 if (button3 == LOW && button3Old == HIGH) {
 Serial.write(144); 
 Serial.write(38); 
 Serial.write(0-127);
 button3Old = button3;
 }

  button4 = digitalRead(4);
 
 if (button4 == HIGH && button4Old == LOW) {
 Serial.write(144);
 Serial.write(40); 
 Serial.write(127);
 button4Old = button4;
 }
 if (button4 == LOW && button4Old == HIGH) {
 Serial.write(144); 
 Serial.write(40); 
 Serial.write(0-127);
 button4Old = button4;
 } 
 
 button5 = digitalRead(5);
 
 if (button5 == HIGH && button5Old == LOW) {
 Serial.write(144); 
 Serial.write(41); 
 Serial.write(127);
 button5Old = button5;
 }
 if (button5 == LOW && button5Old == HIGH) {
 Serial.write(144); 
 Serial.write(41); 
 Serial.write(0-127);
 button5Old = button5;
 }

  button6 = digitalRead(6);
 
 if (button6 == HIGH && button6Old == LOW) {
 Serial.write(144); 
 Serial.write(43); 
 Serial.write(127);
 button6Old = button6;
 }
 if (button6 == LOW && button6Old == HIGH) {
 Serial.write(144); 
 Serial.write(43); 
 Serial.write(0-127);
 button6Old = button6;
 } 
 
 button7 = digitalRead(7);
 
 if (button7 == HIGH && button7Old == LOW) {
 Serial.write(144); 
 Serial.write(45); 
 Serial.write(127);
 button7Old = button7;
 }
 if (button7 == LOW && button7Old == HIGH) {
 Serial.write(144); 
 Serial.write(45); 
 Serial.write(0-127);
 button7Old = button7;
 }

  button8 = digitalRead(8);
 
 if (button8 == HIGH && button8Old == LOW) {
 Serial.write(144); 
 Serial.write(47); 
 Serial.write(127);
 button8Old = button8;
 }
 if (button8 == LOW && button8Old == HIGH) {
 Serial.write(144); 
 Serial.write(47); 
 Serial.write(0-127);
 button8Old = button8;
 } 
 
 button9 = digitalRead(9);
 
 if (button9 == HIGH && button9Old == LOW) {
 Serial.write(144); 
 Serial.write(48); 
 Serial.write(127);
 button9Old = button9;
 }
 if (button9 == LOW && button9Old == HIGH) {
 Serial.write(144); 
 Serial.write(48); 
 Serial.write(0-127);
 button9Old = button9;
 }

 button10 = digitalRead(10);
 
 if (button10 == HIGH && button10Old == LOW) {
 Serial.write(144); 
 Serial.write(50); 
 Serial.write(127);
 button10Old = button10;
 }
 if (button10 == LOW && button10Old == HIGH) {
 Serial.write(144); 
 Serial.write(50);
 Serial.write(0-127);
 button10Old = button10;
 }
}

like 31250 baud (as i have changed in the code below) and changed it to 38400 in Hairless Midi, but same results.

It has to be the same speed in both Hairless and your code.
Set both to 115200 baud.

Grumpy_Mike:
It has to be the same speed in both Hairless and your code.
Set both to 115200 baud.

OK, I did that, and the LoopMidi port is visible in my DAW. Great, thanks!

But there are some other problems:
It seems like it just sends the Midi data to all of the Midi tracks in my DAW (unlike for example my keyboard does), and plays them all together at the same time. Not how it usually works.
Any clue what that could be?

And the other big problem is the latency which is really high. Any idea how I could fix that?

Well I did notice that your code never sends any note off messages so that could be choking your DAW and causing a lag.

You are only sending notes on one channel so I guess your other problem is something to do with your DAW setup.

The code is very very turgid. It keeps doing the same thing over and over. It is time to learn about for loops and arrays and you will get that code down to less than 20 lines.

Well thanks again for your help.
I took that one code for one push button, modyfied it a little bit (probably wrong) and hoped, I could use it. But I should probably just start all over again.

Well I would really like to make this project happen, and also make the best out of it. It's just 9 buttons, and I also would like to make the code as good as possible. So I have a few questions:

  1. Is it possible to make that midi controller being recognized in a DAW as midi controller without having installed additional programs like LoopMidi and Hairless Midi?

  2. Should I include a Midi library or just do it in the code? I must say I still don't understand how these things work.

  3. What would be the best latency I could possibly get?

  4. Are there any projects (I have spent a lot of time on google already) and code I could use without writing everything from scratch?

  5. I don't even know which question to ask, but it seems I have to spend some time studying anyway.

So I would really appreciate any help and guidance, because I feel quite lost right now.
Thank you so far!!!

You can only make an Arduino Leonardo or a Micro look like a MIDI USB device.

For just sending MIDI stuff there is no need for a library.

I don't have a figure for this but it should be unnoticeable.

There are lots of projects like this but I am on my iPad at the moment and copy and pasting links does not work very good.

Having said that I have written a book on the subject at

Wow, thanks for that fast reply.

I thought (and I have read that somewhere) that the Pro Micro would be working with USB to Midi like the Leonardo, but, too bad then. Still would like to make it work...

So one question:

int button2 = LOW;
int button2Old = LOW;

void setup() {
 Serial.begin(115200);
}
void loop(){
 button2 = digitalRead(2);
 
 if (button2 == HIGH && button2Old == LOW) {
 Serial.write(144); // 1001 0000 = Note On Kanal 1
 Serial.write(36); //Note C1
 Serial.write(127);
 button2Old = button2;
 }
 if (button2 == LOW && button2Old == HIGH) {
 Serial.write(144); 
 Serial.write(36); 
 Serial.write(0);
 button2Old = button2;
 }

In the Arduino Software I get that error:

exit status 1
call of overloaded 'write(int)' is ambiguous

for Serial.write(0);

which should be the note-off command (i think?)

What is wrong there?

Integers are the default type for constants. You need to specify it is a byte with

Serial.write((byte)0);

Great, thanks, so I changed that in the code:

int button2 = LOW;
int button2Old = LOW;
int button3 = LOW;
int button3Old = LOW;
int button4 = LOW;
int button4Old = LOW;
int button5 = LOW;
int button5Old = LOW;
int button6 = LOW;
int button6Old = LOW;
int button7 = LOW;
int button7Old = LOW;
int button8 = LOW;
int button8Old = LOW;
int button9 = LOW;
int button9Old = LOW;
int button10 = LOW;
int button10Old = LOW;


void setup() {
 Serial.begin(115200);
 pinMode(2, INPUT_PULLUP);
 pinMode(3, INPUT_PULLUP);
 pinMode(4, INPUT_PULLUP);
 pinMode(5, INPUT_PULLUP);
 pinMode(6, INPUT_PULLUP);
 pinMode(7, INPUT_PULLUP);
 pinMode(8, INPUT_PULLUP);
 pinMode(9, INPUT_PULLUP);
 pinMode(10, INPUT_PULLUP);
}

void loop(){
 button2 = digitalRead(2);
 
 if (button2 == HIGH && button2Old == LOW) {
 Serial.write(144); // 1001 0000 = Note On Kanal 1
 Serial.write(36); //Note C1
 Serial.write(127);
 button2Old = button2;
 }
 if (button2 == LOW && button2Old == HIGH) {
 Serial.write(144); // 1001 0000 = Note On Kanal 1
 Serial.write(36); //Note C1
 Serial.write((byte)0);
 button2Old = button2;
 } 
 
 button3 = digitalRead(3);
 
 if (button3 == HIGH && button3Old == LOW) {
 Serial.write(144); 
 Serial.write(38); 
 Serial.write(127);
 button3Old = button3;
 }
 if (button3 == LOW && button3Old == HIGH) {
 Serial.write(144); 
 Serial.write(38); 
 Serial.write((byte)0);
 button3Old = button3;
 }

  button4 = digitalRead(4);
 
 if (button4 == HIGH && button4Old == LOW) {
 Serial.write(144);
 Serial.write(40); 
 Serial.write(127);
 button4Old = button4;
 }
 if (button4 == LOW && button4Old == HIGH) {
 Serial.write(144); 
 Serial.write(40); 
 Serial.write((byte)0);
 button4Old = button4;
 } 
 
 button5 = digitalRead(5);
 
 if (button5 == HIGH && button5Old == LOW) {
 Serial.write(144); 
 Serial.write(41); 
 Serial.write(127);
 button5Old = button5;
 }
 if (button5 == LOW && button5Old == HIGH) {
 Serial.write(144); 
 Serial.write(41); 
 Serial.write((byte)0);
 button5Old = button5;
 }

  button6 = digitalRead(6);
 
 if (button6 == HIGH && button6Old == LOW) {
 Serial.write(144); 
 Serial.write(43); 
 Serial.write(127);
 button6Old = button6;
 }
 if (button6 == LOW && button6Old == HIGH) {
 Serial.write(144); 
 Serial.write(43); 
 Serial.write((byte)0);
 button6Old = button6;
 } 
 
 button7 = digitalRead(7);
 
 if (button7 == HIGH && button7Old == LOW) {
 Serial.write(144); 
 Serial.write(45); 
 Serial.write(127);
 button7Old = button7;
 }
 if (button7 == LOW && button7Old == HIGH) {
 Serial.write(144); 
 Serial.write(45); 
 Serial.write((byte)0);
 button7Old = button7;
 }

  button8 = digitalRead(8);
 
 if (button8 == HIGH && button8Old == LOW) {
 Serial.write(144); 
 Serial.write(47); 
 Serial.write(127);
 button8Old = button8;
 }
 if (button8 == LOW && button8Old == HIGH) {
 Serial.write(144); 
 Serial.write(47); 
 Serial.write((byte)0);
 button8Old = button8;
 } 
 
 button9 = digitalRead(9);
 
 if (button9 == HIGH && button9Old == LOW) {
 Serial.write(144); 
 Serial.write(48); 
 Serial.write(127);
 button9Old = button9;
 }
 if (button9 == LOW && button9Old == HIGH) {
 Serial.write(144); 
 Serial.write(48); 
 Serial.write((byte)0);
 button9Old = button9;
 }

 button10 = digitalRead(10);
 
 if (button10 == HIGH && button10Old == LOW) {
 Serial.write(144); 
 Serial.write(50); 
 Serial.write(127);
 button10Old = button10;
 }
 if (button10 == LOW && button10Old == HIGH) {
 Serial.write(144); 
 Serial.write(50);
 Serial.write((byte)0);
 button10Old = button10;
 }
}

..and the Problems in Hairless Midi are gone and also those ones in my DAW.
So I should see how to use debounce the next days.

But the problem with the big latency is still there. It is much too high to use it. Trying to figure it out...

But the problem with the big latency is still there. It is much too high to use it.

That has to be down to your PC.

So I should see how to use debounce the next days.

Debounce is easy, just add a 20mS delay after you have sent the MIDI message.

Also have you noticed that a lot of lines keep being repeated?

if (button2 == HIGH && button2Old == LOW) {
 Serial.write(144); // 1001 0000 = Note On Kanal 1
 Serial.write(36); //Note C1
 Serial.write(127);
 button2Old = button2;
 }
 if (button2 == LOW && button2Old == HIGH) {
 Serial.write(144); // 1001 0000 = Note On Kanal 1
 Serial.write(36); //Note C1
 Serial.write((byte)0);
 button2Old = button2;
 }

All those serial writes are the same. Replace them with a function

void sendNote(byte message, byte note, byte velocity){
Serial.write(message); 
 Serial.write(note); 
 Serial.write(velocity);
}

Then you can simply use:-

if (button2 == HIGH && button2Old == LOW) {
 sendNote((144,36,127); // 1001 0000 = Note On Kanal 1
 button2Old = button2;
 }
 if (button2 == LOW && button2Old == HIGH) {
 sendNote((144,36,0);
 button2Old = button2;
 }

That is the first step in making your code smaller and easier to follow. Get you head round that and I will show you how to reduce it even more.

Hint, where would you put the debounce delay so it only needs to appear once in the whole program.

Great, thanks, so I changed the code:

int button2 = LOW;
int button2Old = LOW;
int button3 = LOW;
int button3Old = LOW;
int button4 = LOW;
int button4Old = LOW;
int button5 = LOW;
int button5Old = LOW;
int button6 = LOW;
int button6Old = LOW;
int button7 = LOW;
int button7Old = LOW;
int button8 = LOW;
int button8Old = LOW;
int button9 = LOW;
int button9Old = LOW;
int button10 = LOW;
int button10Old = LOW;


void setup() {
 Serial.begin(115200);
 pinMode(2, INPUT_PULLUP);
 pinMode(3, INPUT_PULLUP);
 pinMode(4, INPUT_PULLUP);
 pinMode(5, INPUT_PULLUP);
 pinMode(6, INPUT_PULLUP);
 pinMode(7, INPUT_PULLUP);
 pinMode(8, INPUT_PULLUP);
 pinMode(9, INPUT_PULLUP);
 pinMode(10, INPUT_PULLUP);
}
 
void sendNote(byte message, byte note, byte velocity){
Serial.write(message);
 Serial.write(note);
 Serial.write(velocity);
 delay (20);
}
void loop(){
 button2 = digitalRead(2);
 if (button2 == HIGH && button2Old == LOW) {
 sendNote(144,36,127);
 button2Old = button2;
 }
 if (button2 == LOW && button2Old == HIGH) {
 sendNote(144,36,0);
 button2Old = button2;
 } 
 button3 = digitalRead(3);
 if (button3 == HIGH && button3Old == LOW) {
 sendNote(144,38,127);
 button3Old = button3;
 }
 if (button3 == LOW && button3Old == HIGH) {
 sendNote(144,38,0);
 button3Old = button3;
 }  
 button4 = digitalRead(4);
 if (button4 == HIGH && button4Old == LOW) {
 sendNote(144,40,127);
 button4Old = button4;
 }
 if (button4 == LOW && button4Old == HIGH) {
 sendNote(144,40,0);
 button4Old = button4;
 } 
 button5 = digitalRead(5);
 if (button5 == HIGH && button5Old == LOW) {
 sendNote(144,41,127);
 button5Old = button5;
 }
 if (button5 == LOW && button5Old == HIGH) {
 sendNote(144,41,0);
 button5Old = button5;
 }  
 button6 = digitalRead(6);
 if (button6 == HIGH && button6Old == LOW) {
 sendNote(144,43,127);
 button6Old = button6;
 }
 if (button6 == LOW && button6Old == HIGH) {
 sendNote(144,43,0);
 button6Old = button6;
 } 
 button7 = digitalRead(7);
 if (button7 == HIGH && button7Old == LOW) {
 sendNote(144,45,127);
 button7Old = button7;
 }
 if (button7 == LOW && button7Old == HIGH) {
 sendNote(144,45,0);
 button7Old = button7;
 }  
 button8 = digitalRead(8);
 if (button8 == HIGH && button8Old == LOW) {
 sendNote(144,47,127);
 button8Old = button8;
 }
 if (button8 == LOW && button8Old == HIGH) {
 sendNote(144,47,0);
 button8Old = button8;
 } 
 button9 = digitalRead(9);
 if (button9 == HIGH && button9Old == LOW) {
 sendNote(144,48,127);
 button9Old = button9;
 }
 if (button9 == LOW && button9Old == HIGH) {
 sendNote(144,48,0);
 button9Old = button9;
 }
 button10 = digitalRead(10);
 if (button10 == HIGH && button10Old == LOW) {
 sendNote(144,50,127);
 button10Old = button10;
 }
 if (button10 == LOW && button10Old == HIGH) {
 sendNote(144,50,0);
 button10Old = button10;
 }
}

If I can figure out how to get rid of the latency, I might be happy with that code.
No idea still how to fix the latency. I'm running Windows 10 on that computer with a focusrite scarlett 2i4 audio interface.

And also Hairless Midi sometimes just doesn't work. I restart it, also LoopMidi, unplug the Pro Micro too, but many times it will not be recognized in Hairless Midi.

Is there a way to do what I want without those two programs, or any different way?

Thanks you so much again for your help!

Any suggestions for fixing the latency? :wink:

The latency is nothing to do with your code, it is not an Arduino problem.
I have just run your code on my system and I get no perceivable latency at all.
Do you want me to post a video of this? I am just using switches and Garage Band on my Mac.

It is possible that the problem is either in your DAW or most probably your operating system.

Just for completeness, here is your code written with arrays and loops. It is a lot shorter but it won't help you with your latency issue.

// simple switch MIDI trigger
boolean buttonLast[9];
const byte switchPin[] = {2,3,4,5,6,7,8,9,10}; // the 9 pins to use
const byte noteToSend [] = {36,38,40,41,43,45,47,48,50}; // notes to play for each pin
boolean button;

void setup() {
 Serial.begin(115200); // Using Hairless at the default speed
 for(int i=0; i< 10; i++){
 pinMode(switchPin[i], INPUT_PULLUP);
 buttonLast[i] = HIGH; // assume button not pressed at start
 }
}

void loop(){
  for(int i =0; i<9; i++){
   button = digitalRead(switchPin[i]);
    if (button == HIGH && buttonLast[i] == LOW) {
      sendNote(144,noteToSend[i],127);
      buttonLast[i] = button;
      }
    if (button == LOW && buttonLast[i] == HIGH) {
      sendNote(144,noteToSend[i],0);
      buttonLast[i] = button;
     }
  }
}

void sendNote(byte message, byte note, byte velocity){
 Serial.write(message);
 Serial.write(note);
 Serial.write(velocity);
 delay (20);
}

Well the thing is, I have a USB midi keyboard, too, which doesn't have any problems with latency. With my audio interface I usually go around 5ms. So I understand that it has nothing to do with the code, but I don't know what to do. Somehow there is a difference between how the arduino and my usb midi keyboard are treated by my system.

Could not find anything here or on google that has helped, but still looking...

Thank you for your help again, anyway!

Well thanks again so far. You really helped me a lot, Grumpy_Mike!

So I might look for a different forum to post or just open a new topic here for my latency issue.

Has anyone else an idea?

Ok well it seems that I have solved the latency problem by changing the latency directly in the ftdiport.inf file of the arduino drivers before installing (I opened a thread for that: latency probelms on windows 10 with Micro Pro - Interfacing w/ Software on the Computer - Arduino Forum ).

No I have a different problem:

I want to use that midi controller mostly as a looper with Mobius VST (which seems to be great freeware).
The problem is, for example I assign one button for the record function, and press the button, it only records for a very short time (less than a second) and then immediately turns it off again.

With my midi masterkeyboard it works the way it should.

What is wrong there?

Hoping for help, and thank you already!

it only records for a very short time (less than a second) and then immediately turns it off again.

With my midi masterkeyboard it works the way it should.

What is wrong there?

Well specifically, but not very helpfully, your master keyboard is doing something different than your home made system.
You have to find out what. A MIDI monitor piece of software to spy on the messages should help.