My usb MIDI footswitch doesn’t work properly. PLEASE HELP

Hello. My board is ARDUINO PRO MICRO.

I made a DIY footswitch with 8 arcade button and 1 analog input that works as expression pedal. The goal is to switch on/off fx (or channels, or launch clips…) in ableton live 11.

The code I used seems to work fine with my analog input: it sends CC and I can route it perfectly for tweak for example volume or sliders.
But I have a problem with buttons… they are sending midi note on/off events which have to be mapped, and ableton receives them, but the toggle isn’t working fine… sometimes it is switched on, sometimes doesn’t…
I have to push once and once and it isn’t being fine because as a guitarist I need to be focus into playing and not so much into “oh, this fx isn’t working now, let’s try again”

I decided to use ableton’s midi monitor to see what is happening and I realized that every time I press one button it is receiving several NOTE ON/NOTE OFF messages, instead of just one… it makes the “toggle” reacts crazy and maybe you could just read my code and help me with it, because I’ve been many days going crazy with it and I have no answers…. Maybe could I add some delay? Have I to change a few lines? Lots of questions for this poor guitarist trying to learn some programming. THANK YOU IN ADVANCE


#include "MIDIUSB.h"


// struct for buttons
struct button{
  uint8_t port;
  bool pressed;
  uint8_t count;
};


// struct for potentiometers
struct pot{
  uint8_t port;
  uint8_t last;
};


button buttons [8];
pot pots[4];


void setup()
{
  // declaring each button port sequentially
  for(int i=0; i<8; i++){
    buttons[i].port = 12-i;
    buttons[i].pressed = false;
    buttons[i].count = 0;
    pinMode(buttons[i].port, INPUT_PULLUP);
  }


  // declaring each potentiometer sequantially
  for(int i=0; i<4; i++){
    pots[i].port = i+A1;
    pots[i].last = 0;
  }
}


void loop()
{
  // button press logic, checkes each button in a loop with debounce
  for(int i=0; i<8; i++){
    if(!digitalRead(buttons[i].port)){
      if(!buttons[i].pressed && millis() - buttons[i].count > 2){
        uint8_t note = buttons[i].port+31;
        midiEventPacket_t noteOn = {0x09, 0x90 | 1, note, 127};
        MidiUSB.sendMIDI(noteOn);
        buttons[i].pressed = true;
      }
    } else {
      if(buttons[i].pressed == true){
        uint8_t note = buttons[i].port+31;
        midiEventPacket_t noteOff = {0x08, 0x80 | 1, note, 0};
        MidiUSB.sendMIDI(noteOff);
      }
      buttons[i].pressed = false;
      buttons[i].count = millis();
    }
  }


  // potentiometer reading logic, checkes each potentiometer for moving a certain threshold to prevent jiggling
  for(uint8_t i=0; i<4; i++){
    uint8_t val = analogRead(pots[i].port)*(127.0/685.0);
    if(val > 127)
      val = 127;
    if(abs(val - pots[i].last) > 1){
      pots[i].last = val;
      midiEventPacket_t event = {0x0B, 0xB0 | 1, pots[i].port, val};
      MidiUSB.sendMIDI(event);
    }
  }
  MidiUSB.flush(); // send MIDI data via USB
}

Hello horhe

Your task description matches not the sketch.

How many analog inputs will be used realy?

Have a nice day and enjoy coding in C++.

Sorry, one friend is helping me with the code and he copied one and adapted it to my needs. I’m using just one analog input. Thank you for your fast response :grin:

so have yo considered that maybe just 2 ms isn't enough of a de-bounce ?

