GG.scene() @=> GScene @ scene; GG.camera() @=> GCamera @ camera; camera.rotX(-.04); camera.posY(.15); function void controlLoop() { while (true) { Math.random2f(.1, 6)::second => now; spork ~ makeSoundBall(); } } 40::ms => dur attackTime; 10000::ms => dur decayTime; function void makeSoundBall() { SinOsc osc => ADSR env => Pan2 panner => dac; Math.random2f(100,400) => osc.freq; env.set(attackTime, decayTime, 0, 0::ms); env.keyOn(); GSphere ball --> scene; spork ~ moveBall(ball, panner); ball.mat().color(@(Math.randomf(), Math.randomf(), Math.randomf())); env.attackTime() + env.decayTime() => now; env =< dac; ball --< GG.scene(); } // Send balls down the scene in the negative z direction // Shrink them to make them disappear better function void moveBall(GGen ball, Pan2 panner) { Math.random2f(-1,1) => float pan; panner.pan(pan); ball.position(@(3 * pan, -1, 0)); while (true) { // TODO: do I need to kill this thread? GG.dt() / (decayTime / second) => float frac; ball.pos() + frac * @(0,0,-50) => ball.position; ball.scale(ball.sca() * Math.pow(.05, frac)); GG.nextFrame() => now; } } spork ~ controlLoop(); while (true) { GG.nextFrame() => now; }