Thanks for replying @PieterP, noted about The Encoder class being replaced by AHEncoder.
Now the sketch works but there are a couple of things to fix:
-
the encoders send value of 127 & 1 rather than 65 & 1 and the reading is imprecise (skipping between values).
-
the disable/enable logic still needs attention. I've added a latch function when the buttons are long-pressed; the sketch below works but it crashes if I long-press a button while already in long-press mode—likely due to a conflict.
EDIT: I want to ensure a clean switch between modes by disabling all encoders briefly (100 ms) before calling the LongPress mode. I thought this could help prevent glitches or crashes due to overlapping encoder state transitions. I've added a 100ms delay between disabling all encoders and enabling the new one.
The sketch runs but the board freezes when I LongPress.
RE-EDIT: I managed to get the sketch working making sure I wasn't disabling elements already disabled. I still have the problem with the encoders though.
RE-RE-Edit: Problem with the encoders sorted: I changed the ContinuousCC Sender to RelativeCCSender.
#include <Control_Surface.h>
USBMIDI_Interface midi;
Button button2 = 14;
Button button3 = 15;
Button button4 = 16;
AHEncoder enc2 = { 3, 4 };
AHEncoder enc3 = { 5, 6 };
AHEncoder enc4 = { 7, 8 };
constexpr unsigned long LONG_PRESS_DURATION = 500; // ms
struct LongPressLatch {
Button &button;
unsigned long pressStartTime = 0;
bool longPressDetected = false;
bool menuActive = false;
LongPressLatch(Button &btn) : button(btn) {}
void begin() {
button.begin();
}
bool update() {
button.update();
if (button.getState() == Button::Pressed) {
if (!pressStartTime) {
pressStartTime = millis();
} else if (!longPressDetected && (millis() - pressStartTime >= LONG_PRESS_DURATION)) {
longPressDetected = true;
menuActive = !menuActive; // Toggle menu state
return true; // Indicates latch state changed
}
} else {
pressStartTime = 0;
longPressDetected = false;
}
return false;
}
bool isMenuActive() const {
return menuActive;
}
};
LongPressLatch lpButton2(button2);
LongPressLatch lpButton3(button3);
LongPressLatch lpButton4(button4);
// Encoders for Menu Mode
BorrowedMIDIRotaryEncoder<ContinuousCCSender> enc2to1 = {
enc2, MCU::V_POT_1, 1, 1, {},
};
BorrowedMIDIRotaryEncoder<ContinuousCCSender> enc3to1 = {
enc3, MCU::V_POT_1, 1, 1, {},
};
BorrowedMIDIRotaryEncoder<ContinuousCCSender> enc4to1 = {
enc4, MCU::V_POT_1, 1, 1, {},
};
// Encoders for Normal Mode
BorrowedMIDIRotaryEncoder<ContinuousCCSender> enc2to2 = {
enc2, MCU::V_POT_2, 1, 1, {},
};
BorrowedMIDIRotaryEncoder<ContinuousCCSender> enc3to3 = {
enc3, MCU::V_POT_3, 1, 1, {},
};
BorrowedMIDIRotaryEncoder<ContinuousCCSender> enc4to4 = {
enc4, MCU::V_POT_4, 1, 1, {},
};
void setup() {
Control_Surface.begin();
lpButton2.begin();
lpButton3.begin();
lpButton4.begin();
enc2to1.disable();
enc3to1.disable();
enc4to1.disable();
}
void disableAllEncoders() {
enc2to1.disable();
enc3to1.disable();
enc4to1.disable();
enc2to2.disable();
enc3to3.disable();
enc4to4.disable();
}
void loop() {
Control_Surface.loop();
// Button 2
if (lpButton2.update()) {
disableAllEncoders();
delay(100);
if (lpButton2.isMenuActive()) {
enc2to1.enable();
} else {
enc2to1.disable();
enc2to2.enable();
enc3to3.enable();
enc4to4.enable();
}
}
// Button 3
if (lpButton3.update()) {
disableAllEncoders();
delay(100);
if (lpButton3.isMenuActive()) {
enc3to1.enable();
} else {
enc3to1.disable();
enc2to2.enable();
enc3to3.enable();
enc4to4.enable();
}
}
// Button 4
if (lpButton4.update()) {
disableAllEncoders();
delay(100);
if (lpButton4.isMenuActive()) {
enc4to1.enable();
} else {
enc4to1.disable();
enc2to2.enable();
enc3to3.enable();
enc4to4.enable();
}
}
}