USB MIDI Controller sending CC continuously

Noob here, so go easy on me :wink:

I'm trying to build a USB MIDI foot controller that will simply send MIDI CC messages when buttons are pressed. I'm using a keyestudio Leonardo board for it's native USB support, so I can do MIDI over USB.

The issue I'm finding is that rather than sending each CC message once, when one of the buttons is pressed, it's just endlessly sending all of the messages all the time (confirmed with both the serial monitor and the MIDI message monitor in my DAW).

Any insight would be gratefully received.

#include "MIDIUSB.h"

const int btn1 = 2;
const int btn2 = 3;
const int btn3 = 4;
const int btn4 = 5;

int btn1State = HIGH;
int btn2State = HIGH;
int btn3State = HIGH;
int btn4State = HIGH;

void setup()
{
  Serial.begin(9600);

  pinMode(btn1, INPUT_PULLUP);
  pinMode(btn2, INPUT_PULLUP);
  pinMode(btn3, INPUT_PULLUP);
  pinMode(btn4, INPUT_PULLUP);
}

// First parameter is the event type (0x0B = control change).
// Second parameter is the event type, combined with the channel.
// Third parameter is the control number number (0-119).
// Fourth parameter is the control value (0-127).

void controlChange(byte channel, byte control, byte value) {
  midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};
  MidiUSB.sendMIDI(event);
}

void loop() {

  btn1State = digitalRead(btn1);
  btn2State = digitalRead(btn2);
  btn3State = digitalRead(btn3);
  btn4State = digitalRead(btn4);

  if (btn1State == LOW) {
  Serial.println("Sending CC 60 127");
  controlChange(0, 60, 127);
  }
  
  if (btn2State == LOW) {
  Serial.println("Sending CC 61 127");
  controlChange(0, 61, 127);
  }

  if (btn3State == LOW) {
  Serial.println("Sending CC 62 127");
  controlChange(0, 62, 127);
  }

  if (btn4State == LOW) {
  Serial.println("Sending CC 63 127");
  controlChange(0, 63, 127);
  }
}```

Yes it will send them continuously because that is what you wrote in your code.

You are sending a message when the button is pressed. You need to send it when the button becomes pressed. That is pressed for the first time.

There is an example of how to do this for one button in the IDE, it is called state change detector, or some such words.

Study that. Note for four buttons each one needs its own last button state variable.

Here's the state-change detection example: https://docs.arduino.cc/built-in-examples/digital/StateChangeDetection

It uses external pull-down resistors, which is not the best strategy since you can use the internal pull-ups for free, but it should be simple enough to adapt the example to use INPUT_PULLUP.

An alternative could be to use a library to do the debouncing and edge-detection for you, if you're doing all of that in your main loop, it tends to get messy if you add more buttons.
You could use the Control Surface library I maintain, it supports buttons that send CC messages out of the box:

#include <Control_Surface.h> // https://github.com/tttapa/Control-Surface

USBMIDI_Interface midi;

CCButton buttons [] {
  {2, 60}, // pin, controller
  {3, 61},
  {4, 62},
  {5, 63},
};

void setup() { Control_Surface.begin(); }
void loop() { Control_Surface.loop(); }

See the following example for more information: Control Surface: CCButton.ino

Thanks so much for the pointers! Works a treat now. :slight_smile: