// Button handling variables
int buttonstate; // the current reading from the input pin
int last_buttonstate = LOW; // the previous reading from the input pin
int debounce_time = 100; // don't expect two pushes any quicker than this
// Beat counting variables
unsigned long prev_time = 0; // system time at last button push, in ms
unsigned long current_time; // system time at this button push, in ms
const int beats_max = 512; // just in case you push the button too many times
int beat_lengths[beats_max]; // array to store the beat lengths
int beat_length = 500; // calculated average of beat lengths
int beat_index = 0; // number of button presses
const int beat_timeout = 2000; // time after which beat_index resets, in ms
// Animation variables
int anim_time = 0; // time since last frame displayed
const int step_count = 8; // how many steps per beat
int step_length = 50; // how long a step lasts in ms
int channel_count = 8; // maximum 8 connected wires
byte frames[step_count] = {1,2,4,8,16,32,64,128}; // each byte is a frame. Each bit of each byte is a channel.
int current_frame = 0; // index to animation array
unsigned long anim_start = 0; // system time at start of animation
int frame_threshold = 0; // when it decreases, we advance to the next frame
int frame_prev_threshold = 0;
// Pattern switching variables
int anim_index=0; // index of list of animations
/*******************Setup Loop***************************/
void setup() {
// Initialize elwire outputs
pinMode(2, OUTPUT); // channel A index 0
pinMode(3, OUTPUT); // channel B index 1
pinMode(4, OUTPUT); // channel C index 2
pinMode(5, OUTPUT); // channel D index 3
pinMode(6, OUTPUT); // channel E index 4
pinMode(7, OUTPUT); // channel F index 5
pinMode(8, OUTPUT); // channel G index 6
pinMode(9, OUTPUT); // channel H index 7
// Initialise button inputs
pinMode(A1, INPUT_PULLUP); // BPM button
// Pin 13 is the onboard status LED if we need it
pinMode(13, OUTPUT);
// Create the animations from binary data
}
/*******************Main Loop***************************/
void loop() {
// read the current time and calculate time since last good button reading
current_time = millis();
int elapsed_time = current_time - prev_time;
// read the state of the switch
int reading = digitalRead(A1);
// if it's the first button push in a while, reset the indexes and timers
if (reading == HIGH && last_buttonstate == LOW && elapsed_time > beat_timeout){
beat_index = 0;
current_frame = 0;
anim_start = current_time;
prev_time = current_time;
frame_threshold = 0;
frame_prev_threshold = 100;
digitalWrite(13,HIGH);
}
// if it's been long enough, but not too long, then record a new beat.
if (reading == HIGH && last_buttonstate == LOW && elapsed_time < beat_timeout && elapsed_time > debounce_time) {
// record this as the new previous time
prev_time = current_time;
// increment the beat index and if we reach the end, go back round, just in case
++beat_index;
if (beat_index == beats_max) beat_index = 0;
// set the current beat to the measured time
beat_lengths[beat_index] = elapsed_time;
// calculate the new average beat length and step length
int running_total = 0;
for (int i=0; i<=beat_index; i++) {
running_total += beat_lengths[i];
}
beat_length = running_total / beat_index;
step_length = beat_length / step_count;
// and set the button state to HIGH so we don't trigger this again too soon
last_buttonstate == HIGH;
}
else {
last_buttonstate == LOW;
}
// update animation timers and see if we've passed a frame threshold
anim_time = current_time - anim_start; // how long since the animation started
frame_threshold = anim_time % step_length; // divide by step length and find remainder
// If a step has passed, increment the frame and set the outputs
if ( frame_threshold < frame_prev_threshold) { // when the remainder goes from high to low, we have started a new frame
if (current_frame >= step_count) current_frame = 0;
int pinout=0;
int channel_state=LOW;
for (int i=0; i< channel_count; i++){
channel_state = bitRead(frames[current_frame], i);
pinout = i+2;
digitalWrite(pinout,channel_state);
}
++current_frame;
}
frame_prev_threshold = frame_threshold;
// save the reading. Next time through the loop, it'll be the lastButtonState:
last_buttonstate = reading;
}