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,...