Synchronizing Tasks

Hi all,

I’m having a hell of a time trying to gets tasks to synchronize. The docs make this look pretty straightforward: call play on a task, tell it which TempoClock to use, set quant to a given number, then do the same thing for the other task. But this doesn’t seem to be working for me! I’ve got about 64 tasks set up with GUI buttons to start and stop them. They’re all yielding based on a central TempoClock I’ve set up and assigned to a variable (~timer), and all the tasks are stored in an array (called ~a). The action of the GUI buttons is set up to call play(~timer, quant: 4) on the index from a that matches the button. The buttons are playing the tasks successfully, but the tasks aren’t synching up. They seem to just be playing immediately on button press, so the end result sounds like a mess. I tried switching over to Tdef and adding a .clock_(~timer).quant_(4) to the end of the Tdef, but this didn’t fix it. Pdef was working just fine, but I wanted to switch over from Patterns to Tasks so I could handle voice/node management on the SynthDefs a little more specifically, rather than instantiating a new synth on each step. Does anyone have any ideas on how to get these tasks to actually synch up? If it helps, I’ve put the whole project I’m working on into a gist here. The TempoClock gets created on line 10 of the main .scd file. The GUI button action gets defined on line 497. The tasks I’m trying to get to play in synch will ultimately be between lines 990 and the end of the end of the file, but right now I’m just testing things out on the first 3 tasks before propagating those changes throughout the rest of the document. Those first three tasks are between lines 990 and 1081.

I took a quick look and I don’t see immediately that you’re doing anything wrong with quant.

Also tried a minimal test:

t = TempoClock(2);  // note, you do not need to `play` a new clock

(
Tdef(\test, {
	thisThread.beats.debug("start");
	loop {
		thisThread.beats.debug("go");
		1.0.wait;
	}
});
)

(
b = Button(nil, Rect(800, 200, 100, 50)).front
.states_([["stopped"], ["running"]])
.action_({ |view|
	if(view.value > 0) {
		Tdef(\test).play(t, quant: 4)
	} {
		Tdef(\test).stop;
	}
});
)

And I get e.g. start: 32.0 // go: 32.0 // go: 33.0 etc… so the syntax play(clock, quant: xxx) is fine.

I’d suggest to add thisThread.beats.debug("start"); at the start of your tasks. If you get non-multiples of 4, then it’s conclusive proof that the quant isn’t working (which can help continue the investigation).

hjh

ah, this was super helpful! Thanks so much. Adding thisThread.beats.debug("start"); to the start of the tasks and thisThread.beats.debug("go"); to the loop section of the tasks yielded some interesting results.

the interesting results
start: 3844.0
go: 3844.0
go: 3844.9375
go: 3845.875
go: 3846.8125
go: 3847.75
go: 3848.6875
go: 3849.625
go: 3850.5625
go: 3851.5
go: 3852.4375
go: 3853.375

So it seems like start is in fact happening on the beat, but go isn’t. The latter is weird to me because the task is set up with delta = ~timer.beatDur*2; at the beginning of the loop and delta.yield; at the end of the loop (wherein ~timer is a TempoClock.new(128/60);). I would think that, set up this way, go would print on every second beat (i.e., the duration of one beat multiplied by 2). I’m not sure why that isn’t happening.

EDIT: I think I might get it now. I vaguely remembered Eli Fieldsteel mentioning in a livestream that sometimes things “think” in seconds and sometimes in beats. So in this case, is the task looking for a delta that’s a number of beats? Changing the delta to, e.g., 1 seems to be producing the desired result

TempoClock’s time unit is beats, not seconds.

If you want every other beat, you’d write delta = 2;.

hjh

1 Like

one other (hopefully quick and easy) question: If I wanted delta to be something different each time the loop is run (i.e., to function like dur in a Pbind), is there a way to do that? I assume there must be but am having more trouble than I would’ve expected figuring it out. Things I’ve tried that didn’t work:

delta = Pseq([1,2,1],inf).asStream.next
delta = PatternProxy(Pseq([1,2,1],inf)).asStream.next
delta = [1,2,1].next
delta = Routine({1;2;1}).next
delta = Routine({arg i; i=1;i=2;i=3}).next

None of these seem to work. Basically, I just need it to return 1 the first time it runs, 2 the second time it runs, 1 the third time it runs, 1 the fourth time it runs, 2 the fifth time it runs, etc. I’m able to get it to select randomly with, e.g., [1,2,1].choose, but is there a way to iterate through that list in order?

EDIT: I think the solution to the above was defining the PatternProxy outside of the Task itself and then calling next on it from within the task, as in:

~durs = PatternProxy(Pseq([1,2,1],inf)).asStream;
Tdef(\task, {
		var delta;
		loop {
			delta = ~durs.next;
			delta.yield;
		}
});