
|
EventStreamPlayer quant for absolute time
Cascading problems... OK...
Suppose I want to play a pattern at an exact specific time on the tempo clock. This is fine if there have been no meter changes: if x is the current clock time and y is the desired start time in the future (x < y), then the next multiple of y after x is y.
But, if there are major changes, then the clock's base bar beat is a positive number and the event stream player actually get scheduled for y + clock.baseBarBeat.
In the past I would have scheduled the event stream player directly on the clock using schedAbs, but with the fix for sync in patterns, this isn't safe in general (unless you know for sure that there is no sync in the pattern that you're playing).
I solve this in my library with an AbsoluteTimeSpec class, which answers to next time on grid with the given time. But it doesn't seem like playing a pattern at a precalculated time is all that exotic a requirement -- is there a workaround with the main library as it is?
e.g.,
( var numChannels = 2; SynthDef("ddwmetro" ++ numChannels, { |t_trig = 0, i_out = 0, gate = 1| var sig; sig = Klank.ar(`[ [ 403.06749750304, 2947.8690441738, 992.38941400907 ], [ 0.15740193350554, 1, 0.63826208002513 ], [ 0.017389599589788, 0.0032695745154834, 0.0098681694619578 ] ], K2A.ar(t_trig)); FreeSelf.kr(gate <= 0); Out.ar(i_out, sig ! numChannels) }).memStore; )
TempoClock.play({ TempoClock.beatsPerBar = 5; "changed meter".postln }, -1); TempoClock.baseBarBeat;
( p = Pmono(\ddwmetro2, \trig, 1, \delta, Pfunc { thisThread.clock.beatsPerBar } ).play(quant: TempoClock.nextBar(TempoClock.beats.debug("current beat")).debug("next bar"))); )
current beat: 5925.2526872044 next bar: 5928.2 an EventStreamPlayer
TempoClock.default.queue.do(_.postln);
11621.4 // <<-- whoopsie! a Function [ 11621.4, a Function ]
hjh : H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:
"Come said the Muse, Sing me a song no poet has yet chanted, Sing me the universal." -- Whitman
|

|
Re: EventStreamPlayer quant for absolute time
Hi James,
I don't understand, with the default approach to sync, I don't think this should be an issue.
The sync'ed stream may keeps its virtual time position, so it may run late for a while but it will ultimately resynchronize.
With the syncNoTimingCompression, the problem is that the virtual time of the pattern becomes unsynced from that of the clock. I suppose we could have syncNoTimingCompression do something like:
var time = thisThread.beats;
server.sync;
thisThread.beats = time;
(I don't know if more needs to be done to jam the time correctly.)
Obviously this alters the timing for everything scheduled by that clock, but that would be the idea....
RJK
On Apr 19, 2009, at 4:04 PM, James Harkins wrote: Cascading problems... OK...
Suppose I want to play a pattern at an exact specific time on the tempo clock. This is fine if there have been no meter changes: if x is the current clock time and y is the desired start time in the future (x < y), then the next multiple of y after x is y.
But, if there are major changes, then the clock's base bar beat is a positive number and the event stream player actually get scheduled for y + clock.baseBarBeat.
In the past I would have scheduled the event stream player directly on the clock using schedAbs, but with the fix for sync in patterns, this isn't safe in general (unless you know for sure that there is no sync in the pattern that you're playing).
I solve this in my library with an AbsoluteTimeSpec class, which answers to next time on grid with the given time. But it doesn't seem like playing a pattern at a precalculated time is all that exotic a requirement -- is there a workaround with the main library as it is?
e.g.,
( var numChannels = 2; SynthDef("ddwmetro" ++ numChannels, { |t_trig = 0, i_out = 0, gate = 1| var sig; sig = Klank.ar(`[ [ 403.06749750304, 2947.8690441738, 992.38941400907 ], [ 0.15740193350554, 1, 0.63826208002513 ], [ 0.017389599589788, 0.0032695745154834, 0.0098681694619578 ] ], K2A.ar(t_trig)); FreeSelf.kr(gate <= 0); Out.ar(i_out, sig ! numChannels) }).memStore; )
TempoClock.play({ TempoClock.beatsPerBar = 5; "changed meter".postln }, -1); TempoClock.baseBarBeat;
( p = Pmono(\ddwmetro2, \trig, 1, \delta, Pfunc { thisThread.clock.beatsPerBar } ).play(quant: TempoClock.nextBar(TempoClock.beats.debug("current beat")).debug("next bar"))); )
current beat: 5925.2526872044 next bar: 5928.2 an EventStreamPlayer
TempoClock.default.queue.do(_.postln);
11621.4 // <<-- whoopsie! a Function [ 11621.4, a Function ]
hjh : H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:
"Come said the Muse, Sing me a song no poet has yet chanted, Sing me the universal." -- Whitman
|

