Pbind with three different layers of Rest() durations

Hello, I am sure there is several way to approach this but that’s really tricky to me. For a museum piece I need to build an automated random sample player that runs infinitely. The thing is that I need to set up three layers of durations (two with Rest() ) to make it interesting ; I am gone try to explain this.
The first layer play a random sample with a random stuttered value that depends of the \dur of the original Pbind, that’s classic. (see the code). BUT when the stuttered seq is done I would like a first Rest(), let’s say between 1.5 and 4 sec, before picking up a new stuttered Seq with another random sample.
So, so far we have two level of \dur, the one that order the repetition of the sample and a Rest() before allowing a new stuttered seq, with a new sample.
But now I would like also to Stutter this previous action (Stuttered seq + Rest) randomly (let’s say between 3 or 6 times) and then Rest() randomly between 2 or 3 minutes ! ( of silence ) before repeating all this again.
Is a Pbind of a Pbind of a Pbind is possible ? I would like to keep the Pbind method if possible, and set up each layer of silence with this form

Pseq([Pwhite(1, 1.5, 1), Pwhite(2, 4, 1).collect(Rest(_))], inf)),

I hope my description of his problem is clear :slight_smile:

Here is the patch, that is just playing the first step


(
~bells = Array.new;

~folder = PathName(" My path");

~folder.entries.do({ | path |

	~bells = ~bells.add(Buffer.read(s, path.fullPath));

});

)


(
SynthDef(\RDM, { | freq |

	var sig = PlayBuf.ar(2, \buf.ir); 

	Out.ar(0, sig);

}).add;
)


(

Pbindef(\ZZZ,
	\instrument, \RDM,
	
	\index, Pstutter(Prand([1, 1, 2, 4], inf), Pxrand( (0..~bells.size-1), inf )),
	
	\dur, Pfunc{|ev| ~bells[ev.index].duration }, 
	\buf, Pfunc{|ev| ~bells[ev.index] }
		
	
).play;


)

Pseq([Pwhite(1.5, 2, 1), Pwhite(4, 5, 1).collect(Rest(_))], inf)

But then I would like another Rest() layer. I would like another Stutter

So there are many ways to do this.
It is possible inside a pattern, although I don’t quite know how, as you can write ‘into’ patterns quite a lot, making them increasing complex. I wouldn’t recommend this. Instead, would this work?

Pdef(\patternA, Pbind(
	\instrument, \RDM,
	\index, Pxrand( (0..~bells.size-1), ~bells.size),
	\dur, Pfunc{|ev| ~bells[ev.index].duration },
	\buf, Pfunc{|ev| ~bells[ev.index] },
	\report, Pfunc{ 'playing patternA'.postln; }
));

Pdef(\patternB, Pbind(
	\instrument, \RDM,
	\index, Pxrand( (0..~bells.size-1), ~bells.size),
	\dur, Pfunc{|ev| ~bells[ev.index].duration } * 0.5,
	\buf, Pfunc{|ev| ~bells[ev.index] },
	\report, Pfunc{ 'playing patternB'.postln; }
));

~p = Pseq([Pdef(\patternA), Pdef(\patternB)], 1).play

Here ~p will play all of patternA, then patternB. Note, the duration of the patterns is determined by the shortest sub pattern, i.e., in this case, \index will only generate ~bells.size number of events, after which, ~p advances to patterB. You could edit patternB to have the rests and sounds in.

The approach above is writing ‘outside’ the pattern, making small simple patterns them composing/sequencing them accordingly. I don’t quite understand what you want; this is mostly because writing ‘into’ patterns gets complex and difficult to understand (let alone communicate in a forum)? - but, would this work for your use case - that is, breaking the types of behaviour into different simple patterns that are then composed as needed?

This means you can then write the piece like this…

given the patterns \A through \G.

//   just making some basic event - each one plays three times
~mk_pat = {|name|
	postf("making pattern %\n", name);
	Pdef(name, Pbind(
		\dur, Pseq([1], 3),
		\report, Pfunc{name.postln}
	))
};

($A.ascii..$G.ascii).do{ |c| ~mk_pat.(c.asAscii.asSymbol) }

… define patterns composing smaller patterns to make each section.

// beginning
~intro = Pseq(Pdef(\G), 2); // Do pattern \G twice

// define main section
~rand_sec = Pwrand([Pdef(\A), Pdef(\B)], [0.2, 0.8], 10);  

