JSFiddle - React, Tailwind, and code Playground

by Santiago J

HTML

<h4>Frequency</h4>
<canvas id="fft-graph"></canvas>

<dl>
  <dt>Oscillator Frequency: <span id="oscf-disp"></span></dt>
  <dd><input id="oscf-slider" type="range"></dd>
</dl>

CSS

body {
  background-color: #333;
  color: #eee;
  font-family: Verdana, sans-serif;
  font-size: 0.9em;
}
canvas {
  background-color: #111;
}

JavaScript

/// Silly polyfilling
window.AudioContext = window.AudioContext || window.webkitAudioContext;
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;

/// Util functions
// query selector helper
function $(s,a,p) {
    if (typeof s !== "string") return s;
    p = p || document;
    return a ? p.querySelectorAll(s) : p.querySelector(s);
}
// sum the numbers in an array slice
function sumSlice(arr, a, b) {
    var sum = 0;
    for (var i = a; i < b; i++) {
        sum += arr[i];
    }
    return sum;
}
// graph a buffer on a given 2d canvas context
function graphBuffer(ctx, buff) {
    var n = buff.length,
        h = ctx.canvas.height;
    ctx.clearRect(0, 0, ctx.canvas.width, h);
    for (var i = 0; i < n; i++) {
        ctx.fillRect(i, h - buff[i] - 1, 1, buff[i]+1);
    }
}
// create a slider
function setInputChangeFn(sel, fn, val) {
    var el = $(sel);
    el.addEventListener("change", fn, false);
    if (val) el.value = val;
    fn.call(el);
}

/// Set up us the canvas
var ctxfft = $("#fft-graph").getContext("2d"); // (not jQuery)
ctxfft.canvas.width = 1024; // half the fftSize
ctxfft.canvas.height = 256;
ctxfft.fillStyle = "#9c3";

/// Set up us the audio
(function() {
    if (typeof AudioContext !== "function") {
        throw new Error("AudioContext not supported!");
    }
    
    /* Graph:
        microphone -->- analyser (-->- modify gains[] params)

        oscillator -->- filters[] -->- gains[] -->- output
        
        (note: filters are 2nd order)
    */

    /// Graph nodes
    var
    mic,       // MediaStreamAudioSourceNode
    context    = new AudioContext,
    analyser   = context.createAnalyser(),
    gainNodes  = [],
    filters1   = [],
    filters2   = [],
    oscillator = context.createOscillator();


    /// Analyser (FFT) config
    analyser.fftSize = 2048; // fun fact: 2048 == 0x800
    analyser.smoothingTimeConstant = 0.65;
    var fftBuffer = new Uint8Array(analyser.frequencyBinCount);


    /// Vocoder...