Want to Add a Midi Channel Change Button

Hi all, first post here. I'm very new to Arduino and I've built my first midi controller that I'm using to change certain parameters in UAD Console using the UA Midi Control app as middleware since Console does not read MIDI on its own. The box I've built has two separate yet identical sets of controls to control parameters on two separate channel strips for two separate microphones. It seems to me that a more ergonomic solution would be to have just one set of physical controls that I can switch from channel strip to channel strip by changing the midi channel my controller box is sending info to. That way all the controls for the first mic can be on midi channel 1, on mic 2 controls on midi channel 2. So, my question is how do I integrate a button that would change midi channels from 1 to 2 or 2 back to 1?

I'm using this code derived from MusicoNerd below:

/*
  // If using with ATmega328 - Uno, Mega, Nano...
  
  #include <MIDI.h>
  
  MIDI_CREATE_DEFAULT_INSTANCE();
*/
// If using with ATmega32U4 - Micro, Pro Micro, Leonardo...
#include "MIDIUSB.h" // Download it here: https://github.com/arduino-libraries/MIDIUSB

/////////////////////////////////////////////
// buttons
const int NButtons = 3; //*
const int buttonPin[NButtons] = {2,3,4};  //* the number of the pushbutton pins in the desired not order
int buttonCState[NButtons] = {0};         // stores the button current value
int buttonPState[NButtons] = {0};        // stores the button previous value
//byte pin13index = 3; // put the index of the pin 13 in the buttonPin[] if you are using it, if not, comment lines 68-70

/////////////////////////////////////////////
// debounce
unsigned long lastDebounceTime[NButtons] = {0};  // the last time the output pin was toggled
unsigned long debounceDelay = 13;    //* the debounce time; increase if the output flickers

/////////////////////////////////////////////
// potentiometers

const int NPots = 5; //*
int potPin[NPots] = {A0,A1,A2,A3,A5}; //* Pin where the potentiometer is
int potCState[NPots] = {0}; // Current state of the pot
int potPState[NPots] = {0}; // Previous state of the pot
int potVar = 0; // Difference between the current and previous state of the pot

int midiCState[NPots] = {0}; // Current state of the midi value
int midiPState[NPots] = {0}; // Previous state of the midi value

int TIMEOUT = 300; //* Amount of time the potentiometer will be read after it exceeds the varThreshold
int varThreshold = 10; //* Threshold for the potentiometer signal variation
boolean potMoving = true; // If the potentiometer is moving
unsigned long PTime[NPots] = {}; // Previously stored time
unsigned long timer[NPots] = {}; // Stores the time that has elapsed since the timer was reset

/////////////////////////////////////////////

byte midiCh = 1; //* MIDI channel to be used
byte note = 1; //* Lowest note to be used
byte cc = 7; //* Lowest MIDI CC to be used

void setup() {

  //Serial.begin(115200); // use if using with ATmega328 (uno, mega, nano...)

  for (int i = 0; i < NButtons; i++) {
    pinMode(buttonPin[i], INPUT_PULLUP);
  }
  //pinMode(buttonPin[3], INPUT); //pin 13

}

void loop() {

  buttons();
  potentiometers();

}

/////////////////////////////////////////////
// BUTTONS
void buttons() {

  for (int i = 0; i < NButtons; i++) {

    buttonCState[i] = digitalRead(buttonPin[i]);
    /*
        // Comment this if you are not using pin 13...
        if (i == pin13index) {
          buttonCState[i] = !buttonCState[i]; //inverts pin 13 because it has a pull down resistor instead of a pull up
        }
        // ...until here
    */
    if ((millis() - lastDebounceTime[i]) > debounceDelay) {

      if (buttonPState[i] != buttonCState[i]) {
        lastDebounceTime[i] = millis();

        if (buttonCState[i] == LOW) {
          // use if using with ATmega328 (uno, mega, nano...)
          //MIDI.sendNoteOn(note + i, 127, midiCh); // note, velocity, channel

          // use if using with ATmega32U4 (micro, pro micro, leonardo...)
          noteOn(midiCh, note + i, 127);  // channel, note, velocity
          MidiUSB.flush();

          //          Serial.print("button on  >> ");
          //          Serial.println(i);
        }
        else {
          // use if using with ATmega328 (uno, mega, nano...)
          //MIDI.sendNoteOn(note + i, 0, midiCh); // note, velocity, channel

          // use if using with ATmega32U4 (micro, pro micro, leonardo...)
          noteOn(midiCh, note + i, 0);  // channel, note, velocity
          MidiUSB.flush();

          //          Serial.print("button off >> ");
          //          Serial.println(i);
        }
        buttonPState[i] = buttonCState[i];
      }
    }
  }
}

