constexpr int ledPins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 46, 47, 48, 49};
constexpr int buttonPins[] = {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37};
constexpr int blueLedPin = 52;
constexpr int yellowLedPin = 53;
constexpr int switchPin = 51;
constexpr int potPin = A0;
constexpr int startStopSwitchPin = 50;
constexpr int invertSwitchPin = 38; //mirror mode
// Number of steps
constexpr uint8_t numSteps = 16;
// Timing constants
constexpr unsigned long debounceDelay = 20;
constexpr unsigned long blinkDuration = 50;
constexpr int minBPM = 30;
constexpr int maxBPM = 255;
// Tempo and sequence control
unsigned long stepInterval = 30; // Dynamically updated
unsigned long previousStepTime = 0;
uint8_t currentStep = 0;
bool sequencerRunning = false; // Tracks if the sequencer is running
// Sequence storage (2 sequences)
bool storedStates[2][numSteps] = {{false}, {false}};
// Button debounce and state tracking
unsigned long lastDebounceTimes[numSteps] = {0};
int buttonStates[numSteps] = {HIGH};
int lastButtonStates[numSteps] = {HIGH};
// LED blink control
unsigned long blinkStartTime[2] = {0, 0};
bool blinkActive[2] = {false, false};
enum Sequence { SEQUENCE_1, SEQUENCE_2 };
void setup() {
// Initialize pins for LEDs and buttons
for (uint8_t i = 0; i < numSteps; i++) {
pinMode(ledPins[i], OUTPUT);
pinMode(buttonPins[i], INPUT_PULLUP);
}
// Initialize control and indicator LEDs
pinMode(blueLedPin, OUTPUT);
pinMode(yellowLedPin, OUTPUT);
pinMode(switchPin, INPUT_PULLUP);
pinMode(startStopSwitchPin, INPUT_PULLUP);
pinMode(potPin, INPUT);
}
void loop() {
const unsigned long currentTime = millis();
const bool sequenceSwitchState = digitalRead(switchPin);
const uint8_t activeSequence = sequenceSwitchState ? SEQUENCE_1 : SEQUENCE_2;
// Check the state of the start/stop switch
sequencerRunning = digitalRead(startStopSwitchPin) == HIGH;
if (!sequencerRunning) {
currentStep = 0; // Reset to step 1
}
updateTempo(); // Update stepInterval based on the potentiometer
handleButtons(activeSequence, currentTime);
// Only update the sequencer if it's running
if (sequencerRunning) {
updateSequencer(currentTime);
updateDisplay(activeSequence);
} else {
displayBPM();
}
updateTriggerLeds(currentTime);
}
void updateTempo() {
// Read the potentiometer value and map it to BPM
int potValue = analogRead(potPin);
int bpm = map(potValue, 0, 1023, minBPM, maxBPM);
// Calculate stepInterval in milliseconds
stepInterval = (60000 / bpm) / 4;
}
void handleButtons(uint8_t activeSequence, unsigned long currentTime) {
for (uint8_t i = 0; i < numSteps; i++) {
const int reading = digitalRead(buttonPins[i]);
// Check for debounce
if (reading != lastButtonStates[i]) {
lastDebounceTimes[i] = currentTime;
}
if ((currentTime - lastDebounceTimes[i]) > debounceDelay) {
if (reading != buttonStates[i]) {
buttonStates[i] = reading;
if (buttonStates[i] == LOW) {
storedStates[activeSequence][i] = !storedStates[activeSequence][i];
}
}
}
lastButtonStates[i] = reading;
}
}
void updateSequencer(unsigned long currentTime) {
if (currentTime - previousStepTime >= stepInterval) {
currentStep = (currentStep + 1) % numSteps;
previousStepTime = currentTime;
const bool invertSequence = digitalRead(invertSwitchPin) == HIGH;
// Trigger blue LED for sequence 1
if ((invertSequence && !storedStates[0][currentStep]) || (!invertSequence && storedStates[0][currentStep])) {
blinkStartTime[0] = currentTime;
blinkActive[0] = true;
digitalWrite(blueLedPin, HIGH);
}
// Trigger yellow LED for sequence 2
if ((invertSequence && !storedStates[1][currentStep]) || (!invertSequence && storedStates[1][currentStep])) {
blinkStartTime[1] = currentTime;
blinkActive[1] = true;
digitalWrite(yellowLedPin, HIGH);
}
}
}
void updateDisplay(uint8_t activeSequence) {
const bool* states = storedStates[activeSequence];
for (uint8_t i = 0; i < numSteps; i++) {
digitalWrite(ledPins[i], (i == currentStep) ? !states[i] : states[i]);
}
}
void updateTriggerLeds(unsigned long currentTime) {
for (uint8_t seq = 0; seq < 2; seq++) {
if (blinkActive[seq] && (currentTime - blinkStartTime[seq] >= blinkDuration)) {
digitalWrite(seq == SEQUENCE_1 ? blueLedPin : yellowLedPin, LOW);
blinkActive[seq] = false;
}
}
}
void displayBPM() {
// Turn off LEDs 1-8
for (uint8_t i = 0; i < 8; i++) {
digitalWrite(ledPins[i], LOW);
}
// Display BPM on LEDs 9-16
int potValue = analogRead(potPin);
int bpm = map(potValue, 0, 1023, minBPM, maxBPM);
for (uint8_t i = 0; i < 8; i++) {
digitalWrite(ledPins[8 + i], (bpm >> i) & 1);
}
}