See Plambda
which lets you Plet
and Pget
from different Pbinds
as long as they are “bound” under the same Plambda
. (Frankly the name for this wrapper is pretty uninspired, as it has to do with data sharing RAM-like style. Something like Pcommon
would have been more fitting and Pput
and Pget
as they work like a common dictionary.)
Penvir
with independent: false
is somewhat similar but less fancy. Actually, you don’t even need use the independent :false
unless you want to share across Penvirs
. Contrast
e = (melody: Pshuf([1,2,3,4], inf).asStream);
(p = Penvir(e, Ppar([
Pbind(\degree, Pfuncn({~cnote = ~melody.next}, inf), \dur, 0.2),
Pbind(\degree, Pfuncn({~cnote}, inf), \ctranspose, 24, \dur, 0.2)
])))
r = p.asStream;
r.nextN(2, ()) // hit a few times to see they are in sync
e[\cnote] // -> nil, private copy is made for Penvir by default
// in contrast...
(p = Ppar([
Penvir(e, Pbind(\degree, Pfuncn({~cnote = ~melody.next}, inf), \dur, 0.2), false),
Penvir(e, Pbind(\degree, Pfuncn({~cnote}, inf), \ctranspose, 24, \dur, 0.2), false)
]))
r = p.asStream
r.nextN(2, ())
e[\cnote] // -> not nil now
Note that Pkey
doesn’t work to access stuff that goes in Penvir.envir
like ~cnote
above. If you hate that syntactic asymmetry, and would rather have something more like Pkey
, but alas still with a different name… you get Pget
from Plambda
.
(p = Plambda(Ppar([
Pbind(\degree, Plet(\melody, Pshuf([1,2,3,4], inf)), \dur, 0.2),
Pbind(\degree, Pget(\melody, repeats: inf), \ctranspose, 24, \dur, 0.2)
])));
r = p.asStream
r.nextN(2, ())
(Beware that Pget
only has repeat
on its 3rd arg; the 2nd is the default value, unlike Pkey
, which doesn’t come with that.)
Also
You cannot actually copy Routines
like that, you don’t get a real copy.
Thread : Stream {
copy { ^this } // sorry cannot copy
}
Routine : Thread {
// inherits Thread.copy
}
And speaking of gotchas, if you try not to use any of the above “specials”, but think that mere Ppar combined with [P]chaining might do it, well it does work, but when using you need account for how many streams you into pull in parallel… Compare:
(p = Ppar([
Pbind(\degree, Pkey(\melody), \dur, 0.2),
Pbind(\degree, Pkey(\melody), \ctranspose, 24, \dur, 0.2)
]) <> Pbind (\melody, Pshuf([1,2,3,4], inf)) );
// with
(p = Ppar([
Pbind(\degree, Pkey(\melody), \dur, 0.2),
Pbind(\degree, Pkey(\melody), \ctranspose, 24, \dur, 0.2)
]) <> Pbind (\melody, Pstutter(2, Pshuf([1,2,3,4], inf))) );
Only the 2nd Ppar works as intended for same-value sharing. It’s actually possible to avoid manual counting (of parallel streams) like that if using scztt’s PtimeClutch
instead of Pstutter.