|
Re: EventStreamPlayer quant for absolute time
I guess I'm not clear on what you mean by "sync no timing compression."
To me, it's quite simple. The delta in the sync event tells you when the next event will occur. We don't know how long the sync will take (and we hope it's less than the delta -- I think this would be the user's responsibility). But we know the delta and we can remember the logical time at the beginning of the play function. Then, after returning from sync, the delta until the next event is the calculated next-time minus the logical time when the thread was unblocked.
This works:
( ~postTime = (play: { thisThread.clock.beats.postln.debug("logical time") }, delta: 0); ~sync = (delta: 1, play: { var saveTime = thisThread.beats; "syncing".debug; s.sync; "returned".debug; ~delta = (currentEnvironment.delta + saveTime - thisThread.beats).debug("rescheduling"); });
Pseq([ ~postTime, (type: \sine1, bufNum: 0, numFrames: 65536, numChannels: 1, amps: (1..100).reciprocal, delta: 0), ~sync, ~postTime.copy.put(\delta, 1), (type: \free, bufnum: 0) ], 1).play; )
810.855806355 logical time: 810.855806355 syncing returned rescheduling: 0.98549023600003 811.855806355 logical time: 811.855806355 -- exactly 1, good!
This, using your thisThread.beats_ approach, does not -- it appears that you're prevented from setting a thread's time back into the past. (Logical restriction.)
( ~postTime = (play: { thisThread.clock.beats.postln.debug("logical time") }, delta: 0); ~sync = (delta: 1, play: { var saveTime = thisThread.beats; "syncing".debug; s.sync; "returned".debug; thisThread.beats = saveTime; });
Pseq([ ~postTime, (type: \sine1, bufNum: 0, numFrames: 65536, numChannels: 1, amps: (1..100).reciprocal, delta: 0), ~sync, ~postTime.copy.put(\delta, 1), (type: \free, bufnum: 0) ], 1).play; )
1310.127884183 logical time: 1310.127884183 syncing returned 1311.144567839 logical time: 1311.144567839 -- > 1, fail
Obviously this alters the timing for everything scheduled by that clock, but that would be the idea....
That sounds like a very bad idea to me. But maybe you're using terminology in a way I'm not expecting, and I'm just not getting it.
hjh
: H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:
"Come said the Muse, Sing me a song no poet has yet chanted, Sing me the universal." -- Whitman
|

|
Re: EventStreamPlayer quant for absolute time
Also, my question in this thread has nothing to do with server sync. hjh On Apr 19, 2009, at 6:58 PM, ronald kuivila wrote: Hi James,
I don't understand, with the default approach to sync, I don't think this should be an issue. : H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:
"Come said the Muse, Sing me a song no poet has yet chanted, Sing me the universal." -- Whitman
|

