#include <Bounce2.h>
#include <MIDI.h>
#define BUTTON1_PIN 2
#define BUTTON2_PIN 3
#define BUTTON3_PIN 4
#define POT_PIN A0 // Pino analógico para o potenciômetro
// Tempo em milissegundos para considerar um pressionamento longo
#define LONG_PRESS_TIME 1000
// Intervalo máximo em milissegundos entre cliques para considerar duplo ou triplo clique
#define CLICK_INTERVAL 500
// Estrutura para armazenar type, val e channel
struct ButtonAction {
int type;
int val;
int channel;
};
const int numButtons = 3;
const int numClicks = 3;
Bounce debouncers[numButtons];
unsigned long pressStartTime[numButtons] = {0};
int clickCount[numButtons] = {0};
bool longPressDetected[numButtons] = {false};
bool simultaneousPressDetected[2] = {false};
// Variáveis de estado para o toggle
bool toggleStateButtonActions[numButtons][numClicks] = {false};
bool toggleStateSimultaneousActions[2] = {false};
bool toggleStateLongpressActions[numButtons] = {false};
// Atualiza o valor de val para toggle
int getToggleValue(bool &toggleState) {
toggleState = !toggleState;
return toggleState ? 127 : 0;
}
// Variável para armazenar o banco atual
int currentBank = 1;
const int maxBank = 1;
int lastStateFxPot = 0; // Último valor lido do potenciômetro
// Matriz para armazenar as ações para cada botão e banco
ButtonAction buttonActions[numButtons][numClicks] = {
{{70, 127, 1}, {71, 127, 1}, {72, 127, 1}}, // Botão 1, Banco 1 (simples, duplo, triplo)
{{73, 127, 1}, {74, 127, 1}, {75, 127, 1}}, // Botão 2, Banco 1
{{76, 127, 1}, {77, 127, 1}, {78, 127, 1}} // Botão 3, Banco 1
};
// Matriz para armazenar as ações simultâneas
ButtonAction simultaneousActions[2] = {
{79, 127, 1}, // Botões 1 e 2
{80, 127, 1} // Botões 2 e 3
};
// Matriz para armazenar as ações de pressionamento longo
ButtonAction longpressActions[numButtons] = {
{81, 127, 1}, // Botão 1
{82, 127, 1}, // Botão 2
{83, 127, 1} // Botão 3
};
ButtonAction getActionForButtonAndBank(int buttonIndex, int clickCount) {
if (buttonIndex >= 0 && buttonIndex < numButtons && clickCount >= 1 && clickCount <= numClicks) {
buttonActions[buttonIndex][clickCount - 1].val = getToggleValue(toggleStateButtonActions[buttonIndex][clickCount - 1]);
return buttonActions[buttonIndex][clickCount - 1];
}
return {-1, -1, -1}; // Ação inválida
}
ButtonAction getSimultaneousAction(int index) {
if (index >= 0 && index < 2) {
simultaneousActions[index].val = getToggleValue(toggleStateSimultaneousActions[index]);
return simultaneousActions[index];
}
return {-1, -1, -1}; // Ação inválida
}
ButtonAction getLongpressAction(int buttonIndex) {
if (buttonIndex >= 0 && buttonIndex < numButtons) {
longpressActions[buttonIndex].val = getToggleValue(toggleStateLongpressActions[buttonIndex]);
return longpressActions[buttonIndex];
}
return {-1, -1, -1}; // Ação inválida
}
void processClicks(int buttonIndex, int clickCount) {
ButtonAction action = getActionForButtonAndBank(buttonIndex, clickCount);
const char* clickTypes[] = {"Clique simples detectado!", "Duplo clique detectado!", "Triplo clique detectado!"};
Serial.print("Botão ");
Serial.print(buttonIndex + 1);
Serial.print(": ");
Serial.print(clickTypes[clickCount - 1]);
Serial.print(" ");
sendControlChange(action);
}
void handleSimultaneousPress() {
if (debouncers[1].fell() && debouncers[0].read() == LOW) {
simultaneousPressDetected[0] = true;
ButtonAction action = getSimultaneousAction(0);
Serial.print("Botão 1 e Botão 2 pressionados simultaneamente! ");
sendControlChange(action);
clickCount[0] = 0;
clickCount[1] = 0;
}
if (debouncers[1].fell() && debouncers[2].read() == LOW) {
simultaneousPressDetected[1] = true;
ButtonAction action = getSimultaneousAction(1);
Serial.print("Botão 2 e Botão 3 pressionados simultaneamente! ");
sendControlChange(action);
clickCount[1] = 0;
clickCount[2] = 0;
}
}
void handleButton(int buttonIndex) {
if (debouncers[buttonIndex].fell()) {
pressStartTime[buttonIndex] = millis();
clickCount[buttonIndex]++;
longPressDetected[buttonIndex] = false;
simultaneousPressDetected[0] = false;
simultaneousPressDetected[1] = false;
}
if (debouncers[buttonIndex].read() == LOW) {
unsigned long pressDuration = millis() - pressStartTime[buttonIndex];
if (pressDuration >= LONG_PRESS_TIME && !longPressDetected[buttonIndex]) {
longPressDetected[buttonIndex] = true;
ButtonAction action = getLongpressAction(buttonIndex);
Serial.print("Botão ");
Serial.print(buttonIndex + 1);
Serial.print(": Pressionamento longo detectado! ");
sendControlChange(action);
clickCount[buttonIndex] = 0;
}
} else {
if (millis() - pressStartTime[buttonIndex] > CLICK_INTERVAL && clickCount[buttonIndex] > 0 && !longPressDetected[buttonIndex] && !simultaneousPressDetected[0] && !simultaneousPressDetected[1]) {
processClicks(buttonIndex, clickCount[buttonIndex]);
clickCount[buttonIndex] = 0;
}
}
}
void sendControlChange(const ButtonAction &action) {
Serial.print("Type: ");
Serial.print(action.type);
Serial.print(", Val: ");
Serial.print(action.val);
Serial.print(", Channel: ");
Serial.println(action.channel);
//MIDI.sendControlChange(action.type, action.val, action.channel);
}
//MIDI_CREATE_DEFAULT_INSTANCE();
void setup() {
int buttonPins[numButtons] = {BUTTON1_PIN, BUTTON2_PIN, BUTTON3_PIN};
for (int i = 0; i < numButtons; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
debouncers[i].attach(buttonPins[i]);
debouncers[i].interval(25);
}
Serial.begin(9600);
}
void loop() {
for (int i = 0; i < numButtons; i++) {
debouncers[i].update();
handleButton(i);
}
handleSimultaneousPress();
// Leitura e mapeamento do potenciômetro
int potValue = analogRead(POT_PIN);
int mapPot = constrain(map(potValue, 0, 1023, 0, 127), 0, 127);
if (abs(mapPot - lastStateFxPot) > 1) {
Serial.print("Leitura = ");
Serial.print(mapPot);
Serial.print(" | Último = ");
Serial.println(lastStateFxPot);
//MIDI.sendControlChange(7, mapPot, 1);
}
lastStateFxPot = mapPot;
delay(10); // Pequeno delay para evitar muitas leituras consecutivas
}