Intergalactic Planetary

The robot voice from the Beastie Boys track of the same name.
youtube.com/watch?v=qoryo0atb6g

Log in to post a comment.

var unpck = (code, offset, scale) => {
    var d = [];
    for(var i = 0; i < code.length; ++i) {
        var db = (code.charCodeAt(i)-0x23)/-scale+offset;
        var v = 10**(db/20);
        d.push(v);
    }
    return d;
};

var tape1 = [
unpck("~~prqkeaadmkgflvu_RKIMS[`ciu~~~~~~~~~~~~oeadiu~~siir~vnggklog_VOKJLQZfiha[YY^hpplkgb__\\\\`l~tmmw~~~~~~|zz~~~~~~~~~~ztnlmz~~~~~~~~~~~~~~~~~{L5)$##&.7AM[gt~~qjf`\\VOGEEJOVbowzthTG=778>DISdnnou~~~~~~~~~~~~zspptyrjeelsty~~~qi_XX\\__cinv~~~~q^XZg{~~~~zontpkilr~~~}~~~~~~}~~q_S",-21.115,5),
unpck("vbPKOSSQMHHGJNTRNHEEGMG@>?DKPX`go{ulcbUHDDHLQPQRMGBABGMWJ<3/02771+*)+.10238AKIILMNF<879>DLQQRX[\\\\]_aaaaeghkaRNRY`ZOIB><@ETglhip~~~~~~~~~~mWLGDBDEDBAEJLJKJIHEB?:8743.)((+.1/*%#$(*+('(((('',4>ELKMOQUVM@=>FLONJIKOKJIGDC@:984.-.08>?@?AB>;=KSQJEFHJE;30-,-17=DHLNNR\\issm`ROP",-13.574,5),
unpck("rWJINQTSQLLKMNLMNPSau}xrnnqux|~~~~~ofZKGGGEED@?A?AN`jrtrnTFEGMRPHB>8410.-/5<EKPRW\\]YUTVX\\^\\XW[\\aglsvtrquuppiSB=>;:<>ACO]fr{~ujfghhr}~~~~~nTF?90*&$#$*/9>BIPTSSPOORROKIGHOU]][UOJFCBA?<<;>AKTZ_hqstwvyxnQA<==>CDHIKNQSNH=30/035;DJT[gjhb]_\\[QD;;:;@BFLOR\\`ejnsxxxtrqtx~~~~~~~",-16.18,5),
unpck("vfejqrqfeegedddbcfjy~~~~~~~~~~~~~~~~~vlgfaYSQQUWY]eny~{wq_J@=650/04:<:=?=*%%(+,++.16:92048<DHEDFJNYaeq~~~~s]VSSWTUVYY^ix||~~~~~~~~~~~~~~~~|ph`UNIGD=87520-()*,*(*+,-.27:ADIQW[a`\\YXUUPPQRTVWVYagknu~~~~zhaYI@6/+,)%##(*+-25;<>DMRZ_dlw{~~~xlaYVPMOSUWZbl{~~~~~~~~~~~~~~~~~~~",-19.572,5),
unpck("eN48PeusYYfehgbegpwpzwtx|~~~~~~~~\\[\\X]C723006DNVMIKMPR77@CBGLGISTXZXYb\\]R>2.,+2467<BOI@@DGGGIKOV\\]]acgldcch_RRVPOQR_t}~qhelx~kfn~~~~~~~~~~~~~~somhTB7326:BJRUTU]bb`ccadhjhdgpZJIMIIOXTRTagkljhfhZUXeppq]SPKGDCDGJMG<87:BMTTONLMRTVUX^cgZ3%%#(9TVRVTSTTOORU[_amxwwl\\WUYh~tsbZ",-21.696,5),
unpck("d<(((&+60-0138>>DIUba`gtuukikkouh><?>?@FCHLD4+)-4SXMIO:115?QMCAHViihfaab\\ST\\[RNMLJIA=<>4/4DY_VNOgoos}vJHKTVI9.---,'&.?T[PS^sq\\Y_rmjd`dmi_`bfffYPOQOKMQX]YTPJD@>=?DHRUY]bfo~~~kQMGBADHJNW]elptvro@=?\\\\XVC616=CHEEDDLXVX^elhhhknnija]`o}eB@HIE:3'#$)&$(39AGEEN`OGCB?AFIPV^gbbh",-22.4,5),
unpck("~qPC?9,)(),*'$$'.=GIJMUehhfhqtvyJ48,##%)-/-.116?JSY_hjb\\YWZXNKSbfgPKOTMMSZ^a^OGGHGGLTZ_\\^djqunn|~~~~~b99?DFJHFIHHLQV\\fihkt~~~~~~~~~~~~~magljknuspqoga`][XPJGHGFFCDDDKT__`bl}~~UOPTUWSQU[acddflqo?:FDD@=>FGBCEGMNEAEPSWZ[ev~~~~}~~vhgprrdbmvkcVQNKHEH[gof]bu~~~yj_adiztrw|~~~",-24.186,5),
unpck("~~~}{utspliYPNLOUuslko{~~~~~~~~~;&$+5EdF>BS]ja^fotwvs{~}xy~~zw}~~~eRMMVn|od``_abefimuw{~~~~~~~~~~~~~~N+$%#'1@A??>@Q\\Y\\]]kvvw}~|wy~~~~~~~ZPTMOS\\RR_eTJIIMNLJJMMLQWZX]fgnsxwuxyoQHEDMOGGOYm|zwy~~wA.&#$,5EB=>=:;;:;@FSSX\\daaeeirswxylbTPRVZp~pc]XW_goqz~~~~~~~~~zifmtxxvv|~~~~",-25.633,5)];

