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 = .86 * 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;
time+=36;
// 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 + .89 * klav + .56 * hichrd + .6 * 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] = 1.1 * this.chrdcrev[2].process(hichrd, 0, 15, 0.4379);
rev_chrds[1] = 1.1 * this.chrdcrev[3].process(hichrd, 8, 15, 0.4371);
// the sum chords stumming + slow, narrow the width will add competition for the dr+bass line
rev_chrds = this.stfltr[3].stwidth(rev_chrds, max(.7, smoothstep(0, 1, mod(.333 * time, 3.))));
rev_chrds[0] += .6 * this.chrdcrev[0].process(lwchrd, 0, 30, 0.439);
rev_chrds[1] += .6 * this.chrdcrev[1].process(lwchrd, 8, 30, 0.439);
// animated stereo width strumming chrods
rev_chrds = this.fltr.stwidth(rev_chrds, min(.96, max(.7, smoothstep(0, 1, mod((1./12) * time, 1.)))));
rev_chrds[0] = 0.18 * rev_chrds[0] + drysynthsum;
rev_chrds[1] = 0.18 * 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);