/////////////////////////////////////////////
// POTENTIOMETERS
void potentiometers() {

  for (int i = 0; i < NPots; i++) { // Loops through all the potentiometers

    potCState[i] = analogRead(potPin[i]); // Reads the pot and stores it in the potCState variable
    midiCState[i] = map(potCState[i], 0, 1023, 0, 127); // Maps the reading of the potCState to a value usable in midi


    potVar = abs(potCState[i] - potPState[i]); // Calculates the absolute value between the difference between the current and previous state of the pot

    if (potVar > varThreshold) { // Opens the gate if the potentiometer variation is greater than the threshold
      PTime[i] = millis(); // Stores the previous time
    }

    timer[i] = millis() - PTime[i]; // Resets the timer 11000 - 11000 = 0ms

    if (timer[i] < TIMEOUT) { // If the timer is less than the maximum allowed time it means that the potentiometer is still moving
      potMoving = true;
    }
    else {
      potMoving = false;
    }

    if (potMoving == true) { // If the potentiometer is still moving, send the change control
      if (midiPState[i] != midiCState[i]) {

        // use if using with ATmega328 (uno, mega, nano...)
        //MIDI.sendControlChange(cc+i, midiCState[i], midiCh);

        // use if using with ATmega32U4 (micro, pro micro, leonardo...)
        controlChange(midiCh, cc + i, midiCState[i]); // manda control change (channel, CC, value)
        MidiUSB.flush();


        //Serial.println(midiCState);
        potPState[i] = potCState[i]; // Stores the current reading of the potentiometer to compare with the next
        midiPState[i] = midiCState[i];
      }
    }
  }

}

/////////////////////////////////////////////
// Arduino (pro)micro midi functions MIDIUSB Library
void noteOn(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
  MidiUSB.sendMIDI(noteOn);
}

void noteOff(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
  MidiUSB.sendMIDI(noteOff);
}

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

You know people might be more inclined to help if you posted the code correctly, as detailed in the how to use this forum sticky post.

As it is your code has been mangled by the forum software so that some of it has been removed and interpreted as the instruction to use italics.

Thanks Grumpy! Fixed the code window. Much appreciated.

Thanks for fixing the post.

I'm using this code derived from MusicoNerd below:

It is a bit of a pity that you had to use code from someone who doesn’t quite understand how to use arrays, but it manages to work despite him getting it wrong.

Anyway to your problem these is a simple way to do this, add a single switch ( not push button ) to your system wired between input and ground, on a pin and give that pin the name chan.
Then at in the setup function add

pinMode(chan, INPUT_PULLUP);

Then at the start of the loop function add

 midiCh = 0;
if(digitalRead(chan)) midiCh= 1;

And that will change between MIDI channel 1 and 2 depending on the switch position.

Thank you, Grumpy! A-ha! A switch is a fantastic idea and makes a ton of sense. I'm brand spanking new to this, pivoting from building tube microphones to devices I can use to make my workflow for work easier. The Musico Nerd code was something I came across on his site for a midi controller I realized I could use with the Universal Audio Console software (like a software mixing console that also integrates plug ins). The box I built last weekend has two sets of channel mute buttons, a pot for preamp gain and a pot for cue send to headphones. It works perfectly and gives me a great jumping off point to go further down the Arduino rabbit hole. Hopefully, in time, I will better understand how his code could be better. I truly appreciate your help.

Theoretically, I could also use a 3 position rotary switch to extend the range to 3 different midi channels, correct?

Theoretically, I could also use a 3 position rotary switch to extend the range to 3 different midi channels, correct?

You could but that would have to be wired to three different pins and your code would have to spot which one was low and set the channel accordingly.

You could even wire a pot to an analogue input and be able to select any channel by turning it to the correct angle and have LEDs indicate the number in binary, or show it in hex on one seven segment display or in decimal on two of them.

Or have a rotary encoder with clicks to select them.

As they say the possibilities are limited only by your imagination.

Wow, yeah I'm going to tinker with this for sure. Your code suggestion above works like a charm. Now, I can work on expanding the midi range. Thank you again, Grumpy Mike. You made my weekend!