var tape2 = [
unpck("dD4-/.77NMVEFC:497JWG>5@BUZ`TH;>:FH@I>@BBFDNQDID>8KRY]OODDENLWS\\JMT]SD<B:=HPVeNG88<?MXdtxoLG:410*+,0-2:>M[irvvvxqrpmmqq~~~~YO6.)))#%3<C@;",-33.795,5),
unpck("jZNMbUTQQEE>=+*#&*5@&$++=>=9=;-/5;OF6(%31??:853,-59FSC9:64<<AAA<66;=EFILW_aWYhiqiqp|~~~~~kLD=8@>?<5132CBNNTTbbov~~~~~~~~~~~`I0,%)03,/'02B",-21.084,5),
unpck("i\\JDPQS\\\\QNE<>/5?JNRHA==<AA22%*DC>;CB1-,87N11=>>CFF::889?CF?=;:8JH[QTOGGCEOPLQLLCMIWUhfsqsd8*(#*(/.;8F?APNOCIHJHIJLPSX[]adhf\\OGGBHGCAGCTR",-22.68,5),
unpck("~qlNCLUZGKD?995EGNCGFULMLOOTVY\\kgoruc\\\\ZVZNQGPNSW[Z\\_hkXWQ_UZ>AFNLQPRUZ_`mkje`[YXqp~}~~~~~~dcOQTSLMbapn|{~xvwvzy{|~~~~~~~~|dMR@;4+&$#)%=3",-24.633,5),
unpck("v|2243%/,))-+53NEGF22&'#1-?;<7PNWU[U77=@>4,-,**C@IFSRUJ))(,+40CDMH^YYPSXX]a\\[VW``u~~{~~}kciSUGHBBACBLdf__kk{x~}|xvrr~~~~~k\\D@97980//.SSPO",-21.371,5),
unpck("kcGHLJEGDIBJGUQ``UVLLEKINMHDSRc_]ZbY*+57D?1=671HKNN>?MN-.=E@@23+,(5355;:@ANOC?=;:?6;9;<>=6522##,,(.8;66?A\\][jjkkhdd`adedea`UVJJ@FINMS^]]Z",-24.622,5),
unpck("mR<-,JDC>NCFQ^]c_nh\\\\XTRED=:YUUTONl\\<?<EEXQNMLVV]fjoojgQFABB??C=<922ECLIKDOPD'&&%-**$%#//119:B>?@@CD@@QRc]d]cebRTRSXXVWKNSUVXMO55>>^`SQXU",-23.752,5),
unpck("gc_::1/GGCBDC``dcgcoKICB5542biggd[ijBCH,,))++:9MJIIYS^X>+)44;<1-..3399OKKBF@>55>>..%#('$$%%KDA;.07CFEHEY^jide_fNPRROPQU[]TUOXaaJIEHghklfe",-30.339,5)];

