// https://www.youtube.com/watch?v=lQ6jZgMaZk4
//
// the boing is roughly a sawtooth with a root frequency of 96Hz, through a band-pass filter
// the center frequency of the filter sits at 1.2kHz for 90ms, then within 90ms sweeps to 2.9kHz were it stays until the end of the sound
const poingOsc = synth.def(class {
constructor(opt) {
this.p = 0;
// crude state variable filter, 12dB per octave
this.flt = {lp: 0, bp: 0, hp: 0};
this.t = 0;
this.svf = (s, inpt, kf, kq) => {
var lp, hp, bp;
lp = s.lp + kf * s.bp;
hp = inpt - lp - kq * s.bp;
bp = s.bp + kf * hp;
s.lp = lp;
s.hp = hp;
s.bp = bp;
};
}
process(note, env, tick, opt) {
// create a sawtooth mixed with a slight square timbre, at a fixed frequency
var v = (this.p % 1 + (this.p % 1 < .33 ? .1 : -.1) - .5) * env.value;
this.p += 96 * ditty.dt;
// add a white noise burst at the beginning
v += (Math.random() - .5) * Math.exp(-this.t * 60) * .3;
// feed it through the bandpass filter and sweep the filter's cutoff frequency
this.svf(this.flt, v, lerp(.169, .41, clamp01((this.t - .09) / .09) ** 2), .08);
this.t += ditty.dt;
// mix the filter output and saturate it sligthly
return Math.sin((this.flt.bp + this.flt.lp * .5 + this.flt.hp * .1) * 4 * env.value);
}
}, {attack: 0, decay: .8, sustain: .2, release: 0.01, duration: .372});
loop( () => {
poingOsc.play(c5);
sleep(1);
}, { name: 'my first loop' });