if(!buttons[i].pressed && millis() - buttons[i].count > 2){

and on that matter, you have only de-bounce 'released' but not 'pressed', you should de-bounce both.
a change of state of the pin(button) should deactivate it for about 50 - 100 ms for any other state change.

It sounds really interesting, but I’m newbie into programming… could you PLEASE change my code applying these changes? I would try it and send some feedback.

THANK YOU :grin:

Hello horhe

You might to take into account to drop your request here:

Ok thanks. I can’t pay for now, so I will try to write the code by myself :crossed_fingers:t2:

and get your friend to help you.

basically you need to do it like this.
first correct this

// struct for buttons
struct button{
  uint8_t port;
  bool pressed;
  uint32_t count; // uint8_t count; // just make sure that millis() doesn't roll over it's a 32-bit variable.
};

define the debounce

#define DEBOUNCE 50

and check for state change and debounce like this

for (int i = 0; i < 8; i++) {
    bool pressed = false;
    if (!digitalRead(buttons[i].port)) pressed = true; // either pressed or not
    if ((buttons[i].pressed != pressed) && (millis() - buttons[i].count > DEBOUNCE)) { // change of button state
      if (pressed) {
        uint8_t note = buttons[i].port + 31;
        midiEventPacket_t noteOn = {0x09, 0x90 | 1, note, 127};
        MidiUSB.sendMIDI(noteOn);
      }
      else {  // not pressed
        uint8_t note = buttons[i].port + 31;
        midiEventPacket_t noteOff = {0x08, 0x80 | 1, note, 0};
        MidiUSB.sendMIDI(noteOff);
      }
      buttons[i].pressed = pressed;
      buttons[i].count = millis();
    }
  }

Thank you very much for your tips. I will try my best and I hope all this will fix that kind of bug that is making my little machine not useful… the concept is really simple, and many controllers do it perfectly… I think I’m reaching the goal. Love for you all. I will close the conversation as soon I will be able to get it working perfectly.

You do this by marking it as solved, with the post that gave you your soloution.

1 Like

Based in these tips, I tried several things and the key for me was adjusting fine the DEBOUNCE DELAY time. Actually the best setup for me is 700 ms, because if I let my foot over the button this time, the note will switch OFF, but my stomps are faster. However I have to wait no less than these 700 ms until push again, because the button won’t work… for me is correct. Each user could config this setting easily.
I leave here the final sketch that worked for me for my 8 BUTTON and 1 POT (the sketch sets 4 but I only use 1) MIDI FOOTSWITCH.

Thank you all for your help :kissing_heart:


#include "MIDIUSB.h"

// struct for buttons
struct button{
  uint8_t port;
  bool pressed;
  uint32_t count;
};

// struct for potentiometers
struct pot{
  uint8_t port;
  uint8_t last;
};

button buttons[8];
pot pots[4];
unsigned long debounce_delay = 700; // debounce delay

void setup()
{
  // declaring each button port sequentially
  for(int i = 0; i < 8; i++){
    buttons[i].port = 9 - i;
    buttons[i].pressed = false;
    buttons[i].count = 0;
    pinMode(buttons[i].port, INPUT_PULLUP);
  }

  // declaring each potentiometer sequentially
  for(int i = 0; i < 1; i++){
    pots[i].port = i + A0;
    pots[i].last = 0;
  }
}

void loop()
{
  // button press logic, checks each button in a loop with debounce
  for(int i = 0; i < 8; i++){
    if(!digitalRead(buttons[i].port)){
      if(!buttons[i].pressed && millis() - buttons[i].count > debounce_delay){
        uint8_t note = i + 60;
        midiEventPacket_t noteOn = {0x09, 0x90 | 8, note, 127};
        MidiUSB.sendMIDI(noteOn);
        buttons[i].pressed = true;
      } else if (buttons[i].pressed && millis() - buttons[i].count > debounce_delay) {
        buttons[i].count = millis();
      }
    } else if (buttons[i].pressed == true){
      uint8_t note = i + 60;
      midiEventPacket_t noteOff = {0x08, 0x80 | 8, note, 0};
      MidiUSB.sendMIDI(noteOff);
      buttons[i].pressed = false;
      buttons[i].count = millis();
    }
  }

  // potentiometer reading logic, checks each potentiometer for moving a certain threshold to prevent jiggling
  for(uint8_t i = 0; i < 1; i++){
    uint8_t val = analogRead(pots[i].port) * (127.0 / 685.0);
    if(val > 127)
      val = 127;
    if(abs(val - pots[i].last) > 1){
      pots[i].last = val;
      midiEventPacket_t event = {0x0B, 0xB0 | 8, pots[i].port, val};
      MidiUSB.sendMIDI(event);
    }
  }
  MidiUSB.flush(); // send MIDI data via USB
}


actually the best would be to debounce also the release as i had shown you, then a debounce time of 50ms would easily suffice.
If you just debounce the press, you are not dealing with the issue at all.

I don’t know how doing it, because I defined the debounce as 700, how can I add this second shorter debounce to my code? I couldn’t see clearly in your post :weary:

you don't need to add a second debounce, you need to put the debounce timing check in the proper spot, so it applies to any change of state of the button, both release and press. I mean nevermind you know, whatever works for you, i am sure i spelled it out sufficiently.

I tried but it doesn’t work as expected…
The second “short debounce” switch on again the fx instantly in my software if I am not enough fast releasing my foot. I assure the last code I posted is working super fine. The only thing I added was a little DEAD ZONE (1%) at the beginning and end of the CC to avoid weird imprecise behavior of the knob when reaching limits as it follows:
BEFORE VOID SETUP:


button buttons[8];
pot pots[4];
unsigned long debounce_delay = 700; // debounce delay
unsigned int dead_zone = 1; // dead zone for potentiometers

AND WHEN VOID LOOP CONFIG


  // potentiometer reading logic, checks each potentiometer for moving a certain threshold to prevent jiggling
  for(uint8_t i = 0; i < 1; i++){
    uint8_t val = analogRead(pots[i].port) * (127.0 / 685.0);
    if (val < dead_zone) {
      val = 0;
    } else if (val > (127 - dead_zone)) {
      val = 127;
    } else {
      val = map(val, dead_zone, (127 - dead_zone), 0, 127);
    }
    if(abs(val - pots[i].last) > 1){
      pots[i].last = val;
      midiEventPacket_t event = {0x0B, 0xB0 | 8, pots[i].port, val};
      MidiUSB.sendMIDI(event);
    }
  }

But thank you for your comments, you all helped me to solve this brain mess for me :partying_face:

This is because you are looking at the signal level of the digital input, not at the edge. That is when the button becomes pressed as opposed to when the button is being pressed.

Look at the "state change detection" example in the Arduino's examples.

bool pressed = false;
    if (!digitalRead(buttons[i].port)) pressed = true; // either pressed or not
    if ((buttons[i].pressed != pressed)  && (millis() - buttons[i].count > DEBOUNCE)) {

is exactly this, all is executed if the switch has changed state and debounce time has expired, thereafter it is determined if it was a release or a press.

I thought it was but then it would not have mattered how long the foot was held down.

It doesn't really, there is just the debounce, but of course the type change for the stored millis() (uint8_t is really to small and is going to cause unpredictable behavior with it rolling over in a bit over 1/4 second.

But when you press the button it does two state changes physically: press and release, and in the most cases it sends two impulses, each one with each movement… even the LED in arduino blinks twice… for me it isn’t working, just my sketch with long debounce is working fine for me, I have only the “bug” of having to wait 700 ms to press again the button but I said in my setup it isn’t being a problem at all…