// by srtuss 2026-3-03
ditty.bpm = 143;
let max=Math.max, min=Math.min,abs=Math.abs,random=Math.random,sin=Math.sin,exp=Math.exp,tanh=Math.tanh,PI=Math.PI,pow=Math.pow,TAU=2*PI;
let flo = v => ~~v;
let tri = p => abs(p % 1 - .5) * 4 - 1;
let shift = (a,n) => {for(let i = 0; i < n; ++i) a.unshift(a.pop()); return a}
const pblep = (t,dt)=>{if(t<dt){t/= dt;return t+t-t*t-1;} else if (t>1-dt){t=(t-1)/dt; return t*t+t+t+1; } return 0; }
//const bd = synth.def((phase, env) => sin((abs(phase % 1 - .5) * 4 - 1)*1.7) * env.value);
const triangle = synth.def((phase, env) => tri(phase) * env.value);
const saw = synth.def((phase, env) => (phase%1-.5) * env.value);
const hat = synth.def((p,e,t,o)=>o.fba.process(random()-.5)*e.value, { attack: .0001, release: .04, duration:.25 });
const hat2 = synth.def((p,e,t,o)=>o.fba.process(random()-.5)*e.value, { attack: .0001, release: .04, duration:0 });
const natural = (v) => 20 * (2 ** (clamp01(v)*9.9657));
const ll = (a, b, v) => exp(lerp(Math.log(a), Math.log(b), v));
class Delayline { constructor(n) { this.n = n; this.p = 0; this.data = new Float32Array(n); } get end() { return this.data[this.p]; } tap(offset) { var x = this.p + offset; x = ~~x; x %= this.n; return this.data[x]; } sample(offset) { if(offset < 0) offset = 0; var p = offset; var pi = ~~p; return lerp(this.tap(pi), this.tap(pi+1), p-pi); } clock(input) { var end = this.data[this.p]; this.data[this.p] = input; if(++this.p >= this.n) { this.p = 0; } return end; } }
const echo = filter.def(class {constructor(opt) {this.lastOut = [0, 0];var division = opt.division || 3/4;var pan = clamp01((opt.pan || 0)*.5+.5);var sidetime = (opt.sidetime || 0) / ditty.dt;var time = 60 * division / ditty.bpm;this.fb = clamp(opt.feedback || 0, -1, 1);this.kl = 1-pan;this.kr = pan;this.wet = opt.wet || .5;this.stereo = isFinite(opt.stereo) ? opt.stereo : 1;var n = ~~(time / ditty.dt);this.delay = [new Delayline(n), new Delayline(n)];this.dside = new Delayline(~~sidetime);}process(inv, opt) {this.dside.clock(inv[0]);var l = this.dside.end * this.kl;var r = inv[1] * this.kr;var nextl = l + this.delay[1].end * this.fb;var nextr = r + this.delay[0].end * this.fb;this.lastOut[0] = inv[0] + this.delay[0].end * this.wet;this.lastOut[1] = inv[1] + this.delay[1].end * this.wet;this.delay[0].clock(nextl);this.delay[1].clock(nextr);if(this.stereo != 1) {var m = (this.lastOut[0] + this.lastOut[1])*.5; var s = (this.lastOut[0] - this.lastOut[1])*.5;s *= this.stereo;this.lastOut[0] = m+s;this.lastOut[1] = m-s;}return this.lastOut;}}, {sidetime: .01, division: 3/3, pan: .5, wet: .3, feedback: .5, stereo: 1.5});
function sleeps(v) {
let h = (ditty.tick*2)%1;
let sf = .02;
sleep(v + (h < 0.5 ? sf : -sf));
}
//input.lowcut = 0;
//input.ring = 0; // min=0,max=24,step=.1
//input.wtf = 0;
//let param = input; // override of "input"
param = {lowcut:0, ring:0, wtf:0 } //structuredClone(param);
param.wtf = 1;
param.ring = 21.6;
param.bdmix = (t,o) => (t % 32) < 30 && !(t % 512 >= 128 && t % 512 < 160)
param.pmix = (t,o) => t % 256 >= 128;
param.tomix = (t,o) => t >= 64;
param.cpmix = (t,o) => t % 256 >= 32;
param.ohmix = (t,o) => t % 256 >= 64;
function autom() {
let t = ditty.tick;
let cy = t % 64;
param.ring = lerp(20, 5, (t*.5) % 1);//sin(t * PI * 4) * .5 + .5;
param.wtf = clamp01((t%128) - 119);
param.lowcut =
//sin(t * PI * 4) * .5 + .5;
clamp01(cy - 55);
param.bdmix = t < 10;
//debug.probe('r', param.ring, 1);
}
let scf = filter.def(class {
constructor() {
}
process(inlr, opt) {
let t = ditty.tick % 1;
let v = min(t * 2, 1) + exp(t * -200);
v = v * .9 + .1;
//debug.probe('a', v, 1, 4);
return [inlr[0]*v, inlr[1]*v];
}
});
let master = filter.def(class {
constructor() {
this.fl = new SVF();
this.fr = new SVF();
this.rp0 = 0;
this.rp1 = 0;
}
process(inlr, opt) {
autom();
this.fl.sf(ll(20, 800, param.lowcut), 2);
this.fr.sf(ll(20, 800, param.lowcut), 2);
let l = inlr[0]*1.2;
let r = inlr[1]*1.2;
l = this.fl.process(l).hp;
r = this.fr.process(r).hp;
if(param.wtf > .5) {
l += l * sin(this.rp0) * .5;
r += r * sin(this.rp1) * .5;
this.rp0 += PI*midi_to_hz(f5+param.ring)*ditty.dt;
this.rp1 += PI*midi_to_hz(f5+param.ring+1)*ditty.dt;
}
let s = [(tanh(l)+l*.2)*2,(tanh(r)+r*.2)*2];
return s;//this.tt.process();
}
}).createShared();
const anim = synth.def(class {
constructor(options) {
this.r = 0;
}
process() {
let px = '─█';
let w = 59, h = 5;
this.r += ditty.dt * 60;
if(this.r >= 1) {
let fo = (sin(ditty.tick * .1) + 1) * 4;
function re(x, y) {
y *= 4;
let l = Math.sqrt(x * x + y * y);
let a = Math.atan2(y, x)
return Math.sin(40/l + PI*ditty.tick + a * fo) > 0;
}
this.r = 0;
for(let y = 0; y < h; ++y) {
let li = [];
for(let x = 0; x < w; ++x) {
li.push(px[1&re(x-w*.5, y-h*.5)]);
}
debug.log(y, li.join(''));
}
}
return 0;
}
});
const syc = synth.def(class {
constructor(o) {
this.p = 0;
this.bob = new Bob(o.syp.r);
this.en = 0;
this.of = new SVF().sf(150, 1);
}
process(n,e,t,o) {
let syp = o.syp;
let p = this.p % 1;
syp.n += (syp.nn - syp.n) * .001;
let dp = ditty.dt * midi_to_hz(syp.n);
let v = p*2 - pblep(p, dp) - 1;
let pw = .48;
v = (p < pw ? 1 : - 1) + pblep(p, dp) - pblep((p - pw + 1) % 1, dp);
this.p += dp;
this.bob.sf(ditty.dt * natural(.2 + sin(t*.1+syp.a) * .1 + .4 * Math.exp(syp.t * -4.)));
syp.t += ditty.dt;
if(syp.g) {
if(this.en < 1)
this.en = min(this.en + ditty.dt * 5000, 1);
}
else {
this.en *= .995;
}
v = this.of.process(v*.8).hp;
let s = this.bob.process(v)* this.en;
return clamp(s*10, -1, 1) * .1;
}
});
const bd = synth.def((p, e, t, o) => bdf.sf(.005+.4*exp(-t*20)).process(tri(p)) * e.value);
loop( () => {
bd.play((t,_)=>f1+30*2**(t*-30)+10*(t<.55?0:2**-max((t-.55)*10,0)), { attack: 0.00015, release: 0.2, duration: 0.7 });
sleep(1);
}, { name: 'a', amp:(t,o)=>.4*param.bdmix(t,o) }).connect(master);
let xxx = synth.def((p,e,t,o) => o.f.length ? (o.f.pop()(),0) : 0);
let poke = (f) => xxx.play(1,{f:[f]});
let gen = (n, f) => { let r = []; for(let i = 0; i < n; ++i) r.push(f(i)); return r};
let syp = {n:a1, nn:a1, t:0, g:0, a:0, r:.8};
loop( lc => {
if(!lc) {
syc.play(a1, { attack: 0, release: 0, duration: 1e38, syp:syp });
anim.play(a1, { duration: 1e38 });
}
let mels = [
[12, 0, 17, 25, 12, 24],
[0, 0, 15, 0, 12, 24],
[0, 0, 13, 0, 12, 24],
[0, 13, 7, 12, 12, 24],
[0, 12, 7, 12+7, 12, 40-9]
];
let l = [5, 8, 16].choose();
let mel = mels.choose();
let acid_n = gen(l, i=>mel.choose());
let acid_s = gen(l, i=>[0, 0, 1].choose());
for(let j = 0; j < 8; ++j) {
for(let i = 0; i < acid_n.length; ++i) {
let sl = acid_s[i];
let nsl = acid_s[(i+1)%acid_n.length];
poke(()=>{
syp.nn = f1+acid_n[i];
if(!sl) {
syp.n = syp.nn;
syp.t = 0;
}
syp.g = 1;
});
sleep(.15);
poke(()=>{
if(!nsl)
syp.g = 0;
});
sleep(1/4-.15);
};
}
}, { name: 'c', amp:param.tomix }).connect(echo.create({mix:.1})).connect(scf.create()).connect(master);
let syp2 = {n:a1, nn:a1, t:0, g:0, a:10, r:.2};
loop( lc => {
if(!lc) syc.play(a1, { attack: 0, release: 0, duration: 1e38, syp:syp2 });
let mels = [
[0, 12, 24],
];
let l = [8, 4, 5].choose();
let mel = mels.choose();
let acid_n = gen(l, i=>mel.choose());
let acid_s = gen(l, i=>[0, 0, 1].choose());
for(let j = 0; j < 8; ++j) {
for(let i = 0; i < acid_n.length; ++i) {
let sl = acid_s[i];
let nsl = acid_s[(i+1)%acid_n.length];
poke(()=>{
syp2.nn = f0+acid_n[i];
if(!sl) {
syp2.n = syp2.nn;
syp2.t = 0;
}
syp2.g = 1;
});
sleep(.15);
poke(()=>{
if(!nsl)
syp2.g = 0;
});
sleep(1/4-.15);
};
}
}, { name: 'i' }).connect(echo.create({mix:.1})).connect(scf.create()).connect(master);
let rhy2 = rhy(10, 16);
loop( () => {
let rhy1 = shift(rhy([4].choose(), 16), 2);
for(let i = 0; i < 4; ++i) {
rhy1.forEach(v => {
if(v)
hat.play(c4, {fba: new MR()});
sleep(1/4);
})
}
}, { name: 'd', amp: (t,o)=>param.ohmix(t,o)*.1 }).connect(scf.create()).connect(master);
loop( () => {
let rhy1 = shift(rhy([13, 11, 3, 15].choose(), 16), 2);
for(let i = 0; i < 4; ++i) {
rhy1.forEach(v => {
if(v) {
hat2.play(c4, {fba: new MR()});
}
sleeps(1/4);
})
}
}, { name: '░', amp: .1 }).connect(scf.create()).connect(master);
function tanhXdX(x) {
var a = x*x;
return ((a + 105)*a + 945) / ((15*a + 420)*a + 945);
}
class Bob {
constructor(q=.9, f=.01) {
this.zi = 0;
this.s = [0, 0, 0, 0];
this.sf(f);
this.sq(q);
}
sf(cutoff) {
this.f = Math.tan(Math.PI * cutoff);
return this;
}
sq(resonance) {
this.r = (40.0/9.0) * resonance;
return this;
}
process(v0) {
var s = this.s;
var f = this.f;
var r = this.r;
var ih = 0.5 * (v0 + this.zi);
this.zi = v0;
var t0 = tanhXdX(ih - r * s[3]);
var t1 = tanhXdX(s[0]);
var t2 = tanhXdX(s[1]);
var t3 = tanhXdX(s[2]);
var t4 = tanhXdX(s[3]);
var g0 = 1 / (1 + f*t1), g1 = 1 / (1 + f*t2);
var g2 = 1 / (1 + f*t3), g3 = 1 / (1 + f*t4);
var f3 = f*t3*g3;
var f2 = f*t2*g2*f3;
var f1 = f*t1*g1*f2;
var f0 = f*t0*g0*f1;
var y3 = (g3*s[3] + f3*g2*s[2] + f2*g1*s[1] + f1*g0*s[0] + f0*v0) / (1 + r*f0);
var xx = t0*(v0 - r*y3);
var y0 = t1*g0*(s[0] + f*xx);
var y1 = t2*g1*(s[1] + f*y0);
var y2 = t3*g2*(s[2] + f*y1);
s[0] += 2*f * (xx - y0);
s[1] += 2*f * (y0 - y1);
s[2] += 2*f * (y1 - y2);
s[3] += 2*f * (y2 - t4*y3);
return y3;
}
}
function rhy(k, n) {
let nx = k, ny = n-k, x = [1], y = [0];
while(nx && ny > 1) {
if(nx < ny) {
x = x.concat(y);
ny -= nx;
}
else {
let t = nx - ny;
nx = ny;
ny = t;
let k = x.concat(y);
y = x;
x = k;
}
}
return Array(nx).fill(x).flat().concat(Array(ny).fill(y).flat());
}
class SVF {
constructor()
{
this.lp=this.bp=this.hp=this.ic1eq=this.ic2eq=0;
}
sf(fc, q) {
fc = clamp(fc * ditty.dt, 0, .499);
let g = Math.tan(PI * fc);
this.k = 1 / q;
this.a1 = 1 / (1 + g * (g + this.k));
this.a2 = g * this.a1;
this.a3 = g * this.a2;
return this;
}
process(v0)
{
let s = this;
let v1, v2, v3;
v3 = v0 - s.ic2eq;
v1 = s.a1 * s.ic1eq + s.a2 * v3;
v2 = s.ic2eq + s.a2 * s.ic1eq + s.a3 * v3;
s.ic1eq = 2 * v1 - s.ic1eq;
s.ic2eq = 2 * v2 - s.ic2eq;
s.lp = v2;
s.bp = v1;
s.hp = v0 - s.k * v1 - v2;
return s;
}
cp() {
let r = new SVF();
r.k = this.k; r.a1 = this.a1; r.a2 = this.a2; r.a3 = this.a3;
return r;
}
}
class MR {
constructor(seed=11941, na=1) {
this.f = [];
this.t = 0;
this.na = na;
for(let i = 0; i < 64; ++i) {
let ff = ll(500, 13000, (((sin(i)+1)*seed)%1));
let f = new SVF().sf(ff, 10);
this.f.push([f, f.cp(), f.cp(), 60000 / ff]);
}
}
process(v) {
let o = 0;
let pulse = exp(-this.t);
this.f.forEach(f => o += f[2].process(f[1].process(f[0].process(pulse*.6 + this.na*Math.random()).bp).bp).bp * exp(-this.t * f[3]));
this.t += ditty.dt;
return o * .004;
}
}
const bdf = new Bob(.05);
let piano = synth.def(
class {
constructor(o) {
this.f = [];
for(let i = 0; i < 80; ++i) {
let ff = midi_to_hz(-4-12+o.cho[i%o.cho.length]+random()*.1);
ff *= (1+(i*135)%22);
let f = new SVF().sf(ff, 80);
this.f.push({f:[f, f.cp(), f.cp()], a:.01/ff, d:2400 / ff, p:2*random()-1});
}
}
process(n,e,t,o) {
let u = 0, v = 0;
let pu = exp(t * -20) * 2;
let no = Math.random()*.2;
this.f.forEach(f => {
let k = f.f[2].process(f.f[1].process(f.f[0].process(pu+no).bp).bp).bp * exp(-t * f.d) * f.a;
v += k*f.p;
u += k*(1-f.p);
});
return [u*e.value,v*e.value];
}
});
loop((lc) => {
let rhy1 = shift(rhy([9, 6, 7, 5].choose(), 16), 2);
let cho = [
[a4, a5, c5, e5, g5],
[a4, a5, c5, d5, fs5]
];
for(let i = 0; i < 4; ++i) {
rhy1.forEach(v => {
if(v)
piano.play(c4, {cho:cho[lc%2]});
sleeps(1/4);
})
}
}, {name:'▒', amp:(o,t)=>param.pmix(o,t)}).connect(echo.create({wet:.9})).connect(scf.create()).connect(master);
let clp = synth.def((p,e,t,o)=>(o.f.process(min(abs(t-.01)*100,1) * random()-.5)).bp*e.value, {release:.1});
loop(() => {
let rhy1 = shift(rhy([2, 6].choose(), 16), 4);
for(let i = 0; i < 4; ++i) {
rhy1.forEach(v => {
if(v)
clp.play(c4, {f:new SVF().sf(3000, 1.5)});
sleeps(1/4);
})
}
}, {name:'▓', amp:param.cpmix})
.connect(echo.create({wet:.2}))
.connect(scf.create())
.connect(master);