Something like Ppar but which stops when first stream ended?

Hi all,

Normal behavior for Ppar is to end when the last of the patterns in its list ends. However, in my current experiment, I’d like a version of Ppar that ends as soon as one of its patterns end. Am I missing the obvious way to do it? If so, I’d appreciate a hint. If not, what would be an approach to accomplish this?

Thanks!

Pfindur?

(
a = Pbind(\degree, Pseq([0,2,4],inf));
b = Pbind(\octave, Pseq([3]));

p = Pfindur(2, Ppar([a,b]));
)
p.play

I’m aware of Pfindur and Pfin but in my use case I cannot easily know exactly how long each of the patterns will take (they are dynamically “compiled” from external data).

I’m somewhat surprised that nothing like it seems to exist yet.

This seems like a straightforward and simple addition to Ppar. I think it’s as simple as:

Ppar : ListPattern {
    var waitForAll = true;
    // ...
}

and:

// Ppar.sc:29
if (nexttime.notNil && waitForAll, {
1 Like

If @shiihs (or anyone!) gets this working, it should be proposed as a pull request, I think this would be a useful addition to sclang.

I was surprised too. I roughly remember that there are other Patterns, that end if one stream ends, but I couldn’t find them. However when dealing with subpatterns Pspawner is your best friend:

p = Pbind(\note, Pn(0, 3));
q = Pbind(\note, 2);

r = [p, q];

// you can emulate Ppar's behaviour like this
Pspawner { |sp|
	sp.par(p);
	sp.par(q)
}.play


// this finishes in the special case when first stream ends
Pspawner { |sp|
	sp.par(Pseq([p, Prout { sp.suspendAll } ]));
	sp.par(q)
}.play


// for an arbitrary number of patterns
Pspawner { |sp|
	r.do { |p| sp.par(Pseq([p, Prout { sp.suspendAll }])) }
}.play

You could write a little helper class or Function for this. A further advantage of Pspawner is that you can easily adapt the finishing behaviour in special cases.

1 Like

changing

var waitForAll = true;

to

var  >waitForAll = true;

in your suggestion makes it possible to write e.g.

p = Ppar([Pseq([0.1,0.2,0.3], 1).trace, Pseq([0.6], inf).trace], 1).waitForAll_(false).play;

which seems to work as expected, thanks for that!

Thanks for this solution too, it works well and is quite flexible.