// MARSHALL 8 BUTTON MIDI FOOTSWITCH
#include <MIDI.h>
MIDI_CREATE_DEFAULT_INSTANCE();
const uint8_t ToggleInPins[4] = {A0, A1, A2, A3};
const uint8_t ToggleOutPins[4] = {6, 7, 8, 9};
const uint8_t Togglepatches[4] = {0, 1, 2, 3};
const uint8_t channelInPins[4] = {2, 3, 4, 5};
const uint8_t channelOutPins[4] = {10, 11, 12, 13};
const uint8_t channelpatches[4] = {0, 1, 2, 3};
const size_t numberofChannelsIn = sizeof(channelInPins) / sizeof(channelInPins[0]);
const size_t numberofChannelsOut = sizeof(channelOutPins) / sizeof(channelOutPins[0]);
const size_t numberOfChannelPatches = sizeof(channelpatches) / sizeof(channelpatches[0]);
static_assert(numberofChannelsIn == numberofChannelsOut, "The number of buttons doesn't match the number of LEDs");
static_assert(numberofChannelsIn == numberOfChannelPatches, "The number of buttons doesn't match the number of patches");
const size_t numberofTogglesIn = sizeof(ToggleInPins) / sizeof(ToggleInPins[0]);
const size_t numberofTogglesOut = sizeof(ToggleOutPins) / sizeof(ToggleOutPins[0]);
const size_t numberOfTogglePatches = sizeof(Togglepatches) / sizeof(Togglepatches[0]);
static_assert(numberofTogglesIn == numberofTogglesOut, "The number of buttons doesn't match the number of LEDs");
static_assert(numberofTogglesIn == numberOfTogglePatches, "The number of buttons doesn't match the number of patches");
const uint8_t CCButtonPin = 6;
const uint8_t CCLEDPin = 12;
const uint8_t controller = 14;
const uint8_t ccValueOff = 0;
const uint8_t ccValueOn = 1;
const uint8_t channel = 1;
void setup() {
for (const uint8_t &pin : ToggleInPins)
pinMode(pin, INPUT_PULLUP);
pinMode(CCButtonPin, INPUT_PULLUP);
for (const uint8_t &pin : ToggleOutPins)
pinMode(pin, OUTPUT);
pinMode(CCLEDPin, OUTPUT);
for (const uint8_t &pin : channelInPins)
pinMode(pin, INPUT_PULLUP);
pinMode(CCButtonPin, INPUT_PULLUP);
for (const uint8_t &pin : channelOutPins)
pinMode(pin, OUTPUT);
pinMode(CCLEDPin, OUTPUT);
MIDI.begin(MIDI_CHANNEL_OMNI) ;
}
int8_t getPressedChannelButton() {
for (int8_t i = 0; i < numberofChannelsIn; i++)
if (digitalRead(channelInPins[i]) == LOW)
return i;
return -1;
}
int8_t getPressedToggleButton() {
for (int8_t i = 0; i < numberofTogglesIn; i++)
if (digitalRead(ToggleInPins[i]) == LOW)
return i;
return -1;
}
void setToggleOut(int8_t led, bool state) {
if (led >= 0)
digitalWrite(ToggleOutPins[led], state);
}
void setChannelOut(int8_t led, bool state) {
if (led >= 0)
digitalWrite(channelOutPins[led], state);
}
void updateChannelSelect() {
static int8_t activeSelection = -1;
int8_t pressedButton = getPressedChannelButton();
if (pressedButton >= 0 && pressedButton != activeSelection) {
setChannelOut(activeSelection, LOW);
activeSelection = pressedButton;
setChannelOut(activeSelection, HIGH);
MIDI.sendProgramChange(channelpatches[activeSelection], channel);
}
}
void updateToggleSelect() {
static int8_t activeSelection = -1;
int8_t pressedButton = getPressedToggleButton();
if (pressedButton >= 0 && pressedButton != activeSelection) {
setToggleOut(activeSelection, LOW);
activeSelection = pressedButton;
setToggleOut(activeSelection, HIGH);
MIDI.sendProgramChange(Togglepatches[activeSelection], channel);
}
}
bool controllerButtonIsPressed() {
const static unsigned long debounceTime = 25;
const static int8_t rising = LOW - HIGH;
const static int8_t falling = HIGH - LOW;
static bool previousState = LOW;
static unsigned long previousBounceTime = 0;
bool pressed = false;
bool state = digitalRead(CCButtonPin);
int8_t stateChange = state - previousState;
if (stateChange == falling) {
if (millis() - previousBounceTime > debounceTime) {
pressed = true;
}
} else if (stateChange == rising) {
previousBounceTime = millis();
}
previousState = state;
return pressed;
}
void updateController() {
static bool controllerState = false;
if (controllerButtonIsPressed()) {
controllerState = !controllerState;
digitalWrite(CCLEDPin, controllerState);
MIDI.sendControlChange(controller, controllerState ? ccValueOn : ccValueOff, channel);
}
}
void loop() {
updateChannelSelect();
updateToggleSelect();
updateController();
}