96 => int bpm; 0::ms => dur none; 240000::ms / (1 * bpm) => dur w; 240000::ms / (2 * bpm) => dur h; 240000::ms / (4 * bpm) => dur q; 240000::ms / (8 * bpm) => dur e; 240000::ms / (16 * bpm) => dur s; class Procedure // or Runnable { fun void run() { // empty } } class FloatProcedure { fun void run(float arg) { // empty } } class FloatFunction { 0.0 => float default; fun float evaluate(float arg) { return default; } } class Uniform extends FloatFunction { float value; fun float evaluate(float arg) { return value; } } class Interpolation extends FloatFunction { 0.0 => float min; 1.0 => float max; } class LinearIn extends Interpolation { fun float evaluate(float arg) { return min + (Std.fabs(max - min) * arg); } } class CircularIn extends Interpolation { fun float evaluate(float arg) { return min + (Std.fabs(max - min) * (1 - Math.sqrt(1.0 - (arg * arg)))); } } class CircularOut extends Interpolation { fun float evaluate(float arg) { return max - (Std.fabs(max - min) * (1 - Math.sqrt(1.0 - (arg * arg)))); } } class Looper { 0::ms => static dur none; fun static void loop(Procedure procedure, dur wait) { loop(procedure, none, wait); } fun static void loop(Procedure procedure, dur offset, dur wait) { offset => now; while (true) { procedure.run(); wait => now; } } fun static void loop(FloatProcedure procedure, dur wait, dur length) { loop(procedure, none, wait, length); } fun static void loop(FloatProcedure procedure, dur offset, dur wait, dur length) { offset => now; dur expired; while (expired <= length) { expired / length => float ratio; procedure.run(ratio); wait => now; wait +=> expired; } } } class Sample extends Procedure { SndBuf buf => dac; { 0.0 => buf.gain; } fun void run() { 0 => buf.pos; 1.0 => buf.gain; 1.0 => buf.rate; } } class Kick extends Sample { { "samples/kick_opn_50.wav" => buf.read; } } class Snare extends Sample { { "samples/snr_ord_r42.wav" => buf.read; } } class Bass extends FloatProcedure { Wurley wurley => dac; Interpolation interpolate; fun void run(float arg) { interpolate.evaluate(arg) => wurley.freq; wurley.noteOn(1.0); } } Looper looper; Kick kick; Snare snare; Bass bass0; CircularIn circularIn; 58.27 => circularIn.min; 87.31 => circularIn.max; circularIn @=> bass0.interpolate; Bass bass1; CircularOut circularOut; 58.27 => circularOut.min; 87.31 => circularOut.max; circularOut @=> bass1.interpolate; Bass bass2; LinearIn linearIn; 43.65 => linearIn.min; 65.41 => linearIn.max; linearIn @=> bass2.interpolate; spork ~ looper.loop(kick, none, h); spork ~ looper.loop(kick, 7 * e, w); spork ~ looper.loop(kick, 13 * e, 4 * w); spork ~ looper.loop(snare, q, h); spork ~ looper.loop(bass0, 2 * w, s, 2 * w); spork ~ looper.loop(bass1, 4 * w, s, 2 * w); spork ~ looper.loop(bass2, 2 * w, e, 4 * w); 7 * w => now;