MIDI controller - multiple button press issue

Hi

This is my first Arduino project and I’m relatively inexperienced when it comes to programming.

I’ve built a prototype midi controller that sends program change (PC) messages to a guitar effects pedal.

The project is based on the information here: https://www.electronicproducts.com/Education/Design/Here_s_how_you_can_make_a_MIDI_controller_with_an_Arduino.aspx

I’ve got it working with single button presses (each button selects a nominated preset) but I would love to get it working where if I press two buttons simultaneously it sends a different PC message.

I’ve sort of got that working with this code:

#include <MIDI.h>
#include <midi_Defs.h>
#include <midi_Message.h>
#include <midi_Namespace.h>
#include <midi_Settings.h>

const int buttonOne = 2; // assign button pin to variable
const int buttonTwo = 3; // assign button pin to variable
const int buttonThree = 4; // assign button pin to variable
const int buttonFour = 5; // assign button pin to variable
const int buttonFive = 6; // assign button pin to variable



MIDI_CREATE_INSTANCE(HardwareSerial,Serial, midiOut); // create a MIDI object called midiOut

void setup() {
  pinMode(buttonOne,INPUT); // setup button as input
  pinMode(buttonTwo,INPUT); // setup button as input
  pinMode(buttonThree,INPUT); // setup button as input
  pinMode(buttonFour,INPUT); // setup button as input
  pinMode(buttonFive,INPUT); // setup button as input
  Serial.begin(31250); // setup MIDI output
}

void loop() {
  if(digitalRead(buttonOne) == HIGH) { // check button state
    delay(10); // software de-bounce
    if(digitalRead(buttonOne) == HIGH) { // check button state again
      midiOut.sendProgramChange(0,1); 
      delay(250); 
    }
  }
 
  if(digitalRead(buttonTwo) == HIGH) { // check button state
    delay(10); // software de-bounce
    if(digitalRead(buttonTwo) == HIGH) { // check button state again
      midiOut.sendProgramChange(1,1); 
      delay(250);
    }
  }

  if(digitalRead(buttonThree) == HIGH) { // check button state
    delay(10); // software de-bounce
    if(digitalRead(buttonThree) == HIGH) { // check button state again
      midiOut.sendProgramChange(2,1); 
      delay(250); 
    }
  }
 
  if(digitalRead(buttonFour) == HIGH) { // check button state
    delay(10); // software de-bounce
    if(digitalRead(buttonFour) == HIGH) { // check button state again
      midiOut.sendProgramChange(3,1); 
      delay(250);
    }
  }

  if(digitalRead(buttonFive) == HIGH) { // check button state
    delay(10); // software de-bounce
    if(digitalRead(buttonFive) == HIGH) { // check button state again
      midiOut.sendProgramChange(4,1); 
      delay(250); 
    }
  }
 
    if(digitalRead(buttonOne) == HIGH & digitalRead(buttonTwo) == HIGH) { // check button state
    delay(10); // software de-bounce
    if(digitalRead(buttonOne) == HIGH & digitalRead(buttonTwo) == HIGH) { // check button state again
      midiOut.sendProgramChange(5,1); 
      delay(250); 
    }
  }
 
    if(digitalRead(buttonTwo) == HIGH & digitalRead(buttonThree) == HIGH) { // check button state
    delay(10); // software de-bounce
    if(digitalRead(buttonTwo) == HIGH & digitalRead(buttonThree) == HIGH) { // check button state again
      midiOut.sendProgramChange(6,1); 
      delay(250); 
    }
  }
 
     if(digitalRead(buttonThree) == HIGH & digitalRead(buttonFour) == HIGH) { // check button state
    delay(10); // software de-bounce
    if(digitalRead(buttonThree) == HIGH & digitalRead(buttonFour) == HIGH) { // check button state again
      midiOut.sendProgramChange(7,1); 
      delay(250); 
    }
  }
 
   if(digitalRead(buttonFour) == HIGH & digitalRead(buttonFive) == HIGH) { // check button state
    delay(10); // software de-bounce
    if(digitalRead(buttonFour) == HIGH & digitalRead(buttonFive) == HIGH) { // check button state again
      midiOut.sendProgramChange(8,1); 
      delay(250); 
    }
  }
 
}

The problem is that when I press both buttons it seems to send three PC messages at once, one for each button and one for them combined. The effects pedal then just scrolls through the associated presets rather than just selecting the one I want.

Whilst it could be a hardware issue (perhaps I need some diodes to stop current flowing where it shouldn’t) but my guess is there’s a simple line or two of code to basically say “when two buttons are pressed within X ms of each other then don’t send the individual button codes”.

Does anyone have any ideas??

Thanks!

You'll have to note that a button has been pressed then wait for a while to see if another button press is going to turn up. Then you can send the appropriate "single button" or "two buttons" PC message.

Steve

Thank you for the tip.

Do you think if I change the first delay for the single button from 10 to, say, 250 that might work?

That way the program gives me more time to press and release the second button before sending the pc message.

Not sure if that’s a stupid suggestion, very new to all this like I say!

