By the way Pattern / Streams and repetitions is by far no trivial topic. I have encountered a number of examples, where the variant of repetition / embedding can be easily thought and formulated, but is clumsy to express in classical Pattern notation.
This is a hint that even the most flexible syntax (and SC patterns are definitely very flexible) tends to lead to certain solutions and makes others less likely to be used …
Exactly, Plazy is then the tool of choice to embed it.
However, thinking about this, the above solution isn’t very flexible. Suppose you wouldn’t only want to choose (which is easy to write with method ‘choose’), but to generate a sequence of Patterns with Patterns itself and then repeat them, controlled with a sequence, which should maybe also be generated by a Pattern. How to do that ?
You could use Ref objects to force a Pattern to output Patterns, or, in other words, inhibit their normal embedding. This Stream of ref’ed Patterns can then be used in a Plazy:
// last example
(
x = Pstutter(
Prand([2, 4], inf),
Prand([`Pseq([1, 2]), `Pseq([3, 4])], inf)
).iter;
Pn(Plazy { x.next.value }).iter.nextN(20);
)
// check helper stream alone
// x.next
So more refined sequences of this type can be generated:
Insterestingly I don’t remember ever having thought about this kind of using Refs in combination with Patterns, it might open some nice possibilities.
Also it might be worth writing a Pattern for this special type of repetition.
// provisional easy implementation, might need improvements
There’s a catch here – something that is poorly documented.
Let’s take Pseries(start, step, length) as an example: beginning with a number start, and producing length values, repeatedly add step.
A given series of numbers can have only one starting point, and one length.
But, within that series, conceivably the step could change. To support that, you’re allowed to provide a pattern for step. When the Pseries streams out, it automatically converts step into a stream.
So, what if you use a pattern for the starting point?
Pseries(Pwhite(0, 7, inf), 1, 5).asStream.all
-> [ a Pwhite, a Pbinop, a Pbinop, a Pbinop, a Pbinop ]
Every time Pseries streams out, it needs one and only one starting point. So it does not automatically asStream, and you get the results of the math operations on the pattern objects themselves (basically, nonsense).
This does actually all make sense, except that sclang does nothing syntactically to distinguish which arguments are which type. You just have to “know.” That’s definitely a point of confusion when getting started with patterns.
Sorry for the late reply @dkmayer and @jamshark70, your two last solutions are a bit difficult to understand for me ! I’m working on it today and will try to get it ! Thanks again !
Based on the title, I thought this thread might have some solutions for what I’m trying to do - that is, to repeat the events of a randomly generated pattern, rather than just re-evaluating (i.e., calling .next on the stream of) the embedded pattern. I have scoured the documentation and am looking through Stream.sc and Patterns.sc and I have not had any success so far.
I’m doing some timing manipulation of the durations and number of events in the embedded Pattern to change up timing, so I don’t necessarily know how many events I should be embedded ahead of time. I’m using Psync in my pattern to repeat, and since this creates a pattern of finite length, and I thought this could be wrapped in Pn to simply repeat the truncated bars, but this does not appear to be the case. Instead, this just re-evaluates the pattern that yielded the events, rendering the extra plumbing pointless.
The Stream documentation has an example of a FuncStream that resets the random seed in its reset function. I guess that could be part of a solution, but it seems a bit hacky and messy to set up.
Pscratch from ddwPatterns also seems to have some potential, but it seems like the indeterminate number of events could get in the way here and I’m not quite sure how to wire it up. The idea of event memory is what seems particularly useful about this class.
I attempted to implement a version of such a memory only for value streams using Plazy - I had to do the aforementioned reseeding trick (i.e., resetting the repeated sequence), but it did work. However, I haven’t figured out how to do this for event streams. Anyway, here’s the closest thing I have so far:
(
var seed = 413;
var rand2 = Pfin(3, Pwhite(0, 100)).asStream;
rand2.randSeed_(seed);
Pn(Plazy({
var next = rand2.next;
next.postln;
if(next == nil, {
'Out of values, resetting'.postln;
rand2.reset;
rand2.randSeed_(seed);
next = rand2.next;
next.postln;
next;
}, {
next
});
})).asStream.nextN(10)
)
Any suggestions appreciated
Sorry if reviving an old thread is a no-no; it seemed like the best approach.
Excellent! This gets me most of the way there. I still need to figure out how to sync it - it doesn’t seem to play nicely with a finite Psync pattern, but maybe there’s some other way to set up an accumulator or use an event key or the like. Thanks!
As extra/exercise you could further condition the “clutch” so it can resume recording on some flag or some other variations…
If you want to “productize” this for event patterns, you do have worry about what happens with cleanups (see EventStreamCleanup) in those repeats and cut-offs.
Hey, I found this thread because it was exactly what I searched for, but I did not understand anything in this thread.
After I sat with this for a good long while I made a little pattern thingy which gave me what I wanted. Now I’m curious if this does the thing you wanted also?
(
Pdef(0,
Pseed(19, // Change me and reevaluate.
Psync(
Pbind(*[
freq: 40 * Plprand(1, 13),
dur: 1 / Pstutter(Phprand(5, 11), Pwhite(5, 11)),
release: 8,
]), 1, 1.5, // 2nd number in this line is loop length.
)
)
).play(quant:1);
)