Monday, 31 August 2020

Final Project: Step Sequencer

Step Sequencer:

Main loop of sketch: Reads analog inputs used to control synth parameters. The controller reads and re-reads analog inputs until preset timer overflows. SIGNAL(PWN_INTERRUPT)  launches.

SIGNAL defined by PWN_INTERRUPT overflow. Synth runs at set frequency, regardless of main loop. 

1. Declare global variables (oscillator parameters). Hardware dependent functions (PWM_INTERRUPT). 
2. Frequency Mapping tables for grain repetition frequency. (Pentatonic mapping: default)
3. AudioOn() - sets PWM timer. 
4. setup() - PWM output in OUTPUT mode. 
5. AudioOn() triggers PWM timer.
6. Setting LED status. 

Casing Design - Built in Blender:





12x White Knobs
16x Rotary Potentiometers (10k)
4x Black Knobs
8x Momentary Button
8x LEDs
1x Arduino Mega 2560 R3
1x Audio Jack
1x Barrel Jack


 Fritz_Sequencer

Code:

int tempo = 100000;

int pattern = 0;

int counter = 0;


int a1 = 0; int a2 = 0; int a3 = 0; int a4 = 0; int a5 = 0; 

int b1 = 0; int b2 = 0; int b3 = 0; int b4 = 0; int b5 = 0; 

int c1 = 0; int c2 = 0; int c3 = 0; int c4 = 0; int c5 = 0; 

int d1 = 0; int d2 = 0; int d3 = 0; int d4 = 0; int d5 = 0; 

int e1 = 0; int e2 = 0; int e3 = 0; int e4 = 0; int e5 = 0; 

int f1 = 0; int f2 = 0; int f3 = 0; int f4 = 0; int f5 = 0; 

int g1 = 0; int g2 = 0; int g3 = 0; int g4 = 0; int g5 = 0; 

int h1 = 0; int h2 = 0; int h3 = 0; int h4 = 0; int h5 = 0; 


int live_sync_phase = 0;

int live_grain_phase = 0;

int live_grain_decay = 0;

int live_grain2_phase = 0;

int live_grain2_decay = 0;


 pinMode(39, OUTPUT); digitalWrite(39, LOW);

  pinMode(41, OUTPUT); digitalWrite(41, LOW);

  pinMode(43, OUTPUT); digitalWrite(43, LOW);

  pinMode(45, OUTPUT); digitalWrite(45, LOW);

  pinMode(47, OUTPUT); digitalWrite(47, LOW);

  pinMode(49, OUTPUT); digitalWrite(49, LOW);

  pinMode(51, OUTPUT); digitalWrite(51, LOW);

  pinMode(53, OUTPUT); digitalWrite(53, LOW);


  pinMode(24, INPUT); digitalWrite(24, HIGH);

  pinMode(26, INPUT); digitalWrite(26, HIGH);

  pinMode(28, INPUT); digitalWrite(28, HIGH);

  pinMode(30, INPUT); digitalWrite(30, HIGH);

  pinMode(32, INPUT); digitalWrite(32, HIGH);

  pinMode(34, INPUT); digitalWrite(34, HIGH);

  pinMode(36, INPUT); digitalWrite(36, HIGH);

  pinMode(38, INPUT); digitalWrite(38, HIGH);


