Pprob random values with arbitrary probability distribution
superclass: Patterns
creates an integral table on instantiation (cpu intensive) which is then used by the streams
to generate random values efficiently.
Pprob(distribution, lo, hi, length, tableSize)
distribution
desired probability distribution (histogram)
lo, hi
lower and upper bounds of the resulting values
length
number of values to repeat
tableSize
resample table to this size. If the size of the distribution is
smaller than 64, it is (linearly) resampled to this minimum size
distribution_(list)
set the distribution, the table is recalculated
tableSize_(n)
set the resample size, the table is recalculated
// a consistency test
(
var a = Pprob([0,0,0,0,1,1,1,1,3,3,6,6,9].scramble);
var b = a.asStream;
b.nextN(800).sort.plot("sorted distribution");
b.nextN(800).sort.plot("sorted distribution, again");
)
// comparison: emulate a linrand
(
var a, b;
a = Pprob([1, 0]);
x = Pfunc({ 1.0.linrand });
b = a.asStream;
y = x.asStream;
postf("Pprob mean: % linrand mean: % \n", b.nextN(800).mean, y.nextN(800).mean);
b.nextN(800).sort.plot("this is Pprob");
y.nextN(800).sort.plot("this is linrand");
)
// compare efficiency
bench { Pprob([0, 1]) } // this is fairly expensive
bench { 16.do { Pseq([0, 1] ! 32) } }
x = Pprob([0, 1]).asStream;
y = Pseq([0, 1], inf).asStream;
bench { 100.do { x.next } }; // this very efficient
bench { 100.do { y.next } };
// sound example
(
SynthDef("help-sinegrain",
{ arg out=0, freq=440, sustain=0.05;
var env;
env = EnvGen.kr(Env.perc(0.01, sustain, 0.2), doneAction:2);
Out.ar(out, SinOsc.ar(freq, 0, env))
}).send(s);
)
(
a = Pprob([0, 0, 1, 0, 1, 1, 0, 0], 60, 80);
t = a.asStream;
Routine({
loop({
Synth("help-sinegrain", [\freq, t.next.midicps]);
0.01.wait;
})
}).play;
)
a.distribution = [0, 1];
a.distribution = [1, 0];
a.distribution = [0, 0, 0, 0, 1, 0];
a.distribution = [0, 1, 0, 0, 0, 0];
// higher resolution results in a more accurate distribution:
a.tableSize = 512;
a.tableSize = 2048;