ditty.bpm = 105;

input.vocoderCarrierNoise = .1;
input.vocoderSize = 0; // min=-1,max=1,step=.1
input.vocoderSpeed = 1; // min=-2,max=2,step=.1
input.vocoderPitch = .3; // min=-24,max=24,step=.1

var autom = (tick) => {
    var st = tick % 32;
    var bend = 0;
    var p;
    var tape;
    if(st < 16) {
        tape = tape1;
        var t = (st+10) % 8;
        p = ((tick % 4) + [0, 0, 2, -2][(tick>>1)%4]) * 69;
        bend = clamp01(t*3) * -6 + clamp01((t-.75)*1.7) * 6;
    }
    else {
        tape = tape2;
        p = (tick % 2) * 69;
        bend = -12 - clamp01(st-20) * 5;
    }
    return [p, bend, tape];
}

var sy = synth.def(class {
    constructor(opt) {
        this.ops = [];
        this.nunison = 2;
        this.tupd = 0;
        var amp = 1 / this.nunison;
        for(var i = 0; i < this.nunison; ++i) {
            var t = this.nunison > 1 ? i / (this.nunison-1) : .5;
            var pan = t*2-1;
            var semitn = t * .1;
            this.ops.push({
                p: Math.random(),
                detune: 2**(semitn/12),
                fl: (.5 + pan * .5) * amp,
                fr: (.5 - pan * .5) * amp
            });
        }
    }
    process(note, env, tick, opt) {
        if(this.tupd <= 0) {
             this.freq = midi_to_hz(note + input.vocoderPitch + opt.bend) * ditty.dt
        }
        this.tupd -= ditty.dt * 100;
        
        var vl = 0;
        var vr = 0;
        for(var i = 0; i < this.ops.length; ++i) {
            var op = this.ops[i];
            vl += (op.p*2-1) * op.fl;
            vr += (op.p*2-1) * op.fr;
            op.p += this.freq * op.detune;
            while(op.p >= 1) {
                op.p -= 1;
            }
        }
        vl = lerp(vl, Math.random()-.5, input.vocoderCarrierNoise);
        vr = lerp(vr, Math.random()-.5, input.vocoderCarrierNoise);
        return [vl, vr];
    }
});

var vocoder = filter.def(class {
    constructor(opt) {
        this.tapepos = 0;
        var freqs = [123, 294, 481, 746, 1387, 2255, 3403, 4865];
        var muls = [.5, .6, 1, 1, 1, 1, 1, 1];
        this.bands = [];
        this.tape = tape1;
        for(var i = 0; i < 8; ++i) {
            this.bands.push({
                freq: freqs[i],
                flt: [new SVF({mode:'bp', num:2, q:4}), new SVF({mode:'bp', num:2, q:4})],
                mul: muls[i]
            });
        }
        this.tupd = 0;
    }
    process(inp, opt) {
        if(this.tupd <= 0) {
            this.tupt += 1;
            this.tape = opt.tape;
            this.tapepos = opt.tapepos;
        }
        this.tupd -= ditty.dt * 100;
        
        var vl = 0;
        var vr = 0;
        var p = this.tapepos;
        
        for(var i = 0; i < this.bands.length; ++i) {
            var tape = this.tape[i];
            var band = this.bands[i];
            var pi = ~~p;
            var l = lerp(tape[pi]||0, tape[pi+1]||0, p-pi);
            
            band.flt[0].fc = (2**input.vocoderSize) * band.freq * ditty.dt;
            band.flt[1].fc = band.flt[0].fc;
            var mul = clamp01(l-.015) * band.mul / band.flt[0].q;
            vl += band.flt[0].process(inp[0]) * mul;
            vr += band.flt[1].process(inp[1]) * mul;
        }
        this.ptape += input.vocoderSpeed * 110 * ditty.dt;
        return [vl*3, vr*3];
    }
});

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.lastOut * this.kl;
        var r = inv[1] * this.kr;
        var nextl = l + this.delay[1].lastOut * this.fb;
        var nextr = r + this.delay[0].lastOut * this.fb;
        this.lastOut[0] = inv[0] + this.delay[0].lastOut * this.wet;
        this.lastOut[1] = inv[1] + this.delay[1].lastOut * 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: 2/3, pan: .5, wet: .3, feedback: .5, stereo: 2});

