Tone Sequencer: GateModSeq.ino

//
// Tone sequencer with gate and modulation outputs
//

// Author:  P.J. Drongowski
// Version: 1.1
// Date:    26 June 2016
// 
// Copyright (c) 2016 Paul J. Drongowski
//               Permission granted to redistribute and modify

#include "ToneFreq.h"
#include "ToneNote.h"

// Define input pins
int arInputPin = 0 ;
int levelInputPin = 1 ;

// Define output pins
int gatePin = 1 ;
int tonePin = 5 ;
int modPin = 9 ;

// Note control values
int noteIndex = 0 ;
int note = 0 ;
int duration = 0 ;

// Filter control values
int attackDuration = 0 ;
int releaseDuration = 0 ;
int sustainDuration = 0 ;
int sustainLevel = 64 ;
int arIncrement = 0 ;
int modValue = 0 ;

// Define, declare and initialize the musical notes
#define TEMPO    (90)
#define REST     -1
#define SEQUENCE 18
#define START    15
int sequence[SEQUENCE][2] = {
  NOTE_As3, EIGHTH, 
  REST,     SIXTEENTH, 
  NOTE_Gs4, SIXTEENTH, 
  REST,     EIGHTH, 
  NOTE_As4, EIGHTH,
  REST,     EIGHTH, 
  NOTE_C4,  EIGHTH, 
  NOTE_Cs4, EIGHTH, 
  NOTE_D4,  EIGHTH,
  NOTE_Ds4, EIGHTH, 
  REST,     SIXTEENTH, 
  NOTE_As4, SIXTEENTH, 
  REST,     EIGHTH, 
  NOTE_Cs5, EIGHTH,
  REST,     EIGHTH, 
  NOTE_G3,  EIGHTH, 
  NOTE_Gs3, EIGHTH, 
  NOTE_A3,  EIGHTH
} ;

void pulseGatePin() {
  digitalWrite(gatePin, LOW) ;
  digitalWrite(gatePin, HIGH) ;
  delay(50) ;
  digitalWrite(gatePin, LOW) ;
}

//
// Sample the analog inputs (sustain level and
// attack/release time). Compute durations and the
// attack/release increment (ramp value).
//
void computeModValues() {
  int arValue ;
  sustainLevel = analogRead(levelInputPin) >> 2 ;
  arValue = analogRead(arInputPin) >> 4 ;
  attackDuration = arValue ;
  sustainDuration = duration - (arValue << 1) ;
  releaseDuration = arValue ;
  arIncrement = sustainLevel / arValue ;
  modValue = 0 ;
}

void setup() {
  Serial.begin(9600) ;
  // Define pin modes
  pinMode(gatePin, OUTPUT) ;
  // Initialize pin values
  digitalWrite(gatePin, LOW) ;
  // Start playing the first note in the sequence
  // This note could be a pick-up!
  noteIndex = START ;
  note = sequence[noteIndex][0] ;
  duration = sequence[noteIndex][1] ;
  computeModValues() ;
  if (note != REST) {
    tone(tonePin, note) ;
    digitalWrite(gatePin, HIGH) ;
  }
}

void loop() {
  delay(1) ;
  duration-- ;
  if (duration <= 0) {
    // Current note has expired.
    noTone(tonePin) ;
    digitalWrite(gatePin, LOW) ;
    delay(1) ;
    // Find the next note to be played
    if (noteIndex >= (SEQUENCE-1)) {
        noteIndex = 0 ;
    } else {
        noteIndex += 1 ;
    }
    note = sequence[noteIndex][0] ;
    duration = sequence[noteIndex][1] ;
    computeModValues() ;
    // Start playing the next note
    if (note != REST) {
      tone(tonePin, note) ;
      digitalWrite(gatePin, HIGH) ;
    }
  } else {
    // Note continues. Adjust modulation value.
    analogWrite(modPin, modValue) ;
    if (attackDuration > 0) {
      attackDuration-- ;
      modValue += arIncrement ;
    } else if (sustainDuration > 0) {
      sustainDuration-- ;
      modValue = sustainLevel ;
    } else if (releaseDuration > 0) {
      releaseDuration-- ;
      modValue -= arIncrement ;
    }
  }
}