Trying to instantly re-trigger a Routine, regardless of .wait value

I am trying syncopate colored text with a beat and am using a Routine to do so. Here is my GUI component for visualization:

The 1s and 0s are mapped to a Pseq which controls an amplitude argument. As time progresses, each ‘bar’ or text field, turns yellow, indicating those are the values being played.

image

I wrote this code to help sync the beat with the color. The ~t1_a_dur_state_a values help me keep track of duration args as I also need to factor in duration. This ~q0dur-~q8dur are initialized to 0 and then just increment +1 each per each beat.

My issue currently is that if the duration = 8, then the waitTime (the var I’m using to essentially quantize the Routine) is 8… and so, if I update the ~t1_a_dur_state_a value to say 0.125, it does not re-trigger the Routine until 8 seconds after. I need this ~waitTime value to be updated instantly and for the Routine to re-trigger instantly if the ~t1_a_dur_state_a value is triggered. Does anyone have any ideas on how to achieve this?

r = {
    inf.do {
        z.do {
            {

					if(~durbank[~t1_a_dur_state_a] == 8){~q0dur = ~q0dur + 1; ~waitTime = 8};
					if(~durbank[~t1_a_dur_state_a] == 4){~q1dur = ~q1dur + 1; ~waitTime = 4};
					if(~durbank[~t1_a_dur_state_a] == 2){~q2dur = ~q2dur + 1; ~waitTime = 2};
					if(~durbank[~t1_a_dur_state_a] == 1){~q3dur = ~q3dur + 1; ~waitTime = 1};
					if(~durbank[~t1_a_dur_state_a] == 0.5){~q4dur = ~q4dur + 1; ~waitTime = 0.5};
					if(~durbank[~t1_a_dur_state_a] == 0.25){~q5dur = ~q5dur + 1; ~waitTime = 0.25};
					if(~durbank[~t1_a_dur_state_a] == 0.125){~q6dur = ~q6dur + 1; ~waitTime = 0.125};
					if(~durbank[~t1_a_dur_state_a] == 0.0625){~q7dur = ~q7dur + 1; ~waitTime = 0.0625};
					if(~durbank[~t1_a_dur_state_a] == 0.03125){~q8dur = ~q8dur + 1; ~waitTime = 0.03125};


					~fulldur = ~q0dur+~q1dur+~q2dur+~q3dur+~q4dur+~q5dur+~q6dur+~q7dur+~q8dur;
					//(((t.beats.floor)%t.beatsPerBar+1)).postln;
					if(~fulldur >= 32){
					~q0dur=0;
					~q1dur=0;
					~q2dur=0;
					~q3dur=0;
					~q4dur=0;
					~q5dur=0;
					~q6dur=0;
					~q7dur=0;
					~q8dur=0;
					~fulldur=0;
					};
					~fulldur.postln;
				}.defer;
        };
			(~waitTime*t.tempo).wait;
    }
}.fork;

It isn’t well documented, but if you need to reschedule a running thread for an arbitrary time, follow this general format.

(
~waitTime = 1;

~reschedulePauseStream = { |player, newQuant|
	player.stop;
	PauseStream(player.originalStream, player.clock).play(quant: newQuant);
};

~task = PauseStream(Routine {
	inf.do { |i|
		[i, thisThread.beats].postln;
		~waitTime.wait;
	}
});

~task.play(quant: 1);
)

(
~waitTime = 0.5;
~task = ~reschedulePauseStream.(~task, 0.5);
)

~task.stop;

The central problem with rescheduling in SC is: Once you schedule something on the clock, there is no way to un-schedule it. You can change the object’s state so that it will do nothing when it wakes up… but it is going to wake up and see if there’s anything to do.

For rescheduling, what you want is for the task to be active at the new time, and inactive at the old time. You can’t have two different states in the same object – the same Routine, Task, whatever cannot be both active and inactive. So the solution above is to create a new player. The new player is active at the new time. The old player is still scheduled on the clock, but deactivated.

Because it’s a new player, it’s important to reassign back: ~task = when rescheduling is not optional.

hjh

@jamshark70, Thank you again for your help. I really appreciate it. This is working as expected!