I don't want to grow up into some other kind of witch and that's why I'm going to show you how I make it to the exit using my own spells. #Instrumental #VHS #RetroFuturism
Log in to post a comment.
/* */ const InstGr = class { constructor() { this.drrevInst = [new DrRoom(), new DrRoom(), new DrRoom()]; this.fltr = new FilterBank(); } process(time) { let snth = 0, fltpd = 0,padhi = 0,padlw = 0,crn1 = 0,crn0 = 0,arp = 0, bll = 0; // -------- INTRO // pad chord progression + warm sound pad crn0 = lerp(.34, .17, fract(.5 * time)) * softkna(arpmel(2. + .5 * time), .76, .86); // flute melody fltpd = .8 * (0.75 * softkna(sup_chd(.3 + 1 * time, 1.5 / 2), .8, .8) + .3 * sup_chd(.15 + 1 * time, .5)); fltpd = smoothstep(3, 4.8, time) * fltpd; //softkn(pad, .7) fltpd = .9 * tanh(fltpd + .9 * crn0); // metalic trumpet crn1 = (mod(time, 8) > 4 ? 1.2 : .7) * sup_ab(time) * env_adc(fract(time), .25, .7); crn1 *= fadein(18, 24, time); // bell-like sound very quiet in the background bll = (sin(time) * .3 + .3) * msat(.6 * sin(12 * time) * sup_chd((1.2 + .5 * time), 4.), .6); bll *= fadein(24, 32, time); // bright bell-like sound melody arp = lerp(.07, .47, fract(.5 * time)) * arpmel(time); // sum to output snth = arp + bll + lerp(1e-6, crn1, fract(time)); // toms let tmdr = 0; let tm0 = 0, tm1 = 0; tm0 = (random() * 2. - 1.); tm1 = tm0; const ft = mod(1 * 2. * time, 1.); const ft1 = mod(1 * 4. * time, 1.); // noise gate toms and than eq for a perceived room fx tm0 *= 25 * (max(0, (1 - ft), min(1, 40 * ft)) / max(1, 250. * ft)); tm1 *= 35 * (max(0, (1 - ft1), min(1, 25 * ft1)) / max(1, 80. * ft1)); tm1 = tm1 * [1, 0, 0, 1, 1, 0, 1, 0].ring(4 * time); tm0 = this.drrevInst[0].process(tm0, { rc_fc: .05 + 0.27, rc_res: 1.0, lpf_fc: 250, lpf_q: 0.55 }); tm1 = this.drrevInst[1].process(tm1, { rc_fc: .1150 + 0.15, rc_res: 1.45, lpf_fc: 100, lpf_q: 0.25 }); tmdr = tanh(tm0 + tm1); // kick const hdkkdt = [260, 60, 0, 160][int(time) % 4]; let hdkk = 0; const hdkk_rt = 4 * time + hdkkdt; hdkk = sin(tau * (4 * hdkk_rt - 3 * exp(-44 * fract(hdkk_rt)))); hdkk *= [1, 0, 1, 1, 0, 1, 0, 1].ring(hdkk_rt); hdkk = softkna(hdkk * 8, .6, .31); hdkk *= env_ad(fract(4. * time), .3, .5); // bass let pwbss = 0; let pwmel = 1 * [49, 58.8, 49, 73.5].ring(time) * tau * time; const pwtft = fract(4 * time); pwbss = .73 * sin(4 * pwmel - 4 * exp(-10 * pwtft)) + .5 * cos(.5 * (6 * pwmel - 24 * exp(-10 * pwtft))); pwbss = sin(pwbss - .21); let pwbss_gain = .763; pwbss *= [1, 0, 1, 1, 0, 1, 0, 1][int(2 * time) % 8]; pwbss = softkn(pwbss, pwbss_gain) * env_ad(pwtft, .37, .46); pwbss = this.drrevInst[2].process(pwbss, { rc_fc: lerp(.78, .9, fract(.2 * time)), rc_res: .5, lpf_fc: 175, lpf_q: 1.25 }); // -------- CHORDS second part let synthtime = 0; const mx = 4.; const chch0 = (mod(time, 12) > 6 ? (mx * (1. / 8) * time) : 1); const chch1 = mx * (1. / 8) * time; const chch2 = [2, 1].ring(mx * (1. / 4) * time); synthtime = [[4, 0, 4, 0].ring(mx * 2. * time), [4, 1, 0, 6].ring(mx * 2. * time)].ring(chch0) + [28, 32, 24].ring(chch1) + mod(time, chch2); const evdt = 2 * 4 * synthtime; // fast strumming padhi = .5 * chd(.1 + .5 * synthtime, evdt, 1, 12) + .63 * chd(synthtime, evdt, 1, 8); // deep and slow padlw = chd([.5, 2, 6, 4].ring(1 * time) + mod(1 * time, 1), 4 * time, .25, 6); padlw += .5 * chd(.1 + 2 * time, 2. * time, .5 * [1.5 / 3, .75 * 2].ring(2. * time), 12); return { hichordOut: padhi * fadein(38, 42, time), lwchordOut: padlw * fadein(34, 36, time), fltpdOut: fltpd * fadein(36, 32, time), synthOut: snth * fadein(18, 24, time), pwbssOut: pwbss * fadein(16, 24, time), tomsOut: tmdr * fadein(6, 10, time), hardkkOut: hdkk * fadein(14, 20, time) } } }; // ######## Intrument Group const MIX = class { constructor() { this.period = 0; this.cmain = new InstGr(); this.crev = [new Rev_Mn(), new Rev_Mn(), new Rev_Mn(), new Rev_Mn(), new Rev_Mn(), new Rev_Mn()]; this.chrdcrev = [new Rev_Mn(), new Rev_Mn(), new Rev_Mn(), new Rev_Mn()]; this.fltr = new FilterBank(); this.stfltr = [new FilterBank(), new FilterBank(), new FilterBank(), new FilterBank()]; this.drrevInst = [new DrRoom(), new DrRoom(), new DrRoom(), new DrRoom()]; } process() { let fltpd = 0,hichrd = 0,lwchrd = 0,klav = 0,toms = 0,ktmdr = 0,pwbss = 0; let rev_oxpad = [0, 0],rev_chrds = [0, 0],rev_osyth = [0, 0],rev_otoms = [0, 0]; this.period += 1; let time = int(this.period) / ditty.sampleRate; // prefilter const cmain = this.cmain.process(time); pwbss = .86 * this.fltr.karlsen4pole(cmain.pwbssOut, 460, .7, 1, 0); fltpd = this.fltr.karlsen4pole(cmain.fltpdOut, 380, .6, 1, 1); klav = .6 * this.fltr.karlsen4pole(cmain.synthOut, 700, 1, 1, 2); toms = .83 * this.fltr.karlsen4pole(cmain.tomsOut, 60, .7, 1, 3); ktmdr = .31 * this.fltr.karlsen4pole(cmain.hardkkOut, 100, 1.3, 1, 4); hichrd = this.fltr.karlsen4pole(cmain.hichordOut, 360, 1, 1, 5); lwchrd = cmain.lwchordOut; const drydrumsum = (toms + ktmdr + .7 * pwbss); const drysynthsum = fltpd + .9 * klav + .6 * hichrd + .7 * lwchrd; // -------- CHORD PROGRESSION second part lwchrd = this.drrevInst[3].process(lwchrd, { rc_fc: .985, rc_res: .29, lpf_fc: 200, lpf_q: 1.2 }); rev_chrds[0] = .8 * this.chrdcrev[0].process(lwchrd, 0, 30, 0.439); rev_chrds[1] = .8 * this.chrdcrev[1].process(lwchrd, 8, 30, 0.439); // animated stereo width strumming chrods rev_chrds = this.fltr.stwidth(rev_chrds, max(.7, smoothstep(0, 1, mod(.166 * time, 3.)))); rev_chrds[0] += 1.12 * this.chrdcrev[2].process(hichrd, 0, 12, 0.427); rev_chrds[1] += 1.12 * this.chrdcrev[3].process(hichrd, 8, 12, 0.417); // the sum chords stumming + slow, narrow the width will add competition for the dr+bass line rev_chrds = this.stfltr[3].stwidth(rev_chrds,min(.96, max(.8, smoothstep(0, 1, mod((1./12) * time, 1.)))) ); rev_chrds[0] = 0.16 * rev_chrds[0] + drysynthsum; rev_chrds[1] = 0.16 * rev_chrds[1] + drysynthsum; // -------- INTRO rev_oxpad[0] = .422 * this.crev[0].process(fltpd, 0, 16, 0.697); rev_oxpad[1] = .422 * this.crev[1].process(fltpd, 8, 16, 0.696); rev_osyth[0] = .237 * this.crev[2].process(klav + .1 * pwbss, 0, 12, 0.433) rev_osyth[1] = .237 * this.crev[3].process(klav + .1 * pwbss, 8, 12, 0.429) rev_otoms[0] = .188 * this.crev[4].process(toms, 0, 38, 0.572); rev_otoms[1] = .188 * this.crev[5].process(toms, 0, 38, 0.560); /* mid side processing of the stwidth with filter helps with a pumping compression-like fx */ rev_oxpad = this.stfltr[0].stwidth(rev_oxpad, max(.7, smoothstep(8, 4, time))); rev_osyth = this.stfltr[1].stwidth(rev_osyth, .5) ; // -------- DRUMS const rvdrwidth = max(.3, .6 * smoothstep(0, 1, mod(.25 * time, 3.))); rev_otoms = this.stfltr[2].stwidth(rev_otoms, rvdrwidth); // second part, adjust volume, subtle chorus-like fx, re-captures the listener's attention if (time > 38&&(mod(time, 16) > 8) ) { rev_otoms = [.63 * msat(rev_otoms[0], lerp(.6, .87, fract(5 * time))) , .63 * msat(rev_otoms[1], lerp(.83, .66, fract(.5 * time)))]; } // eq filter toms for reveb - more darkish bottom rev_otoms[0] = this.drrevInst[0].process(rev_otoms[0], { rc_fc:.52, rc_res:.89, lpf_fc: 125, lpf_q: 0.7 }); rev_otoms[1] = this.drrevInst[1].process(rev_otoms[1], { rc_fc:.52, rc_res:.89, lpf_fc: 125, lpf_q: 0.7 }); // adjust volume in the second part, add dry signal rev_otoms = [((time < 24) ? .9 : .7) * (drydrumsum + rev_otoms[0]) , ((time < 24) ? .9 : .7) * (drydrumsum + rev_otoms[1])]; // -------- MASTER OUT if(time > 46 && time < 48 ) return rev_otoms; return [rev_chrds[0] + rev_osyth[0] + rev_oxpad[0] + rev_otoms[0], rev_chrds[1] + rev_osyth[1] + rev_oxpad[1] + rev_otoms[1]]; } }; // ######## MIX // will filter noise of the toms class DrRoom { constructor() { this.fltr = new FilterBank(); } process(sgnl_in, finp, ov) { let outp = sgnl_in; outp = this.fltr.lpf_rc(outp, finp.rc_fc, finp.rc_res); outp = this.fltr.dcblock(outp, .996, 0);//highpass outp = this.fltr.lpf_earlvl(outp, finp.lpf_fc, finp.lpf_q); return outp; } }; // ########DRROOM /* mono reverb I spend hours with trial and error, why I'm obsessed with this FDN-ish reverberation approach? Even when it looks (in my other ditties ) weird, I simply stop when I like how it sounds. */ const Rev_Mn = class { constructor() { this.zn = Array.from({ length: 8 }, () => Array(2639).fill(0)); this.dcBlockState = Array.from({ length: 17 }, () => [0, 0]); this.period = 0; } // input signal, matrix offset, reverb tail, scale delay times process(rv_xin, offs, rtail, scl) { this.period += 1; let y = [0, 0, 0, 0, 0, 0, 0, 0]; let rv = 0, itter = 0; // no special meaning a hadamard, a constant sum, and something creative const mat0 = [1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1]; const mat1 = [-1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1]; const mat3 = [1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]; // precalc faustlib primenumber delay func with some reordering tweaks let dt = [1637, 1277, 1607, 2639, 1823, 751, 1823, 2591]; dt = dt.map((n, idx) => (scl * dt[idx]) | 0); for (let i = 0; i < 8; i++) { const it8 = i % 8; const pdt = this.period % dt[it8]; const g3 = exp(-(1 * rtail * 0.022675736) / (i + 1)); for (let it = 0; it < 2; it++) { const g4 = exp(-((1.41421 / rtail) * 0.0022675736) * (itter + 1)); // helps with decorrelation y[it8] = this.dcblock((this.zn[it8][pdt] * mat0[itter % 16]), g4, itter); itter++; } this.zn[it8][pdt] = g3 * y[it8] + mat3[it8 + offs] * rv_xin; rv += mat1[it8 + offs] * y[it8]; } rv = this.dcblock(rv, .997, 16);// highpass return rv * 0.25; } dcblock(xin, at, instnc) { let state = this.dcBlockState[instnc]; let y0 = xin - state[0] + at * state[1]; state[0] = xin; state[1] = y0; return y0; } }; // ######## REV_MN class FilterBank { constructor() { this.svf_opt2State = [0, 0]; this.lpf_rc1State = [0, 0]; this.lpf_earlvlState = [0, 0]; this.dcBlockState = Array.from({ length: 8 }, () => [0, 0]); this.k4PolesState = Array.from({ length: 8 }, () => [0, 0, 0, 0]); } // musicdsp lpf_rc(xin, cf, reso) { let state = this.lpf_rc1State; const c = pow(0.5, (128 - cf * 128) / 16.0); const r = pow(0.5, (24 + reso * 24) / 16.0); const a = (1 - r * c); state[0] = a * state[0] - c * state[1] + c * xin; state[1] = a * state[1] + c * state[0]; return state[1]; } // https://www.earlevel.com/main/2012/11/26/biquad-c-source-code lpf_earlvl(xin, fc, reso) { let state = this.lpf_earlvlState; const Fc = fc / 44100.; const Q = reso; const K = tan(PI * Fc); const norm = 1 / (1 + K / Q + K * K); const output = (xin * norm + state[0]); state[0] = xin * (-2 * norm) + state[1] - (2 * (K * K - 1) * norm) * output; state[1] = xin * norm - ((1 - K / Q + K * K) * norm) * output; return output; } // musicdsp // 0:lowpass 1:highpass karlsen4pole(xin, cf, resonance, type, instance) { let poles = this.k4PolesState[instance]; let cutoff = tau * cf / 44100.0; let rez = poles[3] * resonance; xin -= rez; poles[0] = poles[0] + ((-poles[0] + xin) * cutoff); poles[1] = poles[1] + ((-poles[1] + poles[0]) * cutoff); poles[2] = poles[2] + ((-poles[2] + poles[1]) * cutoff); poles[3] = poles[3] + ((-poles[3] + poles[2]) * cutoff); return (type == 0 ? poles[3] : (xin - poles[3])); } // faustlib dcblock(xin, at, instnc) { let state = this.dcBlockState[instnc]; let y0 = xin - state[0] + at * state[1]; state[0] = xin; state[1] = y0; return y0; } // faustlib stwidth(xin, kw) { const tmp = 0.5 * kw; const nL = tmp * (xin[1] - xin[0]); const nR = (1.0 - tmp) * (xin[1] + xin[0]); return [nR + nL, nR - nL]; } }; // ######## FILTER // ++++++++++++++++++++++++++++++++++++++++++ const playall = synth.def(MIX, { amp: 1.0, duration: 240 }); playall.play(); // ++++++++++++++++++++++++++++++++++++++++++ // chord synth function chd(rt, nt, mx, pm) { const chd_osc=(x)=>sin((2. * x + 3. * mod(.5 + abs(x), PI))); /* chrr = [chord(g4, chords['min']), chord(eb4, chords['maj']), chord(f4, chords['maj']), chord(d4, chords['min']), chord(g4, chords['min']), chord(c4, chords['min']), chord(d4, chords['min']), chord(f4, chords['maj'])].flat(); */ const chrr = [67, 70, 74, 63, 67, 70, 65, 69, 72, 62, 65, 69, 67, 70, 74, 60, 63, 67, 62, 65, 69, 65, 69, 72]; let y = 0.; const ft = .5 * rt; const ev = env_adc(fract(nt), .49, .9) * env_adc(fract(ft), .31, .64); for (let i = 0; i < 3; i++) { let ph = mx * midi_to_hz(chrr.ring(int(ft) % 8 * 3 + i % chrr.length)) * tau * rt; y += .3 * chd_osc(lerp(.2, .7, fract(.5 * ft)) - (sin(pm * rt) + ph)) * ev; } return y; } // supportive pad function sup_ab(rt) { let y = 0; y = cos(midi_to_hz([74, 70, 72, 65, 74, 72, 72, 77].ring(rt)) * (3 + rt) * tau); y = softkn((3. * sin(12 * rt)) + 3 * y, .91); return y; } // klav function arpmel(rt) { let y = 0; const ft = 4 * rt; const ev = pow(min(1., 10. * fract(ft)) * (1. - fract(ft)), 2.); const mel = [86., 82., 81., 77., 86., 82., 86., 82., 84., 81., 82., 89., 86., 82., 84., 81., 86., 82.]; y = cos(mod(midi_to_hz(mel.ring(ft)) * rt * tau, tau)); y *= ev; return y; } // flute function sup_chd(rt, mx) { let y = 0; const ft = .5 * rt; const ev = (fract(-ft) * fract(ft)); y = cos(mx * midi_to_hz([67, 77, 65, 74].ring(ft)) * rt * tau); y *= ev; return y; } // utilities const { random, PI, floor, sin, abs, max, min, exp, cos, tanh, pow, tan } = Math; const env_d = (t, d) => exp(-t * 5.436563 / d); const env_ad = (t, a, d) => min(t / max(1e-5, a), env_d((t - a), d)); const env_adc = (t, a, d) => clamp(min(t / max(1e-5, a), env_d((t - a), d)), 0, 1); const msat = (x, a) => 0.5 * (abs(x + a) - abs(x - a)); const softkn = (x, kn) => x / (kn * abs(x) + 1.0); const softkna = (x, kn, ad) => x / (kn * msat(x, ad) + 1.0); const fract = (x) => (x - floor(x)); const mod = (x, y) => (x - floor(x / y) * y); const tau = (PI * 2.0); const int = (x) => (x | 0); const smoothstep = (e0, e1, value) => {const x = max(0, min(1, (value - e0) / (e1 - e0))); return x * x * (3 - 2 * x); }; const fadein = (s, e, t) => smoothstep(s, e, t);