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