An action when 2 buttons pressed - MIDI

Status
Not open for further replies.

musiquemeuble

Active member
Hello guys !

I'm building a simple device with buttons that triggers Midi notes.

I want to add an action to my code : when you press 2 buttons simultaneously, an other note is played. Do you know how to do that ?

Thanks guys !

Code:
/* Buttons to USB MIDI Example

   You must select MIDI from the "Tools > USB Type" menu

   To view the raw MIDI data on Linux: aseqdump -p "Teensy MIDI"

   This example code is in the public domain.
*/

#include <Bounce.h>

// the MIDI channel number to send messages
const int channel1 = 1;

// Create Bounce objects for each button.  The Bounce object
// automatically deals with contact chatter or "bounce", and
// it makes detecting changes very simple.
Bounce button0 = Bounce(0, 5);
Bounce button1 = Bounce(1, 5);  // 5 = 5 ms debounce time
Bounce button2 = Bounce(2, 5);  // which is appropriate for good
Bounce button3 = Bounce(3, 5);  // quality mechanical pushbuttons
Bounce button4 = Bounce(4, 5);
Bounce button5 = Bounce(5, 5);  // if a button is too "sensitive"
Bounce button6 = Bounce(6, 5);  // to rapid touch, you can
Bounce button7 = Bounce(7, 5);  // increase this time.
Bounce button8 = Bounce(8, 5);
Bounce button9 = Bounce(9, 5);
Bounce button10 = Bounce(10, 5);
Bounce button11 = Bounce(11, 5);
Bounce button12 = Bounce(12, 5);
Bounce button13 = Bounce(24, 5);  // 5 = 5 ms debounce time
Bounce button14 = Bounce(25, 5);  // which is appropriate for good
Bounce button15 = Bounce(26, 5);  // quality mechanical pushbuttons
Bounce button16 = Bounce(27, 5);
Bounce button17 = Bounce(28, 5);  // if a button is too "sensitive"
Bounce button18 = Bounce(29, 5);  // to rapid touch, you can
Bounce button19 = Bounce(30, 5);  // increase this time.
Bounce button20 = Bounce(31, 5);
Bounce button21 = Bounce(32, 5);
Bounce button22 = Bounce(33, 5);
Bounce button23 = Bounce(34, 5);
Bounce button24 = Bounce(35, 5);
Bounce button25 = Bounce(36, 5);  // 5 = 5 ms debounce time
Bounce button26 = Bounce(37, 5);  // which is appropriate for good
Bounce button27 = Bounce(38, 5);  // quality mechanical pushbuttons
Bounce button28 = Bounce(39, 5);
Bounce button29 = Bounce(22, 5);
Bounce button30 = Bounce(23, 5);  // if a button is too "sensitive"
Bounce button31 = Bounce(24, 5);  // to rapid touch, you can
Bounce button32 = Bounce(14, 5);
Bounce button33 = Bounce(15, 5);
Bounce button34 = Bounce(16, 5);
Bounce button35 = Bounce(17, 5);
Bounce button36 = Bounce(18, 5);
Bounce button37 = Bounce(19, 5);  // 5 = 5 ms debounce time
Bounce button38 = Bounce(20, 5);  // which is appropriate for good
Bounce button39 = Bounce(21, 5);  // quality mechanical pushbuttons


void setup() {

  
  // Configure the pins for input mode with pullup resistors.
  // The pushbuttons connect from each pin to ground.  When
  // the button is pressed, the pin reads LOW because the button
  // shorts it to ground.  When released, the pin reads HIGH
  // because the pullup resistor connects to +5 volts inside
  // the chip.  LOW for "on", and HIGH for "off" may seem
  // backwards, but using the on-chip pullup resistors is very
  // convenient.  The scheme is called "active low", and it's
  // very commonly used in electronics... so much that the chip
  // has built-in pullup resistors!
  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);  // Teensy++ 2.0 LED, may need 1k resistor pullup
  pinMode(7, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP); // Teensy 2.0 LED, may need 1k resistor pullup
  pinMode(12, INPUT_PULLUP);
  pinMode(24, INPUT_PULLUP);
  pinMode(25, INPUT_PULLUP);
  pinMode(26, INPUT_PULLUP);
  pinMode(27, INPUT_PULLUP);
  pinMode(28, INPUT_PULLUP);
  pinMode(29, INPUT_PULLUP);  // Teensy++ 2.0 LED, may need 1k resistor pullup
  pinMode(30, INPUT_PULLUP);
  pinMode(31, INPUT_PULLUP);
  pinMode(32, INPUT_PULLUP);
  pinMode(33, INPUT_PULLUP);
  pinMode(34, INPUT_PULLUP); // Teensy 2.0 LED, may need 1k resistor pullup
  pinMode(35, INPUT_PULLUP);
  pinMode(36, INPUT_PULLUP);
  pinMode(37, INPUT_PULLUP);
  pinMode(38, INPUT_PULLUP);
  pinMode(39, INPUT_PULLUP);
  // pinMode(A21, INPUT_PULLUP);
  // pinMode(A22, INPUT_PULLUP);  // Teensy++ 2.0 LED, may need 1k resistor pullup
  // pinMode(13, INPUT_PULLUP);
  pinMode(14, INPUT_PULLUP);
  pinMode(15, INPUT_PULLUP);
  pinMode(16, INPUT_PULLUP);
  pinMode(17, INPUT_PULLUP); // Teensy 2.0 LED, may need 1k resistor pullup
  pinMode(18, INPUT_PULLUP);
  pinMode(19, INPUT_PULLUP);
  pinMode(20, INPUT_PULLUP);
  pinMode(21, INPUT_PULLUP);
  pinMode(22, INPUT_PULLUP);
  pinMode(23, INPUT_PULLUP);


}


