Pxrand repeating elements in a row

I’m running into something very strange in the context of a larger script that means that I either misunderstand what Pxrand does, or there’s a bug or something …?

I’m testing the most basic Pxrand script and outputting to the post window:

var g = Pxrand.new([1,2,3,4,5,6,7,8,9,10], inf);
g.asStream.next

When I run this I can see that numbers from the list are repeated multiple times in a row, quite frequently. My understanding is that Pxrand is meant to avoid this exact behaviour so that that same item is never repeated consecutively.

Here’s what I’m seeing in the console:

-> a Pxrand
-> 9
-> 4
-> 1
-> 2
-> 4
-> 9
-> 3
-> 1
-> 5
-> 9
-> 5
-> 10
-> 2
-> 3
-> 9
-> 9
-> 5
-> 3
-> 3
-> 4
-> 8
-> 5

You can see that there’s a double 9 and a double 3 in there, sometimes it repeats even more often.

Am I misunderstanding something? Or is something else going on?

Thanks for any help!

Welcome to the forum @emenel!

There is no bug here. You can think of a pattern as a blueprint for a machine, and a stream as the actual constructed machine. Every time you run g.asStream, you are creating a new stream from that blueprint, independent of any other stream created from the same pattern object. For example, consider the same code using Pseq instead of Pxrand:

g = Pseq.new([0, 1, 2], inf)
g.asStream.next

If you evaluate this multiple times, you’ll only ever see 0, because you are just asking for the first value of a new stream each time.

What you want instead is:

h = g.asStream;
h.next; // this you can evaluate repeatedly to get the results you want

you can also use g.asStream.nextN(n) to get the first n values from the stream.

Hope this helps.

1 Like

Thank you! Yes, this clears it up and helps me better understand how streams work.

1 Like

Hi and welcome !

you are not posting the whole code but I assume generating new Streams from a Pxrand Pattern in each loop is causing the repetitions. This is touching the crucial difference between Patterns and Streams (see James Harkins’ Pattern Guide for this and other Pattern subtleties)

// failing
(
g = Pxrand.new([1,2,3,4,5,6,7,8,9,10], inf);
100.do { g.asStream.next.postln };
)

(
100.do { 
	g = Pxrand.new([1,2,3,4,5,6,7,8,9,10], inf);
	g.asStream.next.postln 
};
)

// correct
(
g = Pxrand.new([1,2,3,4,5,6,7,8,9,10], inf).asStream;
100.do { g.next.postln };
)
1 Like

Yep, that’s precisely the issue I was running into… I don’t think I fully grokked the relationship between the Pattern and the Stream, and was thinking of the stream as a direct reference to the pattern, but just returning values in a different way. I didn’t full get that each stream is independent and only references the the pattern as a source.

I think I understand it better now! Thanks for your quick help.

1 Like

Interesting… But I couldn’t figure out how to apply this in my use case:

(
~list = [
	Pbind(\degree, Pseq([5, 4, 3, 7, 8]), \dur, 0.2),
	Pbind(\degree, Pseq([13, 14, 15, 16]), \dur, 0.2),
	Pbind(\degree, Pseq([13, 14, 15, 16] * 2), \dur, 0.2)
];

~xRand = Pxrand(~list, 1).asStream;

Pdef(\main,
	Pseq([
		~xRand.next.postln,
		Rest({ 1.rrand(1.5) })
	], inf)
);
)

What am I missing here?

Hi !

Indeed, especially the starting point of your version makes it a tricky one, at least I burned some calories while thinking about it :slight_smile:

The problem here is that streamification – because of the embedding of the Pbinds into the Pxrand – nullifies the phrasing that you define and (probably) want to preserve. You can avoid that by regarding the index sequence instead, then you could write it like this:

(
~list = [
	Pbind(\degree, Pseq([5, 4, 3, 7, 8]), \dur, 0.2),
	Pbind(\degree, Pseq([13, 14, 15, 16]), \dur, 0.2),
	Pbind(\degree, Pseq([13, 14, 15, 16] * 2), \dur, 0.2)
];

~xRand = Pxrand((0..2), inf).asStream;

Pdef(\main,
	Pseq([
		Plazy { ~list[~xRand.next] },
		Rest({ 1.rrand(1.5) })
	], inf)
).trace.play;
)

With the index approach, certainly more variants, e.g., with Pswitch etc. become possible.

There is another option that might look strange at first: you can avoid embedding by wrapping the Pbinds into Ref objects (arrays also work).

(
~list = [
	`Pbind(\degree, Pseq([5, 4, 3, 7, 8]), \dur, 0.2),
	`Pbind(\degree, Pseq([13, 14, 15, 16]), \dur, 0.2),
	`Pbind(\degree, Pseq([13, 14, 15, 16] * 2), \dur, 0.2)
];

~xRand = Pxrand(~list, inf).asStream;

Pdef(\main,
	Pseq([
		Plazy { ~xRand.next.() }, // ~xRand.next.value
		Rest({ 1.rrand(1.5) })
	], inf)
).trace.play;
)

(
~list = [
	[Pbind(\degree, Pseq([5, 4, 3, 7, 8]), \dur, 0.2)],
	[Pbind(\degree, Pseq([13, 14, 15, 16]), \dur, 0.2)],
	[Pbind(\degree, Pseq([13, 14, 15, 16] * 2), \dur, 0.2)]
];

~xRand = Pxrand(~list, inf).asStream;

Pdef(\main,
	Pseq([
		Plazy { ~xRand.next[0] },
		Rest({ 1.rrand(1.5) })
	], inf)
).trace.play;
)


2 Likes

Thank you for your answers, they all made things much clearer now.

Very nice - so I’m glad that I contributed to your daily workout :wink: