TempoClock.sec2beats appears broken, can any one confirm this?

{ thisThread.clock.secs2beats(10).postln }.fork returns -9138.438647381
thisThread.clock.secs2beats(10).postln returns 10

I’m not using it wrong am I? that should return something reasonable right?

yes I am also seeing negative numbers here

also for TempoClock.secs2beats(10) in the main thread

I didn’t see them until restarting

This discrepancy is because of:

fork { [thisThread, thisThread.clock].postln };
-> [ a Routine, a TempoClock ]

[thisThread, thisThread.clock];
-> [ a Thread, class SystemClock ]

The confusion with the negative numbers is because beats2secs and secs2beats are operating on absolute time points, not durations.

var t = TempoClock.new;

SystemClock.sched(1, { t.stop });

	"TempoClock beats now = %
SystemClock seconds now = %
t.beats2secs(beats now) = %
t.secs2beats(SystemClock seconds now) = %
t.secs2beats(10) = %

TempoClock beats now = 0.0
SystemClock seconds now = 428.036806685
t.beats2secs(beats now) = 428.036806685
t.secs2beats(SystemClock seconds now) = 0.0
t.secs2beats(10) = -418.036806685

The timing model in SC goes like this:

SystemClock is the time reference. Everything goes back to SystemClock’s seconds. “0 seconds” is set when the sclang process boots up, and SystemClock advances according to std::chrono::high_resolution_clock (or std::chrono::steady_clock).

When you start a TempoClock, it’s a line beats = tempo * secs + b where b is such that 0 = tempo * secs + b (so b = -secondsAtTempoClockOnset * tempo). I think it doesn’t look exactly like that in the source code, but conceptually, that’s what it is.

The above example schedules a routine at 0 beats on t. To wake up on time, “beat 0” as an absolute time point must correspond to an absolute point on the “seconds” timeline. This is t.beats2secs(0). In fact t.beats2secs(t.beats) == SystemClock.seconds, always, by definition.

t.secs2beats then is taking an absolute point on the “seconds” timeline and converting it into the timepoint in beats on this TempoClock. t.beats2secs(10)… chances are, “10 seconds after sclang bootup” was a long time ago. If it was earlier than the moment of creating a tempo clock, then the beats value must be less than 0.


1 Like

I’ll add that to the docs later today.
Should probably be called beat2sec though — 4 beats (duration) verses the fourth beat (time point).