Richeh adapting to change

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);