Unfortunately not. When you do delay() everything stops for that amount of time. So even if you press another button the Arduino would never notice it.

You're going to have to get the hang of using millis() and non-blocking code. Start by having a look at the IDE example BlinkWithoutDelay.

Steve

Hi Steve,

Thanks for your help. After much trial and error I seem to have got it working.

I’ll post the code here for anyone who has a similar issue or to see if anyone has any suggestions for improvements:

#include <MIDI.h>
#include <midi_Defs.h>
#include <midi_Message.h>
#include <midi_Namespace.h>
#include <midi_Settings.h>

const int buttonOne = 2; // assign button pin to variable
const int buttonTwo = 3; // assign button pin to variable
const int buttonThree = 4; // assign button pin to variable
const int buttonFour = 5; // assign button pin to variable
const int buttonFive = 6; // assign button pin to variable
unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 100;  //the value is a number of milliseconds


MIDI_CREATE_INSTANCE(HardwareSerial,Serial, midiOut); // create a MIDI object called midiOut

void setup() {
  pinMode(buttonOne,INPUT); // setup button as input
  pinMode(buttonTwo,INPUT); // setup button as input
  pinMode(buttonThree,INPUT); // setup button as input
  pinMode(buttonFour,INPUT); // setup button as input
  pinMode(buttonFive,INPUT); // setup button as input
  Serial.begin(31250); // setup MIDI output
  startMillis = millis();  //initial start time
}

void loop() {

  if(digitalRead(buttonOne) == HIGH) { // check button state
  delay(10); // software de-bounce
  if(digitalRead(buttonOne) == HIGH) { // check button state again
    
    currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
    if (currentMillis - startMillis >= period)  //test whether the period has elapsed
       
       if(digitalRead(buttonOne) == HIGH) { // check button state
       midiOut.sendProgramChange(0,1); 
       }
       if(digitalRead(buttonOne) == HIGH & digitalRead(buttonTwo) == HIGH) { // check button state
       midiOut.sendProgramChange(5,1);
       }
      delay(500); 
    }
  }
 
  if(digitalRead(buttonTwo) == HIGH) { // check button state
  delay(10); // software de-bounce
  if(digitalRead(buttonTwo) == HIGH) { // check button state again
    
    currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
    if (currentMillis - startMillis >= period)  //test whether the period has elapsed
       
       if(digitalRead(buttonTwo) == HIGH) { // check button state
       midiOut.sendProgramChange(1,1); 
       }
       if(digitalRead(buttonOne) == HIGH & digitalRead(buttonTwo) == HIGH) { // check button state
       midiOut.sendProgramChange(5,1);
       }
       if(digitalRead(buttonThree) == HIGH & digitalRead(buttonTwo) == HIGH) { // check button state
       midiOut.sendProgramChange(6,1);       
       }
      delay(500); 
    }
  }
  
   if(digitalRead(buttonThree) == HIGH) { // check button state
   delay(10); // software de-bounce
   if(digitalRead(buttonThree) == HIGH) { // check button state again
    
    currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
    if (currentMillis - startMillis >= period)  //test whether the period has elapsed
       
       if(digitalRead(buttonThree) == HIGH) { // check button state
       midiOut.sendProgramChange(2,1); 
       }
       if(digitalRead(buttonThree) == HIGH & digitalRead(buttonFour) == HIGH) { // check button state
       midiOut.sendProgramChange(7,1);
       }
       if(digitalRead(buttonThree) == HIGH & digitalRead(buttonTwo) == HIGH) { // check button state
       midiOut.sendProgramChange(6,1);       
       }
      delay(500); 
    }
  }
  
   if(digitalRead(buttonFour) == HIGH) { // check button state
   delay(10); // software de-bounce
   if(digitalRead(buttonFour) == HIGH) { // check button state again 
   
    currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
    if (currentMillis - startMillis >= period)  //test whether the period has elapsed
       
       if(digitalRead(buttonFour) == HIGH) { // check button state
       midiOut.sendProgramChange(3,1); 
       }
       if(digitalRead(buttonThree) == HIGH & digitalRead(buttonFour) == HIGH) { // check button state
       midiOut.sendProgramChange(7,1);
       }
       if(digitalRead(buttonFour) == HIGH & digitalRead(buttonFive) == HIGH) { // check button state
       midiOut.sendProgramChange(8,1);       
       }
      delay(500); 
    }
  }
  
  if(digitalRead(buttonFive) == HIGH) { // check button state
  delay(10); // software de-bounce
  if(digitalRead(buttonFive) == HIGH) { // check button state again  
  
    currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
    if (currentMillis - startMillis >= period)  //test whether the period has elapsed
       
       if(digitalRead(buttonFive) == HIGH) { // check button state
       midiOut.sendProgramChange(4,1); 
       }
       if(digitalRead(buttonFour) == HIGH & digitalRead(buttonFive) == HIGH) { // check button state
       midiOut.sendProgramChange(8,1);       
       }
      delay(500); 
    }
  }
  
  
}