// name: popcorn.ck // desc: a quick popcorn simulation, using: // 1) poisson process // 2) sonification // uniform fun float uniform() { return Std.rand2f(0,1); } // time until next event, given rate // (this is based on the exponential distribution, which models // time until next event in a poisson process - the events in // this model occur independently, and have a rate of lambda) fun float timeUntilNext( float lambda ) { return -Math.log(1-uniform()) / lambda; } // patch SndBuf i => Pan2 pan => dac; // alternate patch using impulse and LPF // Impulse i => LPF f => Pan2 pan => dac; // read in "gunshot.wav" => i.read; // "pen-click.wav" => i.read; // initial gain 0 => i.gain; // number of expected events per second 1 => float N; // counter 0 => int counter; // the attack/release edge duration 20::second => dur E; // how long 2*E => dur T; // stop time now + T => time later; // spork a control shred spork ~ control( E, E ); // control fun void control( dur attack, dur release ) { // attack (increasing events per second) now + attack => time later; while( now < later ) { .1 +=> N; 100::ms => now; } // release (decreasing events per second) now + release => later; while( now < later ) { -.1 +=> N; 100::ms => now; } } // one pop! fun void pop() { // fire (impulse) // 10 => i.next; // fire (sndbuf) 0 => i.pos; // randomize gain Std.rand2f(.5,1) => i.gain; // randomize rate Std.rand2f(.5,1.5) => i.rate; // randomize the pan Std.rand2f(-.5, .5 ) => pan.pan; } // poisson process while( now < later ) { // pop! pop(); // count counter++; // print <<< "pop! N:", N >>>; // wait timeUntilNext(N)::second => now; } // summary (not meaningful as is since we vary N over time) // <<< "expected:", T/second * N, "actual:", counter >>>;