This project again is quite simple – although your breadboard will begin to look a bit busier. There are two sensors that you can use to set the frequency of two oscillators, and also a volume potentiometer and a tempo potentiometer. The speaker switches between playing the first and second frequencies at a rate specified by the tempo pot. You could also add a status LED, and play with LDRs instead of pots. This project is very easy to extend – if you have the components it shouldn’t be much more difficult to make a four (or more) step sequencer.

I have updated this code to make it more reliable – in the playTone method there is an extra check that makes sure that the tones play for as long as they should – check the freqOut function in the arduino playground for more information. It’s still a bit buggy when you turn the tempo right the way down, but this unpredictability actually makes for some pretty interesting noises so I decided not to fix it ; )

I have also included a new schematic so you can build it on the tiny Sparkfun breadboards that were supplied for the workshop last week.

/*
  6: Simple Two-Step Sequencer
 
 This project combines pretty much everything from the previous tutorials.
 It involves two oscillators, a status led, and tempo and volume pots.
 
 */

int speakerPin = 3;      //connect speaker to pin 3
int ledPin = 11;         //we'll use this pin for our status led
int oscillator1Pin = 0;  //we can set frequency for first step here...
int oscillator2Pin = 1;  //... and frequency for step 2 on this pin
int tempoPin = 2;        //read tempo pot here

/*
  The pinState variable checks if we are outputting a sound.
 By default we can set it to LOW - meaning "off".
 */
int pinState = LOW;   

long previousMicros;     //count microSeconds to control frequency
int frequency;           //variable to set frequency

long previousMillis;     //count milliSeconds to control tempo
int tempo = 120;         //default tempo is 120BPM

void setup(){
  Serial.begin(9600);
  pinMode(speakerPin, OUTPUT);
}

void loop(){

  //read from our analog pins and set our frequency limits
  float oscillator1 = analogRead(oscillator1Pin);
  oscillator1 = map(oscillator1, 0, 1023, 200, 2000);

  float oscillator2 = analogRead(oscillator2Pin);
  oscillator2 = map(oscillator2, 0, 1023, 200, 2000);

  //read and set tempo limits
  float tempo = analogRead(tempoPin);
  tempo = map(tempo, 0, 1023, 60, 1000);

  //algorithm to convert tempo into BPM
  float interval = (1000/tempo)*60;

  /*
  We can't use the delay function in this case,
   as it will freeze the sketch and disrupt the
   oscillators.
   Instead we use a method that counts milliSeconds,
   compares it to our BPM, and switches between which 
   oscillator should be in use.
   */

  //oscillator1
  if(millis()-previousMillis > interval/2){
    playTone(speakerPin, oscillator1, interval/2);
    analogWrite(ledPin, LOW);
  }
  //oscillator 2
  if(millis()-previousMillis  interval){
    previousMillis = millis();
  }
}

/*
  We use the same method here as above to
 switch our outputPin on and off without having
 to use delay() and thus keep everything running
 smoothly. 
 */

void playTone(int outputPin, int frequency, float tempo){

//this bit is new - it makes sure we're calculating the note's frequency correctly
  float hperiod = (500000 / frequency) -7;
  long cycles = ((frequency*tempo)/1000);
  for(long i=0; i frequency/2){
      previousMicros = micros();
      if(pinState == LOW){
        pinState = HIGH; //if the pin is already LOW, set it to HIGH
      }
      else{
        pinState = LOW;  //otherwise if it's HIGH, set it to LOW
      }
      digitalWrite(outputPin, pinState); //Write pinState to specified pin
    }
  }
}