input.cutoff = 1.0;
input.filterDecay = 0.5;
input.attack = 0.0;
input.decay = 0.5;
input.sustain = 0.8;
input.release = 0.5;
function softclip(x) {
return x < -1 ? -1 : x > 1 ? 1 : 1.5*(1 - x*x/3)*x;
}
function varsaw(p, formant) {
let x = p%1;
return (x - 0.5) * softclip(formant*x*(1-x));
}
const sawPluck = synth.def(
(phase, env, tick, options) =>
varsaw(phase, options.cutoff / midi_to_hz(options.note) * Math.exp(-options.decaySpeed*tick)) * env.value,
{
env:adsr,
duration:0.5,
cutoff:() => 200 * 100**input.cutoff,
decaySpeed:() => 1 * 100**(1-input.filterDecay),
attack:() => 0.01 * 1000**input.attack,
decay:() => 0.01 * 1000**input.decay,
sustain:() => input.sustain,
release:() => 0.01 * 1000**input.release,
}
);
ditty.bpm = 120;
const nn = [g2,c2,d2,bb1];
loop( (i) => {
sawPluck.play(nn.ring(Math.floor(i/8)));
sleep(0.5);
});