Although undocumented, it’s pretty easy to figure out the basic usage of Pstretch
q = Pbind(*[dur: 0.01, freq: 550 + Pwhite(0, 50)])
p = Pstretch(10, q).play
p.stop
Also, from the source the stretch value (first arg) can be a pattern or stream too.
p = Pstretch(Pwhite(1, 10), q).play
p.stop
And Pstretch will exit its embedInStream
if either stream becomes nil.
p = Pstretch(Pwhite(1, 10, 20), q).play // stops itself
q = Pbind(*[dur: 0.01, freq: 550 + Pwhite(0, 50, 5)])
p = Pstretch(Pwhite(1, 10, 20), q).play // stops even sooner
I’m a little miffed what Pstretchp
is supposed to add to that… The latter class uses two nested loops (but completely ignores any cleanups). So it looks like it will keep playing after the second stream returns nil. There are not many ways to generate something like that but here’s one
r = Pseq([1, nil], 3).asStream
r.nextN(7) // -> [ 1, nil, 1, nil, 1, nil, nil ]
So, putting that to use here:
q = Pbind(*[dur: 0.01, freq: 550 + Pseq([Pwhite(0, 50, 5), nil], 3)])
q.play // only one burst
p = Pstretch(10, q).play // one stretched burst
p = Pstretchp(10, q).play // keeps going (forever) past q nils
p.stop
p = Pstretchp(Pseries(10, -2, 5), q).play // 5 linked bursts, decreasing stretch factor