Timing error after long pre-processing

Hi all!

I have a data “audioalization” (like in visualization) project that requires fairly expensive preparatory calculations (several seconds) before starting any loops. Then, I get a timing error (“thread got too far behind in time”).

My guess is that SP’s timer is already running, thus causing the error. Is there any possibility to prevent that? E.g. to reset the timer?

Here is some code that should reproduce the behaviour:

# Fake calculation to simulate expensive pre-processing
for i in range(0, 10000000)
  x = 1 / 100.0
end

live_loop :tick do
  sample :elec_plip, rate: 2
  sleep sec_per_day
end

I know that I could use set_sched_ahead_time!, but the duration of the pre-processing is not really predictable as it depends on the amout of data.

Many thanks for any hints!

2 approaches (the second may be preferable):

  1. Place a little wait before the live_loop:
# Fake calculation to simulate expensive pre-processing
for i in range(0, 10000000)
  x = 1 / 100.0
end

wait(4)
live_loop :tick do
  sample :elec_plip, rate: 2
  sleep 1
end
  1. Set the live_loop's delay:
# Fake calculation to simulate expensive pre-processing
for i in range(0, 10000000)
  x = 1 / 100.0
end

live_loop :tick, delay: 4 do
  sample :elec_plip, rate: 2
  sleep 1
end

I hope this helps!

1 Like

Ok, thanks for that hint!

To make it work with the unpredictable duration, I will presumably have to measure the time it actually takes. But as Ruby’s Time class is available in SP, this should well be possible. I will try and report the solution here.

:+1: Works well with measuring time elapsed. The demonstrate by extending the example, it can be done like this:

start = Time.now
for i in range(0, 10000000)
  x = 1 / 100.0
end
duration = Time.now - start

live_loop :tick, delay: duration + 0.5 do
  sample :elec_plip, rate: 2
  sleep 1
end
1 Like

Ooh, I’ve never approached timing like that before. Very nice use of Ruby as an interpreted language!

By the way, you may have realised this, but the difference between approaches 1 and 2 is that delay is non-blocking. To illustrate that, here’s a sample program using in_thread, which also has a delay option:

in_thread do
  puts "test"
end

wait 1

in_thread delay: 1 do
  puts "test wait & delay"
end

in_thread do
  puts "test wait"
end

The output is:

{run: 2, time: 0.0}
 └─ "test"
 
{run: 2, time: 1.0}
 └─ "test wait"
 
{run: 2, time: 2.0}
 └─ "test wait & delay"
1 Like

So far, I used delay: 0.01 in most of my projects to sync loops with a “metronome” main loop without delaying the other loops by one iteration. So, “unconsciously”, I already made use of this fact. Thanks!

1 Like

Excellent, you’re welcome! :smiley:

1 Like

Another option is of course to forego the use of arbitrary delays, and to use the sync: option of live_loops to sync on a cue that you emit once your preprocessing has completed :slightly_smiling_face:

1 Like

Ah, that would simplify things! I can’t seem to figure it out however, whether I place the calculations and cue before or after the live_loop :sweat:

Here’s a straightforwardly erroneous attempt with cue placed before the live_loop:

# Fake calculation to simulate expensive pre-processing
for i in range(0, 10000000)
  x = 1 / 100.0
end

cue :start

live_loop :tick, sync: :start do
  sample :elec_plip, rate: 2
  sleep 1
end

I know that calling cue before sync means that sync will never detect a cue, so I tried placing the calculation and cue after the live_loop. This didn’t work either:

live_loop :tick, sync: :start do
  sample :elec_plip, rate: 2
  sleep 1
end

# Fake calculation to simulate expensive pre-processing
for i in range(0, 10000000)
  x = 1 / 100.0
end

cue :start

I’m not sure what I’m doing wrong x.x

True, you have a point :sweat_smile:
It’s less neat, but one way is to send the cue twice :joy:

1 Like

Ok, so that’s not foolproof either :stuck_out_tongue: It’s not my day today :joy:
For now, it looks like mlange’s solution might be best at the moment:

1 Like

Yep :blush: It was well worth a shot!