MIDI program change help

I’m attempting to make a multi-button MIDI footswitch that sends program change messages.
The hardware works properly; press a button, its LED lights,. Press another button and its LED lights. The problem is that the program change messages are not being sent. I’ve tested the serial port via loopback and serial monitor. I can see the data on the computer screen and see the data on an oscilloscope. Thus the problem is with my code. Caveat Emptor, I’m new to Arduino and MIDI. Worse, I’m a musician and an electrical engineer. I’ve been doing a bit of research but haven’t figured out what’s wrong. Code follows.

// MIDI program change
// By machambers 5/8/21
// based on simple_midi_out by Grumpy_Mike 9/19

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

// to add more buttons, add more pins to the lists
byte ledPin[] = {8, 9, 10, 11, 12, 13}; // list of led pins
byte buttonPin[] = {2, 3, 4, 5, 6, 7}; // list of buttons pins
byte buttonState[] = {0, 0}; // start off with off
byte lastButtonState[] = {0, 0}; // start off with off
byte programChanges[] = {1, 19, 39, 59, 81, 105}; // list of program change messages to send

byte channel = 0; // for musicians this is channel 1

void setup() {
  MIDI.begin();
  for (int i = 0; i < sizeof(buttonPin); i++) { // initialise input pins
    pinMode(buttonPin[i], INPUT_PULLUP); // wire all buttons between input and ground
    pinMode(ledPin[i], OUTPUT);
  }
}

void loop() {
  for (int i = 0; i < sizeof(buttonPin); i++) { // look at all pins
    buttonState[i] = digitalRead(buttonPin[i]);
    if (buttonState[i] == LOW && lastButtonState[i] == HIGH) { // LOW = pressed
      ledOffAll();
      digitalWrite(ledPin[i], LOW);
      MIDI.sendProgramChange(channel, programChanges[i]); // send program change messages
      delay(200);
    }
    lastButtonState[i] = buttonState[i];
  }
}

void ledOffAll() {
  for (int i = 0 ; i < sizeof(ledPin); i++) {
    digitalWrite(ledPin[i], HIGH);
  }
}

Any help is much appreciated.

You only have space for 2 buttons but use space for 6 buttons in buttonState and lastButtonState! You are probably writing over your list of program changes!

Did you not see these warnings from the compiler?

sketch_may03a.ino: In function 'loop':
sketch_may03a.ino:40:39: warning: iteration 2 invokes undefined behavior [-Waggressive-loop-optimizations]
     lastButtonState[i] = buttonState[i];
                          ~~~~~~~~~~~~~^
sketch_may03a.ino:30:21: note: within this loop
   for (int i = 0; i < sizeof(buttonPin); i++)   // look at all pins
                   ~~^~~~~~~~~

sketch_may03a.ino:40:39: warning: iteration 2 invokes undefined behavior [-Waggressive-loop-optimizations]
     lastButtonState[i] = buttonState[i];
                                       ^
sketch_may03a.ino:30:21: note: within this loop
   for (int i = 0; i < sizeof(buttonPin); i++)   // look at all pins
                     ^

Here is how I would do it when you have a bunch of arrays that are all supposed to be the same size. By specifying a size for the array you will get an error if give to many entries.

(Note: You don’t need a separate buttonState for each button.)

// MIDI program change
// By machambers 5/8/21
// based on simple_midi_out by Grumpy_Mike 9/19

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

// to add more buttons, add more pins to the lists
const unsigned ButtonCount = 6;
const byte ledPin[ButtonCount] = {8, 9, 10, 11, 12, 13}; // list of led pins
const byte buttonPin[ButtonCount] = {2, 3, 4, 5, 6, 7}; // list of buttons pins
const byte programChanges[ButtonCount] = {1, 19, 39, 59, 81, 105}; // list of program change messages to send

byte lastButtonState[ButtonCount]; // Defaults to LOW/0

byte channel = 0; // for musicians this is channel 1

void setup()
{
  MIDI.begin();
  for (unsigned i = 0; i < ButtonCount; i++)   // initialise input pins
  {
    pinMode(buttonPin[i], INPUT_PULLUP); // wire all buttons between input and ground
    pinMode(ledPin[i], OUTPUT);
  }
}

void loop()
{
  for (unsigned i = 0; i < ButtonCount; i++)   // look at all pins
  {
    byte buttonState = digitalRead(buttonPin[i]);
    if (buttonState == LOW && lastButtonState[i] == HIGH)   // LOW = pressed
    {
      ledOffAll();
      digitalWrite(ledPin[i], LOW);
      MIDI.sendProgramChange(channel, programChanges[i]); // send program change messages
      delay(200);
    }
    lastButtonState[i] = buttonState;
  }
}

void ledOffAll()
{
  for (unsigned i = 0 ; i < ButtonCount; i++)
  {
    digitalWrite(ledPin[i], HIGH);
  }
}

Thank you for your help.

I did see some orange text scroll by quickly when compiling. With the default size of the lower window the error scroll out of view. I now know that any orange text there is a bad sign.

Unfortunately your code doesn’t work any better than mine; the LEDs follow the button presses, but no data gets sent out the TX port. I’m using an Arduino UNO SMD R3 clone, would that effect the way the code works?

Do the MIDI library examples work?

The MIDI.sendProgramChange() that I know takes (program, channel). Yours has the parameters the other way round.

Steve

I haven't been able to make sense out of the examples I've looked at.

Thanks for your help.
I noticed the order problem today while explaining the issue to a co-worker.
The MIDI channel value was also incorrect; no such thing as channel 0.

With those changes the sketch works as desired.
Now I can learn more about how each section works.