~det_sec = Pseq([Pdef(\C), Pdef(\D), Pdef(\E)], 1);


~main = Pseq([~rand_sec, ~det_sec], 5);

// define ending
~outro = Pseq([Pdef(\F), Pdef(\G)], 2);


~peicePlayer = Pseq([~intro, ~main, ~outro], 1).play

Thank you Jordan but it’s not what I had in my mind because I don’t need a succession of a different patterns, it’s not easy to describe, let’s try like this

1/ Stuttered Seq (in this case it picks randomly 4 as the stutter value and 1 sec as \dur)

Random Sample 1 (play for 1 sec) -
Random Sample 1 (play for 1 sec) -
Random Sample 1 (play for 1 sec) -
Random Sample 1 (play for 1 sec)

2 /THEN Random Rest () between 5 or 10 seconds

3/ THEN come back to the previous SEQ but with a new random sample, a new random value of Stutter, new random value of \dur

4/ REDO all of that that 3 or 4 times (each time with new random values)

5/ WHEN IT’S DONE Random Rest() between 3 or 4 minutes !

6/ WHEN SILENCE IS DONE do that again

I know that it typically sound as a Task / Routine job but I would like to keep the Pbind random tools…

I don’t understand what the difference is between what you have described and this…

// 'stutter' sequence
Pdef(\1, Pbind(
	\dur, Pwhite(0.2, 3, 1),
	\buf, Pxrand((0..100), 1),
));

// rest between 5 and 10
Pdef(\2, Pbind(
	\dur, Pwhite(1, 2, 1), // should be between 5 and 10
	\note, Rest(),
));

// do the main bit, n times - between 2 and 4 times
Pdef(\duplicate1, Pdup(Prand((2..5), 1), Pdef(\1)));

//  instructions (1,2,3) with the 3-4 repeats (instrct 4)
~one_through_four = Pseq([Pdef(\duplicate1) , Pdef(\2), Pdef(\duplicate1)], Prand([3, 4], 1));

// 5/ WHEN IT’S DONE Random Rest() between 3 or 4 minutes !
Pdef(\5, Pbind( 
	\dur, Pwhite(3, 4, 1), //* 60, 
	\note, Rest()
));

// 6/ WHEN SILENCE IS DONE do that again
// this is inf many times
~main = Pseq([~one_through_four, Pdef(\5)], inf).trace.play;

Give the patterns proper names though…

Sorry I didn’t see your second post, thanks a lot for this complete answer and for sure it worked ! But in fact I have difficulties to have a good vision of this temporality with thoses Pbind… So I came with that, which is exactly the same thing, but more clear to me as a succession of event :

(

Tdef(\ZZZ).set(\imin, 1, \imax, 47);

Tdef(\ZZZ, { |ev|

	var idx, buf, sustain, shiftdur ;

// ALL TASKS
	
	inf.do {
	
// FIRST TASK ( Stuttered SEQ + Silence )
		
	rrand(4, 7).do {   
			
			idx  = (1..47).choose;	
			
			shiftdur = rrand(1.3, 2.3);
					

// Stuttered SEQ
			
	4.do {  | i |
			
		sustain =  ~bells[idx].duration * shiftdur;
		buf =  ~bells[idx];

		(	instrument: \RDM,

			buf:buf, 			
			sus:sustain,
			
			pitchT: [0, 1].wchoose([0.35, 0.65]),
			pitchV: [0, -1, -2, -3].choose.midiratio,
			
			wowT: [0, 0].wchoose([0.35, 0.65]),
			wowV: [ (0.1..0.7)].choose,
					
			volSynth: 1
			
		).play;
		
		sustain.wait;
	};
	
	    1.wait;

// Silence
	
	1.do {  | i |
	
		idx  = 0;
			
		sustain =  ~bells[idx].duration;
		buf =  ~bells[idx];

		(	instrument: \RDM,

			buf:buf, 			
			sus:sustain,
			
			pitchT: [0, 0].wchoose([0.5, 0.5]),
			pitchV: [0, 1, -1, -2, -3].choose,
			
			wowT: [0, 0].wchoose([0.5, 0.5]),
			wowV: [ (0.1..0.7)].choose,
					
			volSynth: 0
			
		).play;
		
				rrand(5, 15).wait;
	};			
	
		};
		
// END OF FIRST TASK
	
	5.wait;
		
	
// SECOND TASK_LONG SILENCE
	
		1.do {  | i |
	
		idx  = 0;
			
		sustain =  ~bells[idx].duration;
		buf =  ~bells[idx];

		(	instrument: \RDM,

			buf:buf, 			
			sus:sustain,
			
			pitchT: [1, 1].wchoose([0.5, 0.5]),
			pitchV: [0, 1, -1, -2, -3].choose,
			
			wowT: [0, 0].wchoose([0.5, 0.5]),
			wowV: [ (0.1..0.7)].choose,
			
			volSynth: 0
			
		).play;
		
		rrand(160, 240).wait;
	};
	
}}).play;

// RE DO ALL

)

