User:Laurier Rochon/prototyping/arduino recorder

From XPUB & Lens-Based wiki

Smooth Rough arduino pattern recorder/playback

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 (there can be 1min at the beginning though, that's fine)
  • Play the pattern back
  • And then erase it from memory, begin recording again

HARD

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


SOFT

Self-resetting / state-run / compact / verbose 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.

So the 'state' var controls the flow of recordings here.

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

const int b = 2;   //button pin
int bs=0;          //button state
int state=0;       //0 is waiting, 1 is pressed, 2 is released
boolean sr=false;  //started recording?
int t[100];        //recordings array
int c=0;           //counter index for recordings

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

void loop(){                                // all the heavy lifting is here
   bs = digitalRead(b);                     // read the state
   if(!sr){ if(bs==1) sr=true;  }else{      // if user has started clicking, turn SR to true
    if(bs && state==0){ state=1; t[c] = millis(); c++; Serial.println("tstamped"); }   //button pressed, last state : waiting
    if(!bs && state==1){ state=2; t[c] = millis(); c++; Serial.println("tstamped"); }  //button unpressed, last state : pressed
    if(!bs && state==2){ state=0; }                                                    //button unpressed, last state : waiting
    if((millis() - t[c-1])>5000){ p(); }                                               //check if there has been 5 secs of silence
   }
}

void p(){                                              //playback function
  Serial.println("Playing back");
  for(int a=1;a<c-1;a++){
    tone(13, 600,t[a]-t[a-1]);                         //play the tone
    delay(t[a+1]-t[a]);                                //wait
  }
  sr = !sr; memset(t,0,100); c=0;                      //flush & clean
  Serial.println("You can start recording again");     //start 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);
   } 
  }
  
}