void loop() {



  counter++; 


  if(counter>tempo){ 


  counter=0; //Reset the counter variable      

  if(pattern==8){pattern=0;} //Make sure we're not about to go to imaginary step 9.

  pattern++; //Let all of the following code know that we're setting up for the next step      

  //Turn off all of the step indicator lights in preparation for lighting the correct one.

  digitalWrite(39, LOW);digitalWrite(41, LOW);digitalWrite(43, LOW);digitalWrite(45, LOW);

  digitalWrite(47, LOW);digitalWrite(49, LOW);digitalWrite(51, LOW);digitalWrite(53, LOW);


  live_sync_phase = map(analogRead(14),0,1023,-500,500);

  live_grain_phase = map(analogRead(10),0,1023,-200,200);

  live_grain_decay = map(analogRead(9),0,1023,-20,20);

  live_grain2_phase = map(analogRead(8),0,1023,-200,200);

  live_grain2_decay = map(analogRead(11),0,1023,-50,50);


  tempo = map(analogRead(15),0,1023,1000,32000);


  switch(pattern){


    case 1:

    syncPhaseInc = a1 + live_sync_phase; grainPhaseInc = a2 + live_grain_phase; grainDecay = a3 + live_grain_decay; grain2PhaseInc = a4 + live_grain2_phase; grain2Decay = a5 + live_grain2_decay; digitalWrite(53, HIGH); break;

    case 2:

    syncPhaseInc = b1 + live_sync_phase; grainPhaseInc = b2 + live_grain_phase; grainDecay = b3 + live_grain_decay; grain2PhaseInc = b4 + live_grain2_phase; grain2Decay = b5 + live_grain2_decay; digitalWrite(51, HIGH); break;

    case 3:

    syncPhaseInc = c1 + live_sync_phase; grainPhaseInc = c2 + live_grain_phase; grainDecay = c3 + live_grain_decay; grain2PhaseInc = c4 + live_grain2_phase; grain2Decay = c5 + live_grain2_decay; digitalWrite(49, HIGH); break;

    case 4:

    syncPhaseInc = d1 + live_sync_phase; grainPhaseInc = d2 + live_grain_phase; grainDecay = d3 + live_grain_decay; grain2PhaseInc = d4 + live_grain2_phase; grain2Decay = d5 + live_grain2_decay; digitalWrite(47, HIGH); break;

    case 5:

    syncPhaseInc = e1 + live_sync_phase; grainPhaseInc = e2 + live_grain_phase; grainDecay = e3 + live_grain_decay; grain2PhaseInc = e4 + live_grain2_phase; grain2Decay = e5 + live_grain2_decay; digitalWrite(45, HIGH); break;

    case 6:

    syncPhaseInc = f1 + live_sync_phase; grainPhaseInc = f2 + live_grain_phase; grainDecay = f3 + live_grain_decay; grain2PhaseInc = f4 + live_grain2_phase; grain2Decay = f5 + live_grain2_decay; digitalWrite(43, HIGH); break;

    case 7:

    syncPhaseInc = g1 + live_sync_phase; grainPhaseInc = g2 + live_grain_phase; grainDecay = g3 + live_grain_decay; grain2PhaseInc = g4 + live_grain2_phase; grain2Decay = g5 + live_grain2_decay; digitalWrite(41, HIGH); break; 

    case 8:

    syncPhaseInc = h1 + live_sync_phase; grainPhaseInc = h2 + live_grain_phase; grainDecay = h3 + live_grain_decay; grain2PhaseInc = h4 + live_grain2_phase; grain2Decay = h5 + live_grain2_decay; digitalWrite(39, HIGH); break;

  }


    if(digitalRead(24)==LOW){changeStep(1);}

    if(digitalRead(26)==LOW){changeStep(2);}

    if(digitalRead(28)==LOW){changeStep(3);}

    if(digitalRead(30)==LOW){changeStep(4);}

    if(digitalRead(32)==LOW){changeStep(5);}

    if(digitalRead(34)==LOW){changeStep(6);}

    if(digitalRead(38)==LOW){changeStep(7);}

    if(digitalRead(36)==LOW){changeStep(8);}

}}


