// 2022/10/17
// by srtuss
ditty.bpm = 90;
input.radiation = .25; // min=0.1,max=.5,step=0.01
input.nebula = 0; // min=0,max=2,step=0.01
function synthharmonics(outp, harm, len, nh) {
for(var j = 0; j < len; ++j) {
outp[j] = 0;
}
var twopi = Math.PI * 2;
for(var i = 0; i < nh; ++i) {
var f = i + 1;
var amp = harm[i];
var phas = Math.random();
for(var j = 0; j < len; ++j) {
var x = j / len + phas;
outp[j] += Math.sin(x * f * twopi) * amp;
}
}
}
function fract(x) {
return x - Math.floor(x);
}
class MorphWave {
constructor(len, nharm) {
this.len = len;
this.data = new Float32Array(len);
this.nharm = Math.min(nharm || 512, len>>1);
this.update();
}
update() {
var nh = this.nharm;
var harm = new Float32Array(nh);
for(var i = 0; i < nh; ++i) {
harm[i] = .3 * (1 + i)**-1 * Math.exp(-i * input.nebula);
}
for(var i = 0; i < nh; i += 1) {
harm[i] *= Math.pow(Math.random(), 3);
}
synthharmonics(this.data, harm, this.len, nh);
}
}
const syn = synth.def(
class {
constructor(opt) {
this.nwtb = 1024;
this.wtbs = [new MorphWave(this.nwtb, opt.nh), new MorphWave(this.nwtb, opt.nh)];
for(var k = 0; k < 2; ++k) {
this.wtbs[k].update();
}
this.ops = [];
var nop = 8;
for(var i = 0; i < nop; ++i) {
this.ops.push({
t: Math.random(),
ff: 1 + Math.random() * .01,
p: i / (nop-1)});
}
this.morph = Math.random();
this.shimmerc = 0;
this.morphdt = .000005;
}
process(note, env, tick, options) {
var suml = 0;
var sumr = 0;
var dt = midi_to_hz(note) * ditty.dt;
this.morph += this.morphdt;
if(this.morph >= 1) {
this.morph -= 1;
var t = this.wtbs[0]; this.wtbs[0] = this.wtbs[1]; this.wtbs[1] = t;
this.wtbs[1].update();
}
var wtb0 = this.wtbs[0].data;
var wtb1 = this.wtbs[1].data;
var wtbm = this.morph;
if(this.shimmerc >= 1) {
this.shimmerc -= 1;
for(var i = 0, ni = this.ops.length; i < ni; ++i) {
this.ops[i].ff = 2 ** ((Math.random() - .5) * input.radiation);
}
}
this.shimmerc += 700 * ditty.dt;
for(var i = 0, ni = this.ops.length; i < ni; ++i) {
var op = this.ops[i];
var idx = Math.floor(op.t * this.nwtb);
var opv = wtb0[idx] * (1-wtbm) + wtb1[idx] * wtbm;
suml += opv * op.p;
sumr += opv * (1 - op.p);
op.t += dt * op.ff;
while(op.t >= 1) {
op.t -= 1;
}
}
var m = (suml + sumr)*.5;
var s = (suml - sumr)*.5;
s *= 2;
return [(m+s) * env.value, (m-s) * env.value];
}
});
loop(() => {
var k = [0, 2, -2, -4];
for(var i = 0; i < 3; ++i) {
var o = k[i];
var chord = [d4, c4, e4, b4];
sine.play(c1+o, {duration: 16, attack: 5, release: 5, amp: .5});
syn.play(c2+o, {duration: 16, attack: 5, release: 5, nh: 64});
for(var j = 0; j < chord.length; ++j) {
syn.play(chord[j]+o + [-12,0,0,0,7,12].choose(), {duration: 16, attack: 5+j, release: 5, nh: 32});
}
sleep(16);
}
}, {name: "pad"});