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!!!

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

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;
}

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

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;
}

Hello,

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.

:)

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);
}

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

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: )