// Pin mappings
const int ledPins[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 46, 47, 48, 49};
const int buttonPins[] = {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37};
const int blueLedPin = 52;
const int yellowLedPin = 53;
const int switchPin = 51;
const int potPin = A0;
const int startStopSwitchPin = 50; // Switch pin for start/stop control
// 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 = 300; // 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};
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); // Start/stop switch pin
pinMode(potPin, INPUT);
}
void loop() {
const unsigned long currentTime = millis();
const bool sequenceSwitchState = digitalRead(switchPin);
const uint8_t activeSequence = sequenceSwitchState ? 0 : 1;
// Check the state of the start/stop switch
const bool startStopState = digitalRead(startStopSwitchPin);
if (startStopState == HIGH) {
sequencerRunning = true; // Start the sequencer
} else {
sequencerRunning = false; // Stop the sequencer
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);
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) {
// 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;
}
}