Automatically stopping a looping Tdef after reaching the end of an array

Hi everyone,
I have a nooby question that emerged from using a Tdef looping infinitely through a finite array. The array is used to provide frequency values to one or more Pdefs, but what happens is that reaching either boundaries of the array, the last value repeats itself apparently endlessly; the only way to stop is to manually stop the Pdefs playing. I’m looking for a neat way to monitor the progression of the loop, and interrupt (stop) the Tdef when reaching the endpoint (it’d be even neater if I can refer to this action to interrupt other external processes as well, such as the Pdefs playing).
The code looks something like this:

~array = (1..100);
~direction = 1;

Tdef(\x, {
var stream = Pscratch(
pattern: Pseq(~array, inf),
stepPattern: Pfunc{~direction}
).asStream;
loop{
stream.next.postln;
0.5.wait;
}});

Tdef(x).play;

~array is where I’m storing my frequency array, and ~direction is either -1 or 1. When ~direction=1, I would expect Tdef(\x) to stop after reaching ~array[~array.size], instead of looping back from the start; otherwise, if ~direction=-1 I would expect Tdef(\x) to stop after reaching ~array[0], instead of continuing posting ~array[0] value.

Any ideas?

hi @Robin_Morabito

Control Structures may help you

~array = (1..10);
~direction = 1;

(
Tdef(\x, {
	var stream = Pscratch(
		pattern: Pseq(~array, inf),
		stepPattern: Pfunc{~direction}
	).asStream;
	loop {
		var next = stream.next;
		if ( next == (~array.size - 1), { next.postln; Tdef(\x).stop }, { next.postln; 0.1.wait; } );
	}
});
)

Tdef(\x).play;
1 Like

This is a feature of Pscratch – it’s been a while since I looked at this class, but I think my reasoning was, as long as there is a step value, then you should get an output value.

This means that Pscratch in its current form isn’t useful for your case.

The indexing approach from the other thread would work.

(
~array = (1..100);
~direction = 1;

Tdef(\x, {
	var index = 0, item;
	loop {
		item = ~array[index];

		// array out-of-bounds = nil item
		// so if this is not nil, then we are within bounds
		if(item.notNil) {
			item.postln;
			1.0.wait;
			index = index + ~direction;
		} {
			// yielding nil from a Task/Routine stops it
			nil.yield;
		};
	}
}).play;
)

(Note also that the stop condition from wehrk’s reply is a bit muddled – comparing a value retrieved from the array with the array size is certainly not guaranteed to work, except in the very specific and highly unlikely case of a sequential array.)

hjh

2 Likes

This is definitely a much more accurate solution.

Ok great, this makes a lot more sense. Thanks guys!

just if anyone’s interested, I ended up putting all the work done around these topics in a repo:

It’s a program for interactive sonification of earthquake data in Iceland, and uses an interface built on Arduino nano. If anyone has suggestions or feedbacks, it’s always much appreciated!