Cosmodrone

droning chords using wavetable synthesis

Log in to post a comment.

// WIP

function synthharmonics(outp, harm, len, nh) {
    for(var j = 0; j < len; ++j) {
        outp[j] = 0;
    }
    for(var i = 0; i < nh; ++i) {
        var f = i + 1;
        var amp = harm[i];
        for(var j = 0; j < len; ++j) {
            var x = j / len;
            outp[j] += Math.sin(x * f * Math.PI * 2) * amp;
        }
    }
}
function fract(x) {
    return x - Math.floor(x);
}

class MorphWave {
    constructor(len) {
        this.len = len;
        this.data = new Float32Array(len);
        this.nharm = len >> 4;
        this.update();
    }
    update() {
        var nh = this.nharm;
        var harm = new Float32Array(nh);
        for(var i = 0; i < nh; ++i) {
            harm[i] = .3 / (1 + i);
        }
        for(var i = 0; i < nh; i += 1) {
            harm[i] *= Math.pow(Math.random(), 2);
        }
        synthharmonics(this.data, harm, this.len, nh);
    }
}
class Morph {
    
}

const syn = synth.def(
    class {
        constructor(opt) {
            this.nwtb = 1024;
            this.wtbs = [new MorphWave(this.nwtb), new MorphWave(this.nwtb)];
            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 = 0;
            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;
            dt += Math.sin(tick * 9) * .00002;
            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, wtb1 = this.wtbs[1].data, wtbm = this.morph;
            
            if(++this.shimmerc >= 70) {
                this.shimmerc = 0;
                for(var i = 0, ni = this.ops.length; i < ni; ++i) {
                    this.ops[i].ff = 1 + Math.random() * .15;
                }
            }
            
            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;
                }
            }
            return [suml * env.value, sumr * env.value];
        }
    });

loop(() => {
var k = [0, 2, -2, -4];
for(var i = 0; i < 3; ++i) {
    var o = k[i];
    syn.play(c2+o, {duration: 16, attack: 5, release: 5});
    syn.play(d4+o, {duration: 16, attack: 5, release: 5});
    syn.play(c4+o, {duration: 16, attack: 5, release: 5});
    syn.play(e4+o, {duration: 16, attack: 5, release: 5});
    syn.play(b4+o, {duration: 16, attack: 5, release: 5});
    sleep(16);
}
}, {name: "pad"});