synth.def(
class {
process() {
// instrument
function vox(mx, rt, t) {
let y = 0.,
p = mx * [fmod(t, 4.) > 3. ? 10.97 : 8.26, fmod(2. * t, 4.) > 2. ? 9.28 : 12.25, 10.85, 12.25].ring(.5 * t),
an = 0.,
en = fract(t),
em = [550, 739, 550, 550, 739, 550, 550, 418].ring(.5 * t),
v = pow(3.07406, [.377, .41, .377, .355].ring(.25 * t) * log(12.5 + fract(t)));
an = exp(3. * en * exp(log2(1. - en) / (sin(.3 * rt) * .65 + .65) * .1));
y = v * em * p + an;
y = exp(-.5 * fract(t)) * sin(8. * y) * ((cos(.05 * rt) * .25 + .25) + cos((trunc(.5 * t) % 6 > 5 ? 8 : 4) * y));
y *= env_ad(en, .7, .95)
y = y + tanh(softkn(25 * y, (2 + fract(.1 * rt))) * .51);
return y;
}
this.phase += 1;
let time = this.phase / 44100;
// print msg to the gui
debug.log('',['|', '/ ', '-\t', ' \\'].ring(5. * time) + "Prepare yourself" + "\nfor something good that happens\nany second now.");
// initialization
let dtm = fmod(time,16), tm = time; // + .001*sin(time);
let o = [0.0];
let sn = 0, sl = 0;
let l = 0., m = 0, n = 0;
for (let it = 0; it < 4; ++it) {
//chords
tm += (exp2(.05 / (it + 1) % 4) - .85);
tm /= 2;
m = .7 * vox(1, .5 * time, 3 + fmod(4 * tm, [2, 15][trunc(tm) % 2])) * exp(-15. * fmod(tm, 1));
m += 2. * vox(1, .25 * time, 3. + fmod(tm, 6)) * exp(-8. * fmod(tm, 1));
n = 4. * vox(1, time, 1. + fmod(tm, [5, 7][trunc(tm) % 2])) * exp(-10. * fmod(tm, 1));
n += 1. * vox(1, 2 * time, 3 + fmod(2 * tm, 17)) * exp(-5. * fmod(tm, 1));
sn += m + n;
// background voice
dtm += (exp2(.125 / (it + 1) % 4) - .85);
let dd = [2, 4][trunc(.5 * dtm) % 2] * .25 * dtm;
l = cos(2. * vox(.5, .25 * time, [2, 4][trunc(.5 * dtm) % 2] * .25 * dtm )-1.57)
l = abs(2. * l * max(0, 1-fract(dd )) * min(1, 20.*fract( dd )));
l *= max(0., 1.-time/40) * max(0, 1.-fmod(time/4, 1)) * 1.5 * fmod(time/4, 1);
sl += l;
}
// premix
let tmp = [(sl + sn)*4., (sl + sn)*4.];
//sl += .3 * sn;
// reverb
let rv = [0, 0];
let y = Array(8).fill(0);
const samp = this.phase;
// prime power delaytimes
//const dt = [1331, 2197, 4913, 6859, 2401, 3125, 2187, 2048];
const dt = [2401, 3125, 2187,2048, 6859, 4913,2197, 1331];
// hadamard matrix
let hmt = [1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1];
hmt = hmt.map((n, idx) => SQRT1_2 * hmt[idx]);
// input
const minput = {
rev_dly_scR: 1,
rev_dly_scL: .95,
lop_cf: 4200,
lop_q: 1.1,
rev_gn1 :.45,
rev_gn2 :.95
};
// rescale delay
let scl = minput.rev_dly_scL, scr = minput.rev_dly_scR;
for (let i = 0; i < 8; ++i) {
const it4 = i % 4, ip4 = i % 4 + 4;
// gain exp higher more reverb
const g1 = exp2(-minput.rev_gn1 / (1 + i) % 8);
const g2 = minput.rev_gn2;
const sclR = round(scr * dt[it4]), sclL = round(scl * dt[ip4]);
// summer and fix lowh-end accumulation
y[it4] += this.dcblock(this.zn[it4][samp % sclR], 0.994, it4);
y[ip4] += this.dcblock(this.zn[ip4][samp % sclL], 0.994, ip4);
// correlate
y[it4] *= hmt[it4];
y[ip4] *= hmt[it4];
// lowpass
tmp[0] = g2 * this.e2poleLp(tmp[0], minput.lop_cf, minput.lop_q, it4);
tmp[1] = g2 * this.e2poleLp(tmp[1], minput.lop_cf, minput.lop_q, ip4);
//shuffle
//tmp[0] *=hmt[ip4];
//tmp[1] *=hmt[it4];
// buffer last frame
this.zn[it4][samp % sclR] = g1 * y[it4] + tmp[0];
this.zn[ip4][samp % sclL] = g1 * y[ip4] + tmp[1];
// shuffle
rv[0] = (y[0] + y[5] + y[6] + y[2]) / 4;
rv[1] = (y[4] + y[1] + y[3] + y[7]) / 4;
}
o[0] = (rv[0] + l + tmp[0]);
o[1] = (rv[1] + l + tmp[0]);
return o;
}
// buffers, eq states
constructor() {
this.phase = 0;
this.zn = Array(8).fill().map(() => Array(6859).fill(0));
this.e2pSt = Array(8).fill().map(() => Array(4).fill(0));
this.dcbSt = Array(8).fill().map(() => Array(2).fill(0));
}
// highpass
dcblock(xin, at, instnc) {
let state = this.dcbSt[instnc];
let y = xin - state[0] + at * state[1];
state[0] = xin;
state[1] = y;
return y;
}
// lowpass direct form II
e2poleLp(val, cf, q, instnc) {
let state = this.e2pSt[instnc];
let y = 0,
w0 = tau * cf / 44100,
a0 = sin(w0) / (2.0 * q),
ac = 1.0 + a0,
bc = ((1.0 - cos(w0)) / 2) / ac,
a1 = (-2.0 * cos(w0)) / ac,
a2 = (1.0 - a0) / ac;
y = bc * val + bc * state[0]
+ bc * state[1]
- a1 * state[2] - a2 * state[3];
state[1] = state[0];
state[0] = val;
state[3] = state[2];
state[2] = y;
return y;
}
}).play(0, {
amp:.5,
duration: 1e8
});
// utilities
const{PI,exp,log,sin,cos,floor,trunc,pow,log2,min,max,abs,tanh,round,SQRT1_2}=Math;
const tau=PI*2.0;
const fract=x=>x-floor(x);
const fmod=(x,y)=>x-floor(x/y)*y;
const exp2=x=>exp(x*log(2.0));
const env_ad=(t,a,d)=>min(t/max(1e-5,a),exp(-(t-a)*5.436563/d));
const msat=(x,a)=>0.5*(abs(x+a)-abs(x-a));
const softkn=(x,kn)=>x/(kn*abs(x)+1);
const smoothstep=(e0,e1,value)=>{const x=max(0,min(1,(value-e0)/(e1-e0)));return x*x*(3-2*x);};