Timers Not Frame Rate Dependent & Starting On Demand - Oh Please Oh Please :)

Hello Forum,

I am making interactive visualizers that coordinate with sequenced visual automations and sound. I need to start a timer after a button is pushed (which I am pretty sure you can’t do with millis()) and I can’t use the frameCount() solution because I have just learned that computers vs. phones vs. tablets all have the possibility of different frame rates (30,60, even 120 sometimes) - animation timings will be out of sync for several devices. I have witnessed timings play out really differently using frameCount() in the same program run on my phone versus laptop. If I could figure out another reliable solution for a second timer that can be delayed before starting and not dependent of frame counts then I think I could make the project playback work across devices.

Please let mw know if you have another strategy for timers. Hope to hear from you all. Thank you!!!

2 Likes

Why that?
You made already a topic about timers recently.

1 Like

Like in Java you have an 15 microsecond increment on average though. Maybe this should just be subtracted, I don’t know?

let startTime;
let timerRun;

function setup() {
  createCanvas(100, 100);
  background(255);
  button = createButton('click me');
  button.position(20, 20);
  button.mousePressed(startTimer);
  
}

function draw() {
  if(timerRun) {
    if (millis() - startTime > 1000) {
      print(millis() - startTime-15);
      startTime = millis();
   
    }
  }
}

function startTimer() {
 startTime = millis(); 
 timerRun = true;
}
1 Like

Apologies if this new thread should have been added to the old one. I was thinking since the subject was a bit different that maybe a new thread was the appropriate path for clarity in search. Anyways, thanks for replying. :slight_smile:

Hi Noel,

I am not sure I understand your proposed solution here. I guess it is because I feel I need a very precise counter so that I can program things like at 20 seconds do this, at 40 seconds do this.

Side note: the reason I need the button to start the timer is because (I think) Google won’t let audio just come on with phones unless the user starts the audio. So, I have a start screen and then when the user starts the visualizer & the timer and audio start (previously using frameRate() option). But, as I mentioned before this fails on account of different devices having different frame rates.

No, no, I wasn’t complaining. If you’re finished with the sound visualization project and want to share it I’m interested :smiley:
As for your question I don’t know if there’s a js library like java has “java.util.TimerTask” to do exactly what you want. But the simple millis() timer has a accuracy within 20 ms, thus good enough for your project. Just run with multiple if blocks

1 Like

Hi Noel :slight_smile:

So millis() can be delayed to not start its count until a button is pressed? Am I so confused? :slight_smile: Or, maybe I don’t understand you. What do you mean by

Just run with multiple if blocks

You don’t invoke the timer with millis().
When a program starts, it starts a ‘stopwatch’ or ‘millisecond counter’ if you want it or not.
You can access the past time with the function millis();
So if you want a timer you will need a certain start time and then count the seconds that increment until it reaches the time-lap you want. This timer can be triggered by a button or an audio event etc. You can have several timers running in parallel with if blocks. In the code below, you have two independent 5 seconds timers. During the 5 seconds time lap, the buttons have a red color.

let timerRun1, timerRun2;

function setup() {
  createCanvas(500, 500);
  background(255);
  button1 = createButton('timer 1');
  button1.position(20, 20);
  button1.mousePressed(startTimer1);
  button2 = createButton('timer 2');
  button2.position(160, 20);
  button2.mousePressed(startTimer2);
  button1.style('background-color', color(255, 255, 255));
  button2.style('background-color', color(255, 255, 255));
}

function draw() {
  background(255);
  text('Milliseconds running since program start: ' +int(millis())+ '  millisecond', 5, 65);
  if (timerRun1) {
    let time_lap1 = millis() - startTime1;
    if (time_lap1 > 5000) {
      button1.style('background-color', color(255, 255, 255));
      timerRun1 = false;
    }
  }
  if (timerRun2) {
    let time_lap2 = millis() - startTime2;
    if (time_lap2 > 5000) {
      button2.style('background-color', color(255, 255, 255));
      timerRun2 = false;
    }
  }
}

function startTimer1() { 
  button1.style('background-color', color(255, 155, 155));
  startTime1 = millis(); 
  timerRun1 = true;
}

function startTimer2() { 
  button2.style('background-color', color(255, 155, 155));
  startTime2 = millis(); 
  timerRun2 = true;
}
2 Likes

Hello,

https://p5js.org/reference/#/p5/millis

This may (or may not) help:

You can use a mouse, key or any event to update:
whattimeisitatstartofstopwatch

Once you wrap your head around this it becomes easy to code.

:)

3 Likes

Hi Noel, that’s a nice solution! Thank you so much for all of your help and tume!!! I ended up working with setInterval(). I will post it below.

PS: here’s one of the Visualizers

'use strict';

var button;


let timer = 0;
let startProgram = false;
let loaded = false;




function setup() {

    loaded = true;
    beginButton()
    createCanvas(windowWidth, windowHeight);

    console.time('time')
    noSmooth(); //does this improve running?
    console.timeEnd('time')
}


function beginButton() {
    let col = color(255);
    let col2 = color(0);
    button = createButton("begin");
    button.mousePressed(beginExperience);
    button.position(width / 2 - 30, height - 40);
    button.size(60, 25);
    button.style('background-color', col);
    button.style("color", col2);

}

function draw() {

    background(0);
    if (startProgram == false || loaded == false) {
        showLoading();
    }

    //start automations & timer when button pressed	
    else {
 		
			if (timer<=5){
				fill (0,255,0);
			}
			else if (timer>5&&timer<=10){
			fill (255,0,0);
			}	
			else if (timer>11){
			fill (0,0,255);
			}	
      ellipse(mouseX,height/2,100,100);
			
			//timer report
			textSize (20);
		  text (timer,width/2,100);
			
    } //close timed events/experience screen

} //close draw




function beginExperience() {
    setInterval(() => {
        timer++;
    }, 1000)
    button.remove();
    startProgram = true;
}


function touchMoved() {
    return false; //this prevents dragging screen around on mobile
}


function showLoading() {
    background(0);
    textAlign(CENTER, CENTER);
    rectMode(CENTER);
    text('loading...', width / 2, height - 30);
}
2 Likes

Thanks glv - this is really helpful too. Thank you!

1 Like

Great! Now I understand what you wanted. setTimeout() is also a good timer sequencer, the way as used here.
The visualizer is really nice as well. The only thing that I would add in the opening screen, is a bit more detailed information on how it works. ( It took me some time to find out. :smiley: )

2 Likes