void changeStep(int step_num){


  digitalWrite(39, LOW);digitalWrite(41, LOW);digitalWrite(43, LOW);digitalWrite(45, LOW);

  digitalWrite(47, LOW);digitalWrite(49, LOW);digitalWrite(51, LOW);digitalWrite(53, LOW);  


    switch(step_num){


    case 1:

    digitalWrite(53, HIGH); break;

    case 2:

    digitalWrite(51, HIGH); break;

    case 3:

    digitalWrite(49, HIGH); break;

    case 4:

    digitalWrite(47, HIGH); break;

    case 5:

    digitalWrite(45, HIGH); break;

    case 6:

    digitalWrite(43, HIGH); break;

    case 7:

    digitalWrite(41, HIGH); break; 

    case 8:

    digitalWrite(39, HIGH); break;

  }



while(1){  


  counter++;

  if(counter>tempo){


  counter=0;

  syncPhaseInc = mapPentatonic(analogRead(SYNC_CONTROL));


  grainPhaseInc  = mapPhaseInc(analogRead(GRAIN_FREQ_CONTROL)) / 2;

  grainDecay     = analogRead(GRAIN_DECAY_CONTROL) / 8;

  grain2PhaseInc = mapPhaseInc(analogRead(GRAIN2_FREQ_CONTROL)) / 2;

  grain2Decay    = analogRead(GRAIN2_DECAY_CONTROL) / 4; 


  if(digitalRead(24)==LOW && step_num==1){

    a1 = syncPhaseInc; a2 = grainPhaseInc; a3 = grainDecay; a4 = grain2PhaseInc; a5 = grain2Decay; 

    return;}


  else if(digitalRead(24)==LOW && step_num==2){

    b1 = syncPhaseInc; b2 = grainPhaseInc; b3 = grainDecay; b4 = grain2PhaseInc; b5 = grain2Decay; 

    return;}


  else if(digitalRead(24)==LOW && step_num==3){

    c1 = syncPhaseInc; c2 = grainPhaseInc; c3 = grainDecay; c4 = grain2PhaseInc; c5 = grain2Decay; 

    return;}


  else if(digitalRead(24)==LOW && step_num==4){

    d1 = syncPhaseInc; d2 = grainPhaseInc; d3 = grainDecay; d4 = grain2PhaseInc; d5 = grain2Decay; 

    return;}


  else if(digitalRead(24)==LOW && step_num==5){

    e1 = syncPhaseInc; e2 = grainPhaseInc; e3 = grainDecay; e4 = grain2PhaseInc; e5 = grain2Decay; 

    return;}


  else if(digitalRead(24)==LOW && step_num==6){

    f1 = syncPhaseInc; f2 = grainPhaseInc; f3 = grainDecay; f4 = grain2PhaseInc; f5 = grain2Decay; 

    return;}


  else if(digitalRead(24)==LOW && step_num==7){

    g1 = syncPhaseInc; g2 = grainPhaseInc; g3 = grainDecay; g4 = grain2PhaseInc; g5 = grain2Decay; 

    return;}


  else if(digitalRead(24)==LOW && step_num==8){

    h1 = syncPhaseInc; h2 = grainPhaseInc; h3 = grainDecay; h4 = grain2PhaseInc; h5 = grain2Decay; 

    return;}


    }

  }

}


Algorithmic Synthesis: Grain

Two triangle waves (1. Frequency, 2. Decay) calculated based on analog inputs. 







Interrupts, EEPROM, I2C

Interrupts: 
The processor responds to important events. Interrupts interrupt whatever the processor is doing and executes code designer to react to external stimulus. 

EEPROM (Electrically Erasable Programmable Read-Only Memory):
Solid state computer memory. Permanent storage similar to a hard drive in computers. Can be read, erased and re-written electronically. 

MicrocontrollerEEPROM
ATmega328 (Arduino Uno, Nano, Mini)1024 bytes
ATmega168 (Arduino Nano)512 bytes
ATmega2560 (Arduino Mega)4096 bytes
Last State: The EEPROM keeps data even when the Arduino resets or when power is removed.

Remembers the last state of a variable/remembers how many times an appliance was activated.

Ex Scenario. LAMP (on) connected to Arduino -- Arduino loses power -- When power is back on, LAMP stays off (does not keep it's last change).

Solution: Save LAMP state in EEPROM and add condition to sketch to check whether the state of the lamp corresponds to the previous state. 

Schematic:

1x Arduino Uno
1x LED
1x Resistor
1x Button
1x 1k Resistor 
1x Breadboard
5x Jumpers
Code: 
#include <EEPROM.h>

const int buttonPin = 8;    // pushbutton pin
const int ledPin = 4;       // LED pin

int ledState;                // variable to hold the led state
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin


// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {

  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);

  digitalWrite(ledPin, ledState);

  Serial.begin (9600);

  checkLedState(); 
}

void loop() {
 
  int reading = digitalRead(buttonPin);

  if(reading != lastButtonState) {

    lastDebounceTime = millis();
  }

  if((millis() - lastDebounceTime) > debounceDelay) {
  

    if(reading != buttonState) {
      buttonState = reading;
    
      if(buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }


  digitalWrite(ledPin, ledState);
  EEPROM.update(0, ledState);
  lastButtonState = reading;
}

void checkLedState() {
   Serial.println("LED status after restart: ");
   ledState = EEPROM.read(0);
   if(ledState == 1) {
    Serial.println ("ON");
    digitalWrite(ledPin, HIGH);
   } 
   if(ledState == 0) {
    Serial.println ("OFF");
    digitalWrite(ledPin, LOW);
   }
}

Oscillator/Synth/Shift Register

Synth Piano:

1x Arduino Uno
1x Breadboard
1x Accu 3,7v
1x LiPo Rider Pro SEEED Studio
1x Audio Amplifier 
2x Speakers
27x Buttons
27x Resistors (10k)
3x Shift Register - Parallel to Serial 


Screen%20shot%202016 04 15%20at%2017.58.47

Code: 
#include <SPI.h>
#include <Arduino.h> #include <MusicPlayer.h> //#include <SD.h>
#define dataPin 8 #define clockPin 9 #define latchPin 10
#define dataPin2 5 #define clockPin2 6 #define latchPin2 7
#define dnote 4
#define plus 3 #define moin 2
byte switchVar1 = 0; byte switchVar2 = 0; byte switchVar3 = 0;
51int instru = 79;
int sensorvalue = 500;
void son (int myNote, int myVolu, int myTon, int myToff) {
player.midiNoteOn(0, myNote, myVolu); delay(myTon);
player.midiNoteOff(0, myNote, myVolu); delay(myToff);
}
int but(int x, int y, int h, int l) {
if ((digitalRead (moin) == HIGH) && (x<=(h-y))) { x=x+y
;
}
else if ((digitalRead (plus) == HIGH) && (x>=(l+y))){
x=x-y; }
52
return x; }
void setup() {

Serial.begin(9600);
player.beginInMidiFmt();
player.midiWriteData(0xB0, 0x07, 120); // set volume player.midiDemoPlayer();pinMode(latchPin2, OUTPUT); pinMode(clockPin2, OUTPUT); pinMode(dataPin2, INPUT);
pinMode(dnote, INPUT);
pinMode(plus, INPUT);
pinMode(moin, INPUT); }
void loop() {

sensorvalue = analogRead(5); // Serial.println(sensorvalue);if (sensorvalue < 540){ Serial.println("1"); volu = but (volu, 5, 127, 0); Serial.println(volu); delay (1000); } else if (sensorvalue < 620){ Serial.println("2"); ton = but (ton, 10, 10, 1000); Serial.println(ton); } else if (sensorvalue < 700){ Serial.println("3"); toff = but (toff, 10, 10, 1000); Serial.println(toff); } else if (sensorvalue < 780){ Serial.println("4"); player.midiWriteData(0xB0, 0, 0x78); player.midiWriteData(0xC0, 40, 0); } else if (sensorvalue < 815){ Serial.println("5"); player.midiWriteData(0xB0, 0, 0x79); 54if (instru > 8)instru = 1; instru = but(instru, 1, 8, 1); player.midiWriteData(0xC0, instru, 0); Serial.println(instru); } else if (sensorvalue < 845){ Serial.println("6"); player.midiWriteData(0xB0, 0, 0x79); if ((instru<9) || (instru>16)) instru = 9; instru = but(instru, 1, 16, 9); player.midiWriteData(0xC0, instru, 0); Serial.println(instru); } else if (sensorvalue < 870){Serial.println("7"); player.midiWriteData(0xB0, 0, 0x79); if ((instru<17) || (instru>24)) instru = 17; instru = but(instru, 1, 24, 17); player.midiWriteData(0xC0, instru, 0); Serial.println(instru); } else if (sensorvalue < 888){ Serial.println("8"); player.midiWriteData(0xB0, 0, 0x79); if ((instru<25) || (instru>40)) instru = 25; instru = but(instru, 1, 40, 25); player.midiWriteData(0xC0, instru, 0); 55Serial.println(instru); } else if (sensorvalue < 910){ Serial.println("9"); player.midiWriteData(0xB0, 0, 0x79); // set percussion 78 or synth 79 if ((instru<41) || (instru>56)) instru = 41; instru = but(instru, 1, 56, 41); player.midiWriteData(0xC0, instru, 0); Serial.println(instru); } else if (sensorvalue < 928){ Serial.println("10"); player.midiWriteData(0xB0, 0, 0x79); if ((instru<57) || (instru>80)) instru = 65; instru = but(instru, 1, 80, 57); player.midiWriteData(0xC0, instru, 0); Serial.println(instru); } else if (sensorvalue < 945){ Serial.println("11"); player.midiWriteData(0xB0, 0, 0x79); if ((instru<81) || (instru>96)) instru = 91; instru = but(instru, 1, 96, 81); player.midiWriteData(0xC0, instru, 0); Serial.println(instru); } else if (sensorvalue < 1000){Serial.println("12"); player.midiWriteData(0xB0, 0, 0x79); // set percussion 78 or synth 79 if ((instru<97) || (instru>124)) instru = 99; instru = but(instru, 1, 120, 97); player.midiWriteData(0xC0, instru, 0); Serial.println(instru); } else{ Serial.println("Error"); }switch (switchVar1) { case B1: son (55, volu, ton, toff); break; case B10: son (53, volu, ton, toff); break; case B100: son (52, volu, ton, toff); break; case B1000: son (50, volu, ton, toff); break; case B10000: son (54, volu, ton, toff); break; case B100000: son (51, volu, ton, toff); break; case B1000000: son (49, volu, ton, toff); break; case B10000000: son (48, volu, ton, toff); break; } 59switch (switchVar2) { case B1: son (59, volu, ton, toff); break; case B10: son (58, volu, ton, toff); break; case B100: son (60, volu, ton, toff); break; case B1000: son (57, volu, ton, toff); break; case B10000: son (63, volu, ton, toff); break; case B100000: son (62, volu, ton, toff); break; case B1000000: son (61, volu, ton, toff); break; 60 case B10000000: son (56, volu, ton, toff); break; }switch (switchVar3) { case B1: son (71, volu, ton, toff); break; case B10: son (65, volu, ton, toff); break; case B100: son (69, volu, ton, toff); break; case B1000: son (67, volu, ton, toff); break; case B10000: son (70, volu, ton, toff); break; case B100000: son (66, volu, ton, toff); 61 break; case B1000000: son (68, volu, ton, toff); break; case B10000000: son (64, volu, ton, toff); break; } if (digitalRead (dnote) == HIGH) son (72, volu, ton, toff);Serial.println("-------------------"); }
int i; 62 int temp = 0; int pinState; byte myDataIn = 0; pinMode(myClockPin, OUTPUT); pinMode(myDataPin, INPUT);
for (i=7; i>=0; i--) { digitalWrite(myClockPin, 0); delayMicroseconds(2); temp = digitalRead(myDataPin); if (temp) { pinState = 1;} else { //debugging turn it off 63 //print statement: 0 pinState = 0; } digitalWrite(myClockPin, 1); } return myDataIn; }