Randomise Rest() duration!

Hi folks,

I don’t get how can I randomise the Rest() lenght in order to have random durations of silence between thoses chords:

(
~l1 = Pbindef(

	\LLL,

	\type, \midi,

	\midicmd, \noteOn,

	\midiout, ~midiout,

	\chan, 0,

	\midinote, Pseq([[60, 57, 64, 67], Rest(),  [66, 62, 69, 59], Rest()], inf),    /// the duration of the silence between thoses chords is what I want to randomise 

	\ctranspose, 0,

	\dur, Pseq([ 2, Rest(Pwhite(0.5, 2.4)) ],  inf),   /// doesn't work

	\amp, 1,

	\sustain, Pkey(\dur)  * 1

).play

)

Thanks a lot,

For now, Pwhite(0.5, 2.4).collect(Rest(_)).

There’s a long thread about this, I think on github but I forget exactly where. I proposed a way to make Rest work in the way that you’re expecting, but that would break the ideal of statelessness for patterns, so then it was suggested to add a method to convert a pattern’s output to rests, e.g., pattern.rest – which, two issues, 1/ then rest(pattern) would work, but not Rest(pattern) and that would confuse people, and 2/ it can’t be a simple filter pattern because normally you wouldn’t embed a long stream of rests.

So it turns out not to be a simple issue to design.

hjh

I got it, great, thanks James.

Correction : I got it on the principle but unfortunatly it doesn’t work, as you can see with this simple example (the silence should be super short)


(
SynthDef(\SINE, { | freq = 440, sustain = 1 |
	
	
	var sig = SinOsc.ar(freq);
	
	var env = EnvGen.kr(Env([0, 1, 1, 0], [0.05, sustain, 0.05], \lin), doneAction:2);
	
	Out.ar(0, sig * env * 0.1 !2);
	
	
}).add;
)


(
	Pbind(
	
	\instrument, \SINE,

	\freq, Pseq([[60, 57, 64, 67], Rest(),  [66, 62, 69, 59], Rest()], inf).midicps,

	\dur, Pseq([Pwhite(2, 3), Pwhite(0.05, 0.02).collect(Rest(_))], inf),

	\sustain, Pkey(\dur)  * 1,
).play;
)

Ok got it both Pwhite should have a single numer of repetition

\dur, Pseq([Pwhite(2, 3, 1), Pwhite(0.05, 0.02, 1).collect(Rest(_))], inf),

As an alternative you can use the legato key:

(
x =	Pbind(
	
	\instrument, \SINE,

	\freq, Pseq([[60, 57, 64, 67], [66, 62, 69, 59]], inf).midicps,

	\dur, Pwhite(2.0, 3.0),
	
	\legato, Pwhite(0.7, 0.95),

).play;
)

x.stop;

or if you need the rests (e.g. to calculate other values not being sent to the server):

(
x =	Pbind(
	
	\instrument, \SINE,

	\freq, Pseq([[60, 57, 64, 67], \rest, [66, 62, 69, 59], \rest], inf).midicps,

	\dur, Pseq([Pwhite(2.0, 3.0, 1), Pwhite(0.05, 0.1, 1)], inf),

).play;
)

x.stop

I’ve found the most elegant solution to be Pwhite(0.1,1.0) * Rest()

3 Likes

That’s exactly the problem I hinted at: “it can’t be a simple filter pattern because normally you wouldn’t embed a long stream of rests.”

I did make a proposal at one point where Rest would automatically make a stream for its argument, and then, when it’s embedded in an output stream, it would dole out one value and return control back to the parent stream. This would have done what you expected in your initial example. That’s problematic in this case though:

// note: this isn't supported in SC currently!
// if you try to run it, you won't get a sensible result.
// this is just to illustrate a scenario where
// a seemingly intuitive Rest behavior becomes un-intuitive

p = Pseq([Pn(1, 3), Rest(Pseries(0, 0.25, inf))], inf);

q = p.asStream;
r = p.asStream;

Here, you would expect the q and r streams to be completely independent – but if Rest “auto-streamifies” internally, then there’s one Rest object = one stream, shared between the two parent streams.

There’s no good solution to this… which is why we never put in that behavior.

hjh