# Repeating a random pattern

Hello

I’m sure it’s trivial but I haven’t found out how to repeat a random number of times a random pattern from a list of patterns.

Example : I have two patterns Pseq([1,2]) and Pseq([3,4]) and I want to choose one of them, and repeat it 2 or 4 times.

I’ve tried Pn and Pstutter but neither of them does what I want

``````Pn(
Prand(
[Pseq([1,2]), Pseq([3,4])],
),
Prand([2,4])
).asStream.nextN(10)
-> [ 3, 4, nil, nil, nil, nil, nil, nil, nil, nil ]
``````
``````Pstutter(
Prand([2,4]),
Prand(
[Pseq([1,2]), Pseq([3,4])],
)
).asStream.nextN(10)
-> [ 3, 3, nil, nil, nil, nil, nil, nil, nil, nil ]
``````

Any clue ?

Thanks !

The simplest what comes to my mind is the straight translation of your verbal formulation:

`Pn([Pseq([1,2]), Pseq([3,4])].choose, [2, 4].choose).asStream.nextN(10)`

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 …

Thanks a lot @dkmayer for your fast and simple answer !

I was expecting to repeat that process several times.
Based on your solution, I would do

``````Pn(
Plazy(
{
Pn([Pseq([1,2]), Pseq([3,4])].choose, [2, 4].choose.debug("nb"));
}
), inf).asStream.nextN(20)
``````

which seems to work

``````nb: 4
nb: 2
nb: 4
-> [ 1, 2, 1, 2, 1, 2, 1, 2, 3, 4, 3, 4, 1, 2, 1, 2, 1, 2, 1, 2 ]
``````

but maybe there’s something clever ?

Thanks again !

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:

``````(
y = Pstutter(
Pseq([Prand([1, 2]), Prand([3, 5])], inf),
Pseq([ `Pseq([1, 2]), `Prand([3, 4]) ], inf)
).iter;

Pn(Plazy { y.next.value }).iter.nextN(30);
)
``````

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
``````

save as .sc file in Extensions and recompile

``````PpatStutter : Pstutter {
*new { |n, pattern|
^super.new.n_(n).pattern_(pattern)
}

embedInStream { | event |
var str = Pstutter(n, pattern).iter;
inf.value(event).do { event = str.next.value.embedInStream(event) };
^event;
}
}
``````

Then we can write

``````(
PpatStutter(
Pseq([Prand([1, 2]), Prand([3, 5])], inf),
Pseq([ `Pseq([1, 2]), `Prand([3, 4]) ], inf)
).iter.nextN(30)
)

(
PpatStutter(
Prand([2, 4], inf),
Prand([`Pseq([1, 2]), `Pseq([3, 4])], inf)
).iter.nextN(30)
)``````

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.

``````Pseries(0, 1, 5).asStream.all
-> [ 0, 1, 2, 3, 4 ]

Pseries(0, Pwhite(1, 3, inf), 5).asStream.all
-> [ 0, 3, 5, 6, 8 ]
``````

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).

``````Pseries(Pwhite(0, 7, inf).asStream, 1, 5).asStream.all
-> [ 7, 8, 9, 10, 11 ]
``````

^^ If you supply a stream explicitly, then it does as you expect.

One step further, to show why streams are useful here:

``````Pn(
Pseries(  // <-- return values
Pseries(0, 1, inf).asStream,  // <-- `start` stream
1, 4
),
5
).asStream.all
-> [ 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6, 4, 5, 6, 7 ]
``````

^^ The `start` stream remembers its state between invocations of the “return” pattern. Without the explicit `asStream`, that state is forgotten.

Back to your example: In a single invocation of `Pn`, there can be one and only one number of repeats. So `Prand([2, 4])` needs `.asStream`.

``````Pn(
Prand(
[Pseq([1, 2]), Pseq([3, 4])],
),
Prand([2, 4]).asStream
).asStream.nextN(10)
-> [ 3, 4, 3, 4, nil, nil, nil, nil, nil, nil ]  // did twice, OK
``````

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.

hjh

1 Like

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.

See PSloop from miSC lib. Or else you need to do what it does, i.e. save the values if you want to repeat the same.

.) PSloop: Pattern to derive loops from a given Pattern

1 Like

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!

Here’s my crude version of a “Pfin-style” auto-repeater

``````(
~pbuf = { |pat, n, rreps = 1|
if (n < 1) { nil } { Plazy {
var buf = Array(n), i = -1;
Prout({ |ev|
// recording mode
while { i = i+1; i < n } {
buf = buf.add(ev);
ev = ev.yield;
};
// replay mode
rreps do: {buf do: _.yield};
})
<> Pclutch(pat, Pfunc {i < n});
}}
}
)
``````

Some tests

``````~pbuf.(Pseq([5, 7, 11, 345]), 3).iter.all
// -> [ 5, 7, 11, 5, 7, 11 ]

// 0 == rreps is Pfin basically
~pbuf.(Pseq([5, 7, 11, 345]), 2, 0).iter.all
// -> [ 5, 7 ]

~pbuf.(Pseq([5, 7, 11, 345]), 2, 4).iter.all
// -> [ 5, 7, 5, 7, 5, 7, 5, 7, 5, 7 ]

~pbuf.(Pbind(\degree, (:1..8)), 2).iter.all(())
// -> [ ( 'degree': 1 ), ( 'degree': 2 ), ( 'degree': 1 ), ( 'degree': 2 ) ]

~pbuf.(Pbind(\freq, 100 * Pwhite(1, 9)), 2).iter.all(())
// -> [ ( 'freq': 600 ), ( 'freq': 200 ), ( 'freq': 600 ), ( 'freq': 200 ) ]
``````

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.

4 Likes

Even better, something I can wrap my head around. Cheers!

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);
)
``````
2 Likes

To be honest, I don’t remember exactly what I was going for now, but I tried your example and I like this approach!

1 Like

Hi!

I want to select items from a list and repeat them while the size of the repeated items keep growing, for instance:

``````[4,5,11,10,3,6] // my list of degrees

[3,5,10]
[3,5,10]
[3,5,10,6]
[3,5,10,6]
[3,5,10,6]
[3,5,10,6,4]
[3,5,10,6,4]
[3,5,10,6,4]
[3,5,10,6,4]
``````

They will be read as single notes 3->5->10->3…, not as a chord [3,5,10].

@RFluff answer solves the first part of the problem which is the variable size repeated streams, but I am not able to sequence his `~pbuf` pattern.

I am doing something like:

``````a = Pbind(
\degree, ~pbuf.(Prand([4, 5, 11, 10, 3, 6], inf), 3, 6),
\dur, 0.25,
);

Pseq([
Pset(\degree, ~pbuf.(Pxrand([4, 5, 11, 10, 3, 6], inf), 5, 8), a),
Pset(\degree, ~pbuf.(Pxrand([4, 5, 11, 10, 3, 6], inf), 6, 9), a),
Pset(\degree, ~pbuf.(Pxrand([4, 5, 11, 10, 3, 6], inf), 7, 10), a),
], 1).play;
``````

But it is not working as expected, the number of repetitions is always small as expected. Is this the way to go ?

Is there a way of doing this using a more traditional and simple approach? some sintax like below but with`.iter` and `.asStream` ?

`Pn( Prand([4,5,11,10,3,6],inf), Pn(Pseries(5,1,inf), Pseries(8,1,inf)))`