Remove an item from a sequence at each repeat

Hi -

I’m branching off of an older thread, since this is a slightly different consideration.

I’d like to have an item removed from “degreeX”, at random, on each repeat. Is this possible?

~degreeX = [0, 9, 11, 15, 19, 12, 10, 2, 3, 4];

Pbindef(\fe,
	\degree, Pn(Plazy(Pseq(~degreeX, 1))),
	\dur, 0.1).play;

Thanks!

I don’t know if this is feasible, but I have the feeling that it sounds strange in the Pbind context.

I find Routine easier to use for implementing these kinds of behavior :

(
Routine({
	var degreeX =  [0, 9, 11, 15, 19, 12, 10, 2, 3, 4];
	
	var currentTime = 0;
	
	loop {
		// Synth(\someSynth, [freq: degreeX[currentTime]);
		
		("I played : " ++ degreeX[currentTime]).postln;
		0.1.wait;
		currentTime = currentTime + 1;
		if(currentTime == degreeX.size) {
			currentTime = 0;
			degreeX.removeAt(degreeX.size.rand);
			("Notes are  now : " ++ degreeX ++ "\n").postln;
		}
	};
}).play;
)

My other guess was to use a Pfunc that removes the random value at each repeat (because I think that it’s the only Pattern that can perform such a thing), but I don’t know how to articulate it so it also yields the correct value for the Pbind to keep playing.

I suppose it should store the last item of the Array in a variable (in case it’s removed), remove a random entry, then return the stored degree so that the note plays and the Pbind keeps running.

Here’s a way to do it inside Plazy. Keep in mind you can put any code you want inside the Plazy function, such as mutating an ~environmentVariable, as long as the return value is a valid pattern.

(
~degreeX = [0, 9, 11, 15, 19, 12, 10, 2, 3, 4];

Pbindef(\fe,
    \degree, Pn(Plazy{
        if (~degreeX.size > 0) { // first make sure ~degreeX is not empty
            var seq = Pseq(~degreeX, 1); // make the Pseq from ~degreeX
            ~degreeX.remove(~degreeX.choose); // remove an item from ~degreeX
            seq; // return the Pseq
        } {nil} // return nil to end the stream if ~degreeX is empty
    }),
	\dur, 0.1
).play;
)
2 Likes

Thanks, @PitchTrebler - this is very close to what I want to do.

Two small follow-up questions, if you have the chance:

  1. If, instead of nil, I simply wanted to restore the array back to being full, simply putting “~degreeX = [0, 9, 11, 15, 19, 12, 10, 2, 3, 4];” in place would play a chord - is there a way to prevent that from happening?

  2. If I wanted to roll this into a kind of Pattern language abstraction - maybe call it something like “Pextract” - what would be the best way to learn about doing that?

Thanks again!

http://doc.sccode.org/Tutorials/A-Practical-Guide/PG_Ref01_Pattern_Internals.html

hjh

2 Likes

It’s playing a chord because you are returning an array from the Plazy. Plazy should return a pattern or pattern-like object (something that responds to the .asStream method). Arrays respond to the .asStream method by returning the full array:

p = [1,2,3].asStream;
p.nextN(3); // -> [ [ 1, 2, 3 ], [ 1, 2, 3 ], [ 1, 2, 3 ] ] (chords)

If you want to sequentialize the array, wrap it in a Pseq, and return that from the Plazy.

(
~degreeX = [0, 9, 11, 15, 19, 12, 10, 2, 3, 4];

Pbindef(\fe,
    \degree, Pn(Plazy{
        var seq;
        if (~degreeX.size < 1) {
            ~degreeX = [0, 9, 11, 15, 19, 12, 10, 2, 3, 4];
        };
        seq = Pseq(~degreeX);
        ~degreeX.remove(~degreeX.choose);
        seq;
    }),
	\dur, 0.1
).play;
)
2 Likes