var position = 0;

loop( () => {
    sy.play(b2, { duration: 1e20, release: .1, amp: 4, bend: (t,o) => {
        position += ditty.dtick * input.vocoderSpeed;
        if(position < 0)
            position += 32;
        return autom(position)[1]
    }});
    sleep(1e20);
}, { name: 'vocoder' })
    .connect(vocoder.create({tape: (t,o) => autom(position)[2], tapepos: (t,o) => autom(position)[0]}))
    .connect(echo.create()
);

class Delayline {
    constructor(n) {
        this.n = ~~n;
        this.p = 0;
        this.lastOut = 0;
        this.data = new Float32Array(n);
    }
    clock(input) {
        this.lastOut = this.data[this.p];
        this.data[this.p] = input;
        if(++this.p >= this.n)
            this.p = 0;
        return this.lastOut;
    }
    tap(offset) {
        var x = this.p - offset - 1;
        x %= this.n;
        if(x < 0)
            x += this.n;
        return this.data[x];
    }
}

// State Variable Filter based on an article by cytomic Sound Music Software
// https://cytomic.com/files/dsp/SvfLinearTrapOptimised2.pdf
class SVF {
    constructor(opt)
    {
        this.stages = [];
        this.mode = opt ? opt.mode || 'lp' : 'lp';
        this.fc = 0;
        this.q = 1;
        this.num = opt ? opt.num || 1 : 1;
        // g parameter determines cutoff
        // k parameter = 1/Q
        for(var i = 0; i < this.num; ++i) {
            this.stages.push({lp:0,bp:0,hp:0,ap:0,ic1eq:0,ic2eq:0});
        }

        this.q = opt && isFinite(opt.q) ? opt.q : 1;
        this.fc = opt && isFinite(opt.fc) ? opt.fc : .25;
    }
    _clock(s, input, a1, a2, a3, k) {
        var v1, v2, v3;
        v3 = input - s.ic2eq;
        v1 = a1 * s.ic1eq + a2 * v3;
        v2 = s.ic2eq + a2 * s.ic1eq + a3 * v3;
        s.ic1eq = 2 * v1 - s.ic1eq;
        s.ic2eq = 2 * v2 - s.ic2eq;
        s.lp = v2;
        s.bp = v1;
        s.hp = input - k * v1 - v2;
        s.ap = s.lp + s.hp - k * s.bp;
    }
    process(input)
    {
        if(this.fc != this._fc) {
            this._fc = this.fc;
            this._q = this.q;
            var fc = this.fc * .5;
            if (fc >= 0 && fc < .5) {
                this.g = Math.tan(Math.PI * fc);
                this.k = 1 / this.q;
                this.a1 = 1 / (1 + this.g * (this.g + this.k));
                this.a2 = this.g * this.a1;
                this.a3 = this.g * this.a2;
            }
        }
        if(this.q != this._q) {
            this._q = this.q;

            this.k = 1 / this.q;
            this.a1 = 1 / (1 + this.g * (this.g + this.k));
            this.a2 = this.g * this.a1;
            this.a3 = this.g * this.a2;
        }

        for(var i = 0; i < this.num; ++i) {
            this._clock(this.stages[i], input, this.a1, this.a2, this.a3, this.k);
            this._clock(this.stages[i], input, this.a1, this.a2, this.a3, this.k);
            input = this.stages[i][this.mode];
        }
        return input;
    }
}