const int ledPins[] = {2, 3, 4, 5};
const int buttonPins[] = {6, 7, 8, 9};
const int blueLedPin = 10;
const int yellowLedPin = 12;
const int switchPin = 11;
const int potPin = A0;
constexpr uint8_t numSteps = 4;
constexpr unsigned long debounceDelay = 20;
constexpr unsigned long blinkDuration = 50;
constexpr int minBPM = 30;
constexpr int maxBPM = 255;
unsigned long stepInterval = 300; // This will be dynamically updated based on the pot value
bool storedStates[2][numSteps] = {{false}, {false}};
uint8_t currentStep = 0;
unsigned long previousStepTime = 0;
unsigned long blinkStartTime[2] = {0, 0};
bool blinkActive[2] = {false, false};
unsigned long lastDebounceTimes[numSteps] = {0};
int buttonStates[numSteps] = {HIGH, HIGH, HIGH, HIGH};
int lastButtonStates[numSteps] = {HIGH, HIGH, HIGH, HIGH};
void setup() {
for (uint8_t i = 0; i < numSteps; i++) {
pinMode(ledPins[i], OUTPUT);
pinMode(buttonPins[i], INPUT_PULLUP);
}
pinMode(blueLedPin, OUTPUT);
pinMode(yellowLedPin, OUTPUT);
pinMode(switchPin, INPUT_PULLUP);
pinMode(potPin, INPUT);
}
void loop() {
const unsigned long currentTime = millis();
const bool switchState = digitalRead(switchPin);
const uint8_t activeSequence = switchState ? 0 : 1; // Switch logic inverted due to INPUT_PULLUP
updateTempo(); // Update stepInterval based on the potentiometer
handleButtons(activeSequence, currentTime);
updateSequencer(currentTime);
updateDisplay(activeSequence);
updateTriggerLeds(currentTime);
}
void updateTempo() {
int potValue = analogRead(potPin);
int bpm = map(potValue, 0, 1023, minBPM, maxBPM);
// Calculate the stepInterval (ms) based on BPM
stepInterval = 60000 / bpm;
}
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) {
// Toggle the active sequence's stored state
storedStates[activeSequence][i] = !storedStates[activeSequence][i];
}
}
}
lastButtonStates[i] = reading;
}
}
void updateSequencer(unsigned long currentTime) {
if (currentTime - previousStepTime >= stepInterval) {
currentStep = (currentStep + 1) % numSteps;
previousStepTime = currentTime;
// Trigger blue LED for sequence 1
if (storedStates[0][currentStep]) {
blinkStartTime[0] = currentTime;
blinkActive[0] = true;
digitalWrite(blueLedPin, HIGH);
}
// Trigger yellow LED for sequence 2
if (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) {
// Handle blue LED blinking
if (blinkActive[0] && (currentTime - blinkStartTime[0] >= blinkDuration)) {
digitalWrite(blueLedPin, LOW);
blinkActive[0] = false;
}
// Handle yellow LED blinking
if (blinkActive[1] && (currentTime - blinkStartTime[1] >= blinkDuration)) {
digitalWrite(yellowLedPin, LOW);
blinkActive[1] = false;
}
}