void loop() {

  // Update all the buttons.  There should not be any long
  // delays in loop(), so this runs repetitively at a rate
  // faster than the buttons could be pressed and released.
  button0.update();
  button1.update();
  button2.update();
  button3.update();
  button4.update();
  button5.update();
  button6.update();
  button7.update();
  button8.update();
  button9.update();
  button10.update();
  button11.update();
  button12.update();
  button13.update();
  button14.update();
  button15.update();
  button16.update();
  button17.update();
  button18.update();
  button19.update();
  button20.update();
  button21.update();
  button22.update();
  button23.update();
  button24.update();
  button25.update();
  button26.update();
  button27.update();
  button28.update();
  button29.update();
  button30.update();
  button31.update();
  button32.update();
  button33.update();
  button34.update();
  button35.update();
  button36.update();
  button37.update();
  button38.update();
  button39.update();

  // Check each button for "falling" edge.
  // Send a MIDI Note On message when each button presses
  // Update the Joystick buttons only upon changes.
  // falling = high (not pressed - voltage from pullup resistor)
  //           to low (pressed - button connects pin to ground)
  if (button0.fallingEdge()) {
    usbMIDI.sendNoteOn(48, 127, channel1);  // C2
  }
  if (button1.fallingEdge()) {
    usbMIDI.sendNoteOn(49, 127, channel1);  // C#2
  }
  if (button2.fallingEdge()) {
    usbMIDI.sendNoteOn(50, 127, channel1);  // D2
  }
  if (button3.fallingEdge()) {
    usbMIDI.sendNoteOn(51, 127, channel1);  // D#2
  }
  if (button4.fallingEdge()) {
    usbMIDI.sendNoteOn(52, 127, channel1);  // E2
  }
  if (button5.fallingEdge()) {
    usbMIDI.sendNoteOn(53, 127, channel1);  // F2
  }
  if (button6.fallingEdge()) {
    usbMIDI.sendNoteOn(54, 127, channel1);  // F#2
  }
  if (button7.fallingEdge()) {
    usbMIDI.sendNoteOn(55, 127, channel1);  // G2
  }
  if (button8.fallingEdge()) {
    usbMIDI.sendNoteOn(56, 127, channel1);  // G#2
  }
  if (button9.fallingEdge()) {
    usbMIDI.sendNoteOn(57, 127, channel1);  // A2
  }
  if (button10.fallingEdge()) {
    usbMIDI.sendNoteOn(58, 127, channel1);  // A#2
  }
  if (button11.fallingEdge()) {
    usbMIDI.sendNoteOn(59, 127, channel1);  // B2
  }
  if (button12.fallingEdge()) {
    usbMIDI.sendNoteOn(60, 127, channel1);  // C3
  }
  if (button13.fallingEdge()) {
    usbMIDI.sendNoteOn(61, 127, channel1);  // C#3
  }
  if (button14.fallingEdge()) {
    usbMIDI.sendNoteOn(62, 127, channel1);  // D3
  }
  if (button15.fallingEdge()) {
    usbMIDI.sendNoteOn(63, 127, channel1);  // D#3
  }
  if (button16.fallingEdge()) {
    usbMIDI.sendNoteOn(64, 127, channel1);  // E3
  }
  if (button17.fallingEdge()) {
    usbMIDI.sendNoteOn(65, 127, channel1);  // F3
  }
  if (button18.fallingEdge()) {
    usbMIDI.sendNoteOn(66, 127, channel1);  // F#3
  }
  if (button19.fallingEdge()) {
    usbMIDI.sendNoteOn(67, 127, channel1);  // G3
  }
  if (button20.fallingEdge()) {
    usbMIDI.sendNoteOn(68, 127, channel1);  // G#3
  }
  if (button21.fallingEdge()) {
    usbMIDI.sendNoteOn(69, 127, channel1);  // A3
  }
  if (button22.fallingEdge()) {
    usbMIDI.sendNoteOn(70, 127, channel1);  // A#3
  }
  if (button23.fallingEdge()) {
    usbMIDI.sendNoteOn(71, 127, channel1);  // B3
  }
  if (button24.fallingEdge()) {
    usbMIDI.sendNoteOn(72, 127, channel1);  // C4
  }
  if (button25.fallingEdge()) {
    usbMIDI.sendNoteOn(73, 127, channel1);  // C#4
  }
  if (button26.fallingEdge()) {
    usbMIDI.sendNoteOn(74, 127, channel1);  // D4
  }
  if (button27.fallingEdge()) {
    usbMIDI.sendNoteOn(75, 127, channel1);  // D#4
  }
  if (button28.fallingEdge()) {
    usbMIDI.sendNoteOn(76, 127, channel1);  // E4
  }
  if (button39.fallingEdge()) {
    usbMIDI.sendNoteOn(77, 127, channel1);  // D#5
  }
  if (button29.fallingEdge()) {
    usbMIDI.sendNoteOn(78, 127, channel1);  // E5
  }
  if (button30.fallingEdge()) {
    usbMIDI.sendNoteOn(79, 127, channel1);  // F5
  }
  if (button32.fallingEdge()) {
    usbMIDI.sendNoteOn(80, 127, channel1);  // G#4
  }
  if (button33.fallingEdge()) {
    usbMIDI.sendNoteOn(81, 127, channel1);  // A4
  }
  if (button34.fallingEdge()) {
    usbMIDI.sendNoteOn(82, 127, channel1);  // A#5
  }
  if (button35.fallingEdge()) {
    usbMIDI.sendNoteOn(83, 127, channel1);  // B5
  }
  if (button36.fallingEdge()) {
    usbMIDI.sendNoteOn(84, 127, channel1);  // C5
  }
  if (button37.fallingEdge()) {
    usbMIDI.sendNoteOn(85, 127, channel1);  // C#5
  }
  if (button38.fallingEdge()) {
    usbMIDI.sendNoteOn(86, 127, channel1);  // D5
  }





  // Check each button for "rising" edge
  // Send a MIDI Note Off message when each button releases
  // For many types of projects, you only care when the button
  // is pressed and the release isn't needed.
  // rising = low (pressed - button connects pin to ground)
  //          to high (not pressed - voltage from pullup resistor)
  if (button0.risingEdge()) {
    usbMIDI.sendNoteOff(48, 0, channel1);  
  }
  if (button1.risingEdge()) {
    usbMIDI.sendNoteOff(49, 0, channel1);  
  }
  if (button2.risingEdge()) {
    usbMIDI.sendNoteOff(50, 0, channel1);
  }
  if (button3.risingEdge()) {
    usbMIDI.sendNoteOff(51, 0, channel1);  
  }
  if (button4.risingEdge()) {
    usbMIDI.sendNoteOff(52, 0, channel1);  
  }
  if (button5.risingEdge()) {
    usbMIDI.sendNoteOff(53, 0, channel1);  
  }
  if (button6.risingEdge()) {
    usbMIDI.sendNoteOff(54, 0, channel1); 
  }
  if (button7.risingEdge()) {
    usbMIDI.sendNoteOff(55, 0, channel1);  
  }
  if (button8.risingEdge()) {
    usbMIDI.sendNoteOff(56, 0, channel1);  
  }
  if (button9.risingEdge()) {
    usbMIDI.sendNoteOff(57, 0, channel1);  
  }
  if (button10.risingEdge()) {
    usbMIDI.sendNoteOff(58, 0, channel1);  
  }
  if (button11.risingEdge()) {
    usbMIDI.sendNoteOff(59, 0, channel1);  
  }
  if (button12.risingEdge()) {
    usbMIDI.sendNoteOff(60, 0, channel1);  
  }
  if (button13.risingEdge()) {
    usbMIDI.sendNoteOff(61, 0, channel1);  
  }
  if (button14.risingEdge()) {
    usbMIDI.sendNoteOff(62, 0, channel1);
  }
  if (button15.risingEdge()) {
    usbMIDI.sendNoteOff(63, 0, channel1);  
  }
  if (button16.risingEdge()) {
    usbMIDI.sendNoteOff(64, 0, channel1);  
  }
  if (button17.risingEdge()) {
    usbMIDI.sendNoteOff(65, 0, channel1);  
  }
  if (button18.risingEdge()) {
    usbMIDI.sendNoteOff(66, 0, channel1); 
  }
  if (button19.risingEdge()) {
    usbMIDI.sendNoteOff(67, 0, channel1);  
  }
  if (button20.risingEdge()) {
    usbMIDI.sendNoteOff(68, 0, channel1);  
  }
  if (button21.risingEdge()) {
    usbMIDI.sendNoteOff(69, 0, channel1);  
  }
  if (button22.risingEdge()) {
    usbMIDI.sendNoteOff(70, 0, channel1);  
  }
  if (button23.risingEdge()) {
    usbMIDI.sendNoteOff(71, 0, channel1);  
  }
  if (button24.risingEdge()) {
    usbMIDI.sendNoteOff(72, 0, channel1);  
  }
  if (button25.risingEdge()) {
    usbMIDI.sendNoteOff(73, 0, channel1);  
  }
  if (button26.risingEdge()) {
    usbMIDI.sendNoteOff(74, 0, channel1);
  }
  if (button27.risingEdge()) {
    usbMIDI.sendNoteOff(75, 0, channel1);  
  }
  if (button28.risingEdge()) {
    usbMIDI.sendNoteOff(76, 0, channel1);  
  }
  if (button39.risingEdge()) {
    usbMIDI.sendNoteOff(77, 0, channel1);  
  }
  if (button29.risingEdge()) {
    usbMIDI.sendNoteOff(78, 0, channel1);  
  }
  if (button30.risingEdge()) {
    usbMIDI.sendNoteOff(79, 0, channel1);  
  }
  if (button32.risingEdge()) {
    usbMIDI.sendNoteOff(80, 0, channel1);  
  }
  if (button33.risingEdge()) {
    usbMIDI.sendNoteOff(81, 0, channel1);  
  }
  if (button34.risingEdge()) {
    usbMIDI.sendNoteOff(82, 0, channel1);  
  }
  if (button35.risingEdge()) {
    usbMIDI.sendNoteOff(83, 0, channel1);  
  }
  if (button36.risingEdge()) {
    usbMIDI.sendNoteOff(84, 0, channel1);  
  }
  if (button37.risingEdge()) {
    usbMIDI.sendNoteOff(85, 0, channel1);  
  }
  if (button38.risingEdge()) {
    usbMIDI.sendNoteOff(86, 0, channel1);
  }
}
 