I have two question thought :

  • if I do a 4.do { } and I have an array of value inside [a, b, c, d], what is the more minimal way to say to the first “do” to return only the first value of the array (a) for the second do the second (b) and so on ? ( I tried to create a succession of pitches, like if it was a step sequencer).
  • when I run this task, at some point (sometimes after few minutes, sometimes seconds) it stops with this error message, which is scary as it is supposed to run infinitely ofr an installtioon, any idea of what is the problem ?

Thanks a lot

ERROR: 'PauseStream-next' Out of context return of value: a DoesNotUnderstandError
RECEIVER:
Instance of PauseStream {    (0x11f1bc4d8, gc=E4, fmt=00, flg=00, set=03)
  instance variables [7]
    stream : nil
    originalStream : instance of Routine (0x11f50f498, size=27, set=5)
    clock : instance of TempoClock (0x11bd2e128, size=7, set=3)
    nextBeat : nil
    streamHasEnded : true
    isWaiting : false
    era : Integer 107
}
PATH: /Users/raphaelhenard/Desktop/PLEURAGES & SCINTILLEMENTS/P & S Player XXXX.scd
CALL STACK:
	MethodError:reportError
		arg this = <instance of OutOfContextReturnError>
	Nil:handleError
		arg this = nil
		arg error = <instance of OutOfContextReturnError>
	Thread:handleError
		arg this = <instance of Thread>
		arg error = <instance of OutOfContextReturnError>
	Object:throw
		arg this = <instance of OutOfContextReturnError>
	Object:outOfContextReturn
		arg this = <instance of PauseStream>
		arg method = PauseStream:next
		arg result = <instance of DoesNotUnderstandError>
	PauseStream:next
		arg this = <instance of PauseStream>
		arg inval = 3966.4789115646
		var nextTime = nil
	PauseStream:awake
		arg this = <instance of PauseStream>
		arg beats = 3966.4789115646
		arg seconds = 3967.5412470056
		arg inClock = <instance of TempoClock>
^^ The preceding error dump is for ERROR: 'PauseStream-next' Out of context return of value: a DoesNotUnderstandError
RECEIVER: a PauseStream

Sorry this is the correct and simplified version

(

Tdef(\biGliss).set(\smin, 0.04, \smax, 0.5, );

Tdef(\biGliss, { |envir|

	var idx, sustain, buf, pitchT, pitchV, pitchToggle, stutter, timeshift;


// Stutter + Silence
	4.do {

		idx = (1..47).choose;

		pitchT = [1, 1].wchoose([0.5, 0.5]);

		stutter = [1, 2, 4].wchoose([0.6, 0.2, 0.2]);
		
		timeshift = rrand( 1, 3);
	//	pitchT = if ( stutter > 1, { 0 }, { 1 } );


		stutter.do { |i|


		buf = ~bells[idx];
		sustain = ~bells[idx].duration;


		(	instrument: \RDM,


			buf: buf,

			pitchT: if ( stutter > 1, { 1 }, { 0 } ),
			pitchV: pitchV = [-1, 0, -2, -3].choose.midiratio,

			pitchToggle: pitchToggle,

			sus: sustain * timeshift,
		).play;
		sustain.wait;
	};


		1.wait;


		// Silence




		1.do { |i|


		buf = ~bells[0];
		sustain = ~bells[0].duration;


		(	instrument: \RDM,


			buf: buf,

			sus: sustain,
		).play;
			
			
		3.wait;
	};




		// LongSilence



		1.do { |i|


		buf = ~bells[47];
		sustain = ~bells[47].duration;


		(	instrument: \RDM,


			buf: buf,

			sus: sustain,
		).play;
			
			
		10.wait;
	};





	};

}).play;
)

I still don’t get this " ERROR: ‘PauseStream-next’ Out of context return of value: a DoesNotUnderstandError
RECEIVER:"