8 step gate sequencer for modular synths

This is a simple 8 step gate sequencer with controls for clock speed, gate time and swing. It was pieced together out of various tutorials like the pushbutton, reading an analog pot, and the 595 shift register so look to those pages for more detailed build info. The switches are read from the built in digital pins and the leds are driven by the shift register.

I was originally planning to expand this to 16 steps and add some kind of reverse and pendulum functions but then I didn't touch the Arduino for 6 months and I forgot all about this project. So now I decided to post it as-is. There's currently a bug where the steps will clear themselves if you crank the clock speed up too fast but I haven't been able to fix that yet.

But it works just fine as-is for feeding gate sequences into my Doepfer modular so maybe it will be useful for somebody else too. I didn't have any 1/8" sockets so I just alligator clipped the tip and sleeve of a cable to the gate out and ground.

int y;
int j = 0;

// pins for the demux
int latchPin = 10;
int clockPin = 12;
int dataPin = 11;
int clockPotPin = 2;
int gatePotPin = 1;
int swingPotPin = 3;
int gateOutPin = 13;

// if the step is turned on we blink it off briefly to indicate the current step
int lastblink = 0;
int blinkstat = 0;
int blinkInt = 50;

// arrays for the toggle switches
byte inPin[8];
byte state[8];
byte previous[8];
int reading;

// for debouncing the switch
long time = 0;
long debounce = 200;

// clock
long previousMillis = 0;
long clockspeed = 1000;

// for swing
long stepLength;
long evenStep;
long oddStep;

// gate time as a percentage
int gatePercent = 50;
int gateTime;

// swing
int swingPercent = 0;
int swingTime;

// initial state
byte data = 0;

void setup() {
  state[0] = HIGH;
  state[1] = HIGH;
  state[2] = HIGH;
  state[3] = HIGH;
  state[4] = HIGH;
  state[5] = HIGH;
  state[6] = HIGH;
  state[7] = HIGH;
  previous[0] = LOW;
  previous[1] = LOW;
  previous[2] = LOW;
  previous[3] = LOW;
  previous[4] = LOW;
  previous[5] = LOW;
  previous[6] = LOW;
  previous[7] = LOW;
  inPin[0] = 2;
  inPin[1] = 3;
  inPin[2] = 4;
  inPin[3] = 5;
  inPin[4] = 6;
  inPin[5] = 7;
  inPin[6] = 8;
  inPin[7] = 9;
  pinMode(latchPin, OUTPUT);
  pinMode(gateOutPin, OUTPUT);
  pinMode(inPin[0], INPUT);
  pinMode(inPin[1], INPUT);
  pinMode(inPin[2], INPUT);
  pinMode(inPin[3], INPUT);
  pinMode(inPin[4], INPUT);
  pinMode(inPin[5], INPUT);
  pinMode(inPin[6], INPUT);
  pinMode(inPin[7], INPUT);
  Serial.begin(9600);
}


void loop() {

  // check the pushbuttons
  for (int i = 0; i < 8; i++) {
    reading = digitalRead(inPin[i]);
    if (reading == HIGH && previous[i] == LOW && millis() - time > debounce) {
      if (state[i] == HIGH){
        state[i] = LOW;
      }
      else{
        state[i] = HIGH;
        time = millis();    
      }
      data ^= (1 << i);
    }
    previous[i] = reading;
  }

  // check the clock speed
  clockspeed = analogRead(clockPotPin)+51;

  // check the swing pot & calculate swing time
  swingPercent = analogRead(swingPotPin)/20;
  swingTime = clockspeed*(swingPercent+50)/400;

  // if it's an even numbered step
  if (j%2 == 0){
    stepLength = swingTime*2;
  }  
  else {
    stepLength = clockspeed-(swingTime*2);

  }


  // check the gate pot & calculate gate time
  gatePercent = analogRead(gatePotPin)/10;
  gateTime = clockspeed*gatePercent/100;



  // if the blink interval has finished
  if (millis() - previousMillis > blinkInt) {
    // and if this step is turned on
    if (blinkstat == 1){
      // toggle the light off
      data ^= (1 << lastblink);
      digitalWrite(latchPin, 0);
      shiftOut(dataPin, clockPin, data);   
      digitalWrite(latchPin, 1);
      blinkstat = 0;
    }
  }

  // if the gate time is over
  if (millis() - previousMillis > gateTime) {
    // set the gate output to low
    digitalWrite(gateOutPin, 0);
  }

  // if the step is over
  if (millis() - previousMillis > stepLength) {
    //  reset the timer
    previousMillis = millis();
    // if we're at step 8, go back to 1
    if (j == 8) {
      j = 0; 
    }
    // toggle the light for this step
    y = (data >> j) & 1;
    // if the step is turned on toggle the light off and set the blink status to 1
    if ( y == 1 ) {
      data ^= (1 << j);
      digitalWrite(latchPin, 0);
      shiftOut(dataPin, clockPin, data);   
      digitalWrite(latchPin, 1);
      lastblink = j;
      blinkstat = 1;
      // and set the gate output to high
      digitalWrite(gateOutPin, 1);
    }
    // if the step is turned off, toggle the light on until the next step
    else {      
      data ^= (1 << j);
      digitalWrite(latchPin, 0);
      shiftOut(dataPin, clockPin, data);   
      digitalWrite(latchPin, 1);
      data ^= (1 << j);
      blinkstat = 0;
      // and set the gate output to low
      digitalWrite(gateOutPin, 0);
    }
    j++;
  }
}

void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
  int i=0;
  int pinState;
  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, OUTPUT);
  digitalWrite(myDataPin, 0);
  digitalWrite(myClockPin, 0);
  for (i=8; i>=0; i--)  {
    digitalWrite(myClockPin, 0);
    if ( myDataOut & (1<<i) ) {
      pinState= 1;
    }
    else {      
      pinState= 0;
    }
    digitalWrite(myDataPin, pinState);
    digitalWrite(myClockPin, 1);
    digitalWrite(myDataPin, 0);
  }
  digitalWrite(myClockPin, 0);
}