Several different approches, but one is to go into the two relevant if(button.fallingEdge()) statements and instead of sending the not, set a previously defined (and zeroed)variable to one, say buttonOneDown and ButtonTwoDown

Then you have if statements, either
if (buttoneOneDown==1&&ButtonTwoDown==1) usbMIDI.sendNoteOn(XX, 127, channel1);
else{
if(buttoneOneDown==1)usbMIDI.sendNoteOn(49, 127, channel1);
if(buttoneTwoDown==1) usbMIDI.sendNoteOn(50, 127, channel1);
}
Or you can
if (buttoneOneDown==1&&ButtonTwoDown==1) usbMIDI.sendNoteOn(xx, 127, channel1);
if (buttoneOneDown==1&&ButtonTwoDown==0) usbMIDI.sendNoteOn(49, 127, channel1);
if (buttoneOneDown==0&&ButtonTwoDown==1) usbMIDI.sendNoteOn(50, 127, channel1);
Or there are various other logic processes to the same end, largely comes down the the one that will not make your head explode when you have a whole nest of them later
 
The hard part about doing something when a human presses 2 buttons, and also do something different when they press just 1 of those buttons, is what to do the instant you first detect just 1 button press. The big question is how long do you wait. If you immediately do the 1 button action, that will appear as a mistake to the user if their fingers are on both buttons and the 2nd button event occurs several milliseconds later. So you must wait, which can feel like you're making an unresponsive system while writing the code, but it's a necessity if you want to avoid the "wrong" behavior.

Usually this task involves creating 2 variables. You'll need a way to remember which state you're in. You'll go from idle, to 1 button pressed but waiting, and from that state, you'll go the 1 button confirmed if too much time elapses, or to the 2 buttons if you detect the other button before the timeout period expires.

elapsedMillis is the simplest way to do the check for how much time has elapsed.

https://www.pjrc.com/teensy/td_timing_elaspedMillis.html

How long to wait for the 2nd button press, before you do the action for only 1 button is sort of an open question. It really can depend on the type of buttons you have, maybe other aspects of your project. But as a rule of thumb, humans perceive "instant" reaction if you give a response within ~50 ms, so that's a good starting point for the timeout setting.
 
Status
Not open for further replies.
Back
Top