User:Laurier Rochon/prototyping/arduino recorder

From XPUB & Lens-Based wiki

Rough arduino pattern recorder/playback #1

Simple code to emulate a pattern recording device. It has a few little glitches, but the main idea works.

  • Program starts
  • User starts using pushbutton to determine a pattern (up to 100 clicks before array goes out of bounds)
  • After 5 seconds of silence, after user has started pushing (there can be 1min at the beginning though, that's fine)
  • Play the pattern back in a loop, with 2 sec intervals

(there is no way to restart it yet, I guess that will be part II)

HARD

  • Piezo in ground/pin 13
  • Pushbutton in 10K resistor => pin 2 / 5V power


SOFT

self-resetting / state-run / compact version

The realization with this version was that there are actually not 3 states, but more like 2 & 1/2. Counting the 'waiting' period as state 1, pressed as state 2 - but the 'released' state not being an actual state in itself, rather the un-doing of the 'pressed' one. To paraphrase, you can't really 'hold' the unpressed state, it just delimits/completes the 'pressed' action. It also seemed weird to have a for/while loop inside the loop() statement, creating somewhat of a nested loop.

With that in mind, I built a simple IF structure (could easily of been a case/switch) that changes states depending on the previous state, and button position. Since all the combinations have discrete properties, it is possible to only mark the difference in state change, and let the loop run 'in between the cracks' (i.e. when none of the conditions are met) of the program, triggering only the recording function when we need it.

I've somewhat compacted the variables and code a bit for readability, sorry.

const int b = 2;
int bs=0;
int state=0; //0 is waiting, 1 is pressed, 2 is released
boolean sr=false;
unsigned long time;
int t[100];
int c=0;

void setup() {
  pinMode(b, INPUT);
  tone(13,600,10);
  Serial.begin(9600); 
  Serial.println("Start recording...");
}

void loop(){
   bs = digitalRead(b);
   if(!sr){ if(bs==1) sr=true;  }else{
    if(bs && state==0){ state=1; t[c] = millis(); c++; Serial.println("tstamped"); }
    if(!bs && state==1){ state=2; t[c] = millis(); c++; Serial.println("tstamped"); }
    if(!bs && state==2){ state=0; }
    if((millis() - t[c-1])>5000){ p(); }
   }
}

void p(){
  Serial.println("Playing back");
  for(int a=1;a<c-1;a++){
    tone(13, 600,t[a]-t[a-1]);
    delay(t[a+1]-t[a]); 
  }
  sr = !sr;
  memset(t,0,100);
  c=0;
  Serial.println("You can start recording again");
}


(better than below)

const int buttonPin = 2;
const int nb=100;
int bs = 0;
int cs = 0;
unsigned long time;
int values[nb];
int c=0;
boolean startrec = false;

void setup() {
  pinMode(buttonPin, INPUT);
  tone(13,600,10);
  Serial.begin(9600); 
  Serial.println("Start recording...");
}

void loop(){
   bs = digitalRead(buttonPin);
   time = millis();
   char buffer[255];
   
   if(cs!=bs){
     startrec=true;
     cs=bs;
     values[c] = time;
     sprintf(buffer,"Recorded : %d",time);     
     Serial.println(buffer);
     c++;
   }
   
   if(startrec){
     int deadtime = time-values[c-1];
     if(deadtime>5000) playback();
   }
}

void playback(){
    Serial.println("Playing back");
    int cc = 0;
     for(int a=1;a<c-1;a++){
       int playtime = values[a]-values[a-1];
       int delaytime = values[a+1]-values[a];
       tone(13, 600,playtime);
       delay(delaytime);
     }
     Serial.println("Finished playing back");
     delay(1000);
     restart();
}

void restart(){
   startrec = false;
   memset(values,0,nb);
   c=0;
   Serial.println("You can start recording again");
}

(old version)

//globals
const int buttonPin = 2;
int values[100];
int c=0;
unsigned long time;
boolean startrec = false;

int buttonState = 1;
int newstate = 1;

void setup() {  
  pinMode(buttonPin, INPUT);
  Serial.begin(9600); 
}

void loop(){
  //time counter
  time = millis();
  buttonState = digitalRead(buttonPin);
  //this prevents the button from recording 2-3 times in the same push...
  delay(10);
  
  //if state has changed
  if(buttonState != newstate){
   startrec = true;
   
   //store in the array, print to screen and increment array index
   newstate = buttonState;
   values[c] = time/100; 
   Serial.println(values[c]);
   c++;
  }
  
  if(startrec){
   //if it's been more than 5 seconds doing nothing, after you've started pushing
   int deadtime = (time/100)- values[c-1];
   if(deadtime > 50){
     int cc = 0;
     //loop through values, and interpret the time difference as delays
     for(int a=0;a<c-1;a++){
        tone(13, 600,10);
        int dtime = (values[a+1]-values[a])*100;
        delay(dtime);
     }
     //gimme something to look at
     Serial.println("waiting 2 secs...replaying");
     delay(2000);
   } 
  }
  
}