|
Re: EventStreamPlayer quant for absolute time
Hi James,
'sync no timing compression' means that any time lost in the sync message is ignored - all events are delayed by that amount. So the timing of the EventStream will drift wrt to realtime. (Generally the delta associated with a synch would be 0, so it is more or less guaranteed to drift.) The question is if the EventStream and the clock that schedules it remain in sync. If they do, the problem you were describing will be avoided.
During the time waiting for the sync from the server, other clients of the clock may run. I don't think this is a major problem (basically whatever they do during that interval will be stretched by the delay created by the sync). It might be. If so, you would have to suspend the clock for the sync time. You could probably do that by grabbing its queue and setting it to an empty array.
Anyway, this is all a bit speculative. The good example would be loading a few hundred megabytes of soundfile into buffers.
RJK On Apr 19, 2009, at 10:31 PM, James Harkins wrote: I guess I'm not clear on what you mean by "sync no timing compression."
To me, it's quite simple. The delta in the sync event tells you when the next event will occur. We don't know how long the sync will take (and we hope it's less than the delta -- I think this would be the user's responsibility). But we know the delta and we can remember the logical time at the beginning of the play function. Then, after returning from sync, the delta until the next event is the calculated next-time minus the logical time when the thread was unblocked.
This works:
( ~postTime = (play: { thisThread.clock.beats.postln.debug("logical time") }, delta: 0); ~sync = (delta: 1, play: { var saveTime = thisThread.beats; "syncing".debug; s.sync; "returned".debug; ~delta = (currentEnvironment.delta + saveTime - thisThread.beats).debug("rescheduling"); });
Pseq([ ~postTime, (type: \sine1, bufNum: 0, numFrames: 65536, numChannels: 1, amps: (1..100).reciprocal, delta: 0), ~sync, ~postTime.copy.put(\delta, 1), (type: \free, bufnum: 0) ], 1).play; )
810.855806355 logical time: 810.855806355 syncing returned rescheduling: 0.98549023600003 811.855806355 logical time: 811.855806355 -- exactly 1, good!
This, using your thisThread.beats_ approach, does not -- it appears that you're prevented from setting a thread's time back into the past. (Logical restriction.)
( ~postTime = (play: { thisThread.clock.beats.postln.debug("logical time") }, delta: 0); ~sync = (delta: 1, play: { var saveTime = thisThread.beats; "syncing".debug; s.sync; "returned".debug; thisThread.beats = saveTime; });
Pseq([ ~postTime, (type: \sine1, bufNum: 0, numFrames: 65536, numChannels: 1, amps: (1..100).reciprocal, delta: 0), ~sync, ~postTime.copy.put(\delta, 1), (type: \free, bufnum: 0) ], 1).play; )
1310.127884183 logical time: 1310.127884183 syncing returned 1311.144567839 logical time: 1311.144567839 -- > 1, fail
Obviously this alters the timing for everything scheduled by that clock, but that would be the idea....
That sounds like a very bad idea to me. But maybe you're using terminology in a way I'm not expecting, and I'm just not getting it.
hjh
: H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:
"Come said the Muse, Sing me a song no poet has yet chanted, Sing me the universal." -- Whitman
|

|
Re: EventStreamPlayer quant for absolute time
Whilst this thread got hijacked, the initial question is being ignored :)
Anyway, I think it is possible to start a pattern at an exact clock time with a truly horrid workaround:
TempoClock.setMeterAtBeat(4, TempoClock.nextBar(TempoClock.beats));
Pn((play: { thisThread.clock.beats.debug("now") }), 1).play(quant: TempoClock.nextBar(TempoClock.beats).debug("desired onset time") - TempoClock.baseBarBeat);
But yeeeesh, that's some serious ugly. hjh On Apr 19, 2009, at 4:04 PM, James Harkins wrote: Cascading problems... OK...
Suppose I want to play a pattern at an exact specific time on the tempo clock. This is fine if there have been no meter changes: if x is the current clock time and y is the desired start time in the future (x < y), then the next multiple of y after x is y.
But, if there are major changes, then the clock's base bar beat is a positive number and the event stream player actually get scheduled for y + clock.baseBarBeat.
In the past I would have scheduled the event stream player directly on the clock using schedAbs, but with the fix for sync in patterns, this isn't safe in general (unless you know for sure that there is no sync in the pattern that you're playing).
I solve this in my library with an AbsoluteTimeSpec class, which answers to next time on grid with the given time. But it doesn't seem like playing a pattern at a precalculated time is all that exotic a requirement -- is there a workaround with the main library as it is?
e.g.,
( var numChannels = 2; SynthDef("ddwmetro" ++ numChannels, { |t_trig = 0, i_out = 0, gate = 1| var sig; sig = Klank.ar(`[ [ 403.06749750304, 2947.8690441738, 992.38941400907 ], [ 0.15740193350554, 1, 0.63826208002513 ], [ 0.017389599589788, 0.0032695745154834, 0.0098681694619578 ] ], K2A.ar(t_trig)); FreeSelf.kr(gate <= 0); Out.ar(i_out, sig ! numChannels) }).memStore; )
TempoClock.play({ TempoClock.beatsPerBar = 5; "changed meter".postln }, -1); TempoClock.baseBarBeat;
( p = Pmono(\ddwmetro2, \trig, 1, \delta, Pfunc { thisThread.clock.beatsPerBar } ).play(quant: TempoClock.nextBar(TempoClock.beats.debug("current beat")).debug("next bar"))); )
current beat: 5925.2526872044 next bar: 5928.2 an EventStreamPlayer
TempoClock.default.queue.do(_.postln);
11621.4 // <<-- whoopsie! a Function [ 11621.4, a Function ] : H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:
"Come said the Muse, Sing me a song no poet has yet chanted, Sing me the universal." -- Whitman
|