We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Hello,
I have to sychronize an animation to 1 frame per second.
Until now I used the millis() function for the timing. But annoyingly the time is running away. The Code is like:
draw(){
while ((millis () >= time + timeStep)){
println(time);
...
}
time = millis();
With timeStep = 500 I get time codes like:
8165,
8768,
9305,
9818
What I want is:
8000,
8500,
9000,
9500
How do I reallize this?
Answers
You could use the
frameCount
variable to go by frames instead.do you mean >= there?
your draw loop gets called, by default, 60 times a second. you're checking things within this draw loop. your code only runs when the draw loop as been called, so your timing is being obscured by that.
but you won't get exactly 500 millisecond steps anyway - the code takes time to run
@leclerke -- You are trying to take the 'slack' out of your clock to have millisecond-consistent starting times.
First,
frameRate()
won't work as a precision timer, it drifts:This outputs:
Instead, align your time frame within the draw loop, like this:
... which will print:
... etc.
P.S. as @koogs pointed out, your sample code above gives an infinite while loop that hangs the sketch on the first draw. You probably meant
<
.Yeah, koogs' of course right, I didn't want to put the whole code in here, its too huge ;-) I'm gonna try your way jeremy. Thank you so far!
I would not recommend using an empty
while
loop to take up the slack. The draw method is executed in the main event thread thread and there is a risk the while loop will hog the thread making it unresponsive to mouse and keyboard events.The code below averages out at 1 step every 500 milliseconds.
Here is the output I got
There's a separate Thread just to enqueue all Processing's input events.
However, the dequeueing happens in the main "Animation" Thread though. 8-|
In other words, enqueue is asynchronous, while dequeueing is synchronous. :-B
How very true. :)
So anything that restricts dequeuing the events will make the sketch less responsive to mouse and keyboard.
Yup! But eventually all of those accumulated input events are gonna be dequeued at once when draw() finally returns. :P
I suppose it depends on the goal, @quark.
I thought that @leclerke 's question was about millisecond-synchronized animation -- in the example requested, at precise half-second intervals. If we aren't losing input events, then isn't being "more responsive" in this case just another way of saying "desynchronized", which isn't the goal?
That's true but then all those dequeued events will be processed before
draw()
is executed again :)If leclerke REALLY needs exact millisecond precision (although I can't image why) then by all means use the while loop. But if the aim is to have accurate average timing and individual timings can be within a few milliseconds then it can be done without the while loop.
Using tight loops inside the main event processing thread to create delays is not good programming practice.
@quark -- I agree that this seems a bit hack-ish in order to achieve the stated goals (1000, 1500, 2000 etc.) -- especially if you don't need that last lousy millisecond. However I'm not sure that the language design of Processing agrees with you that this kind of main thread blocking is bad practice. After all, isn't Processing's
delay()
precisely a millisecond time checking loop that makes the main thread unresponsive? The difference is that writing a delay-aligning timer loop by hand such aswhile (millis()<nextTime){}
(as above) generates slightly more precise results than specifying the exact same thing in Processing's native idiom:...which produces:
Processing already got frameRate() in order to control its speed:
https://Processing.org/reference/frameRate_.html
delay() should only be used for other threads, not the main animation thread. [-X
@GoToLoop -- I understand that point of view -- and, as I've said, neither
frameRate()
nordelay()
actually produces the precision of a simplewhile(){}
-- which is functionally equivalent todelay()
, just faster. So:frameRate()
- imprecise, non-blockingif(millis()...)
- imprecise, non-blockingdelay()
- imprecise, blockingwhile(millis()...)
- precise, blockingIf you need to be precise, what should you use? while.
However, re: "delay() should only be used for other threads" -- I'm pointing out that using delay in the draw loop is actually how Processing documents and gives examples of the function! For one, the canonical delay() reference demo is actually "a sketch that needs to wait a few milliseconds" -- just like the OP example here -- and it uses delay in the draw loop (i.e. the main thread).
An infinite loop w/o any delay() uses 100% of the CPU time!!! :-SS
As I've already denounced many times in this forum, Processing API's reference is incomplete, imprecise and even superstitious! [-(
The delay() entry was added and removed countless times.
They tried to hide it in the hopes it'd be forgotten.
But folks coming from Arduino kept using it.
There are many useful functions and variables which are very useful but are censored too!
I only send folks to the reference b/c I'm lazy.
Even though they may learn bad programming and receive some erroneous info there! :-\"
Well, 100% of CPU time for a fraction of a second every single second isn't great. Of course, if your goal is to use the computer to achieve a particular timing/output/effect, it also isn't that bad.
Let's make this constructive:
Suppose someone wants to execute two Processing statements precisely 500 millis() apart. They can do this. They do this using
while
.Question: are there any other ways for them to achieve this result? If so, what are those ways?
For the purposes of this thought experiment, saying "you shouldn't want to do this in the first place!" = "no".
IMO, if some1 wants to execute 2 functions w/ a specific & precise time apart, they should do so in another Thread instead. (:|
Okay, a thread. So, when leclerke asked "How do I reallize this?"... how does he realize this? Does the thread contain a tight while loop? Or does it use delay, or some other Java timing facility?
Interesting approach! I don't think it works, though.
OP requested:
And this is producing e.g.:
...so I'm seeing thread actions drift about as much as if the sketch simply used
frameRate(2)
.You can replace the delay() there for a
while ()
block if you really need so.Regardless, placing such tight loop in a separate Thread eases the main 1. #:-S
Another way is to takeover Processing's timing loop with your own timer like this.
The output I got was
Just one blip at 5494 > 6510 = 1016ms
Not sure whether the 'language design of Processing' can have an an opinion ;) but thread blocking using tight loops IS bad programming practice. I have presented 2 methods that provide accurate (but not to the milisecond) timings.
If the OP wants exact millisecond precision, and I can't think why, then use the while loop if it has no adverse impact on the running sketch.
AFAIK the delay method was removed because it suspended the main thread preventing queued events to be processed but was dragged back because so may people used it. Just to clarify, the
delay()
method does NOT use a loop to create the delay rather it sends the main thread to sleep allowing other processes to use the CPU.Wow @quark, nice sketch's takeover! =D>
Although not as tricksy, neither synchronized w/ the "Animation Thread", I've got 1 example w/ TimerTask from this old forum thread: :ar!
https://forum.Processing.org/two/discussion/1725/millis-and-timer#Item_7
P.S.: Can you spot something very rare in Java there? Parameter sec is a closure inside the anonymous instance of class TimerTask! :P
When run() is called back after the tasked waiting time, it remembers the value passed to parameter sec, even though it shoulda ceased to exist when createScheduleTimer() returned earlier! @-)
That is a very cool timer, @GoToLoop !
For thread readers interested in millisecond timings or just in average drift, just be aware that -- like many solutions -- it drifts over time. You can't use it as an animation clock or a metronome if that matters.
This is an updated demo of the dreaded "tight loop timer." :ar!
It uses a conditional return of the draw loop to avoid taxing the CPU -- and the tight loop only runs once per timing step, whenever the clock is within less than a single frame worth of time to the next step time.
The net effect is to align the clock by pinning the CPU (and blocking the draw loop, becoming non-interactive) for a fraction of one frame per second. That works great at 60fps or 30fps; it can hit the CPU hard at really low framerates (like 2).
When set to a quarter-second metronome running at ~60fps, here is the example output:
Ah, sweet, clean, millisecond-perfect timings.
Each * indicates a frame that draw() skipped drawing -- each _ indicates a partial frame where it used a tight loop to perfectly align the clock before executing the next draw.
It might be interesting to try wrapping this approach in a thread. Not sure what that would do performance-wise, though.
Indeed method schedule() isn't adequate for metronome stuff: :-<
http://docs.Oracle.com/javase/8/docs/api/java/util/Timer.html#schedule-java.util.TimerTask-long-long-
However, scheduleAtFixedRate() is a hopeful approach: :>
http://docs.Oracle.com/javase/8/docs/api/java/util/Timer.html#scheduleAtFixedRate-java.util.TimerTask-long-long-
The whole timing problem cannot be solved that easily - there are just too many factors involved.
With @jeremydouglass's code, it will only work if your processor and GPU can actually do the specified frameRate. Once the processor starts getting overloaded, no solution could possibly work.
This has been explained in many of the existing pages related to timing. It just depends on how much inaccuracy is ok.
Hello
This is exactly what I was looking for, about my fast reading system....
Thanks