JSFiddle - React, Tailwind, and code Playground

KS synth

by yonatan

HTML

<canvas id="canvas"></canvas>
frequency
<input id="ifreq" type="number" value="110"> Q
<input id="q" type="number" value=".5">

CSS

canvas {
  background: #fff;
  width: 100%;
}

JavaScript

let audioBufSize = 4096;
let ac = new AudioContext;

// oscilloscope
let scope = ac.createScriptProcessor(audioBufSize, 1, 1);
let ctx = canvas.getContext('2d');
scope.onaudioprocess = function(e) {
  let buff = e.inputBuffer.getChannelData(0);
  canvas.width = audioBufSize / 4;
  canvas.height = audioBufSize / 8;
  for (let i = 0; i < audioBufSize; i++) {
    let x = i / audioBufSize * canvas.width;
    let y = (buff[i] / 2 + .5) * canvas.height;
    ctx.lineTo(x, y);
  }
  ctx.stroke();
}

function ks(ctx, freqSeq, bowSeq, dampSeq) {
  let syn = ac.createScriptProcessor(audioBufSize, 1, 1);
  let ksBuf = [];
  //for (let i = 0; i < ksBufLen; i++) ksBuf[i] = 0;
  let ksBufIdx = 0;
  let ksMix = .99;
  let out, last = 0,
    cnt = 0,
    a0 = 0,
    a1 = 0,
    a2 = 0,
    b1 = 0,
    b2 = 0,
    z1 = 0,
    z2 = 0;
  syn.onaudioprocess = function(e) {
    let output = e.outputBuffer.getChannelData(0);
    for (let i = 0; i < audioBufSize; i++) {
      let freq = freqSeq(cnt);
      let Fc = freq / 44100;
      let Q = q.value;

      let K = Math.tan(Math.PI * Fc);
      let norm = 1 / (1 + K / Q + K * K);
      // calc bandpass params
      a0 = K / Q * norm;
      a1 = 0;
      a2 = -a0;
      b1 = 2 * (K * K - 1) * norm;
      b2 = (1 - K / Q + K * K) * norm;

      let ksBufLen = 44100 / freq;
      if (++ksBufIdx >= ksBufLen) {
        ksBuf[ksBufIdx | 0] = ksBuf[(ksBufIdx %= ksBufLen) | 0]; // avoid leftover ringing
      }
      let input = bowSeq(cnt) * (Math.random() * 2 - 1);
      let damp = dampSeq(cnt);
      let hist = ksBuf[ksBufIdx | 0] || 0;
      let val = input;
      out = val * a0 + z1;
      z1 = val * a1 + z2 - b1 * out;
      z2 = val * a2 - b2 * out;
      out = out * (1 - ksMix) + (hist * ksMix);
      out = out * (1-damp) + last * damp;
      output[i] = ksBuf[ksBufIdx | 0] = last = out;
      output[i] *= 16;
      cnt++;
    }
  }
  return syn;
}
let syn = ks(ac, t=>t&0x8000?183.33:110, t=>t&0x4000?0:1, t=>.1)
let syn2 = ks(ac,...