xxxxxxxxxx
359
// Real-time Monstercat visualizer using IIR filter banks
// audio vars
var audioCtx = new AudioContext();
var analyser = audioCtx.createAnalyser();
addEventListener('click', () => {
if (audioCtx.state === 'suspended')
audioCtx.resume();
});
var bands = [];
var filterBank = [];
var filterBank2 = [];
var filterBank3 = [];
var filterBank4 = [];
var filterBank5 = [];
var spectrum = [];
var spacing = 1/12;
analyser.fftSize = 512; // [32, 64, 128, 256, 512, 1024, 2048]
var dataArrays = new Float32Array(analyser.fftSize);
var dataArray = new Uint8Array(analyser.frequencyBinCount);
/*for (var i = Math.round(Math.log2(20) / spacing) * spacing; i < Math.round(Math.log2(20000) / spacing) * spacing; i += spacing) {
bands.push(Math.pow(2, i));
}*/
//var octaveBands = [];
var freq = 0;
var root24 = 2 ** ( 1 / 24 );
var c0 = 440 * root24 ** -114;
let i = 0;
while ((freq = c0 * root24 ** i) <= 20000) {
if (freq >= 20 && i % 4 == 0)
bands.push(freq);
i++;
}
for ( i = 0; i < bands.length; i++ ) {
const gamma = 1/0.00437,
q = bands[i]/(bands[i]+gamma)*6;
filterBank.push(audioCtx.createBiquadFilter());
filterBank[i].frequency.value = bands[i];
filterBank[i].type = 'bandpass';
filterBank[i].Q.value = q;
filterBank2.push(audioCtx.createBiquadFilter());
filterBank2[i].frequency.value = bands[i];
filterBank2[i].type = 'bandpass';
filterBank2[i].Q.value = q;
filterBank3.push(audioCtx.createBiquadFilter());
filterBank3[i].frequency.value = bands[i];
filterBank3[i].type = 'bandpass';
filterBank3[i].Q.value = q;
filterBank4.push(audioCtx.createBiquadFilter());
filterBank4[i].frequency.value = bands[i];
filterBank4[i].type = 'bandpass';
filterBank4[i].Q.value = q;
filterBank5.push(audioCtx.createBiquadFilter());
filterBank5[i].frequency.value = bands[i];
filterBank5[i].type = 'bandpass';
filterBank5[i].Q.value = 0;
spectrum.push(audioCtx.createAnalyser());
spectrum[i].fftSize = analyser.fftSize;
spectrum[i].smoothingTimeConstant = 0;
}
function normalize(val, min, max) {return (val - min) / ( max - min );}
// canvas vars
var canvas = document.querySelector("canvas");
ctx = canvas.getContext("2d");
var cw = (canvas.width = window.innerWidth);
var ch = (canvas.height = window.innerHeight);
var requestId = null;
// points array
var points = [];
var pNum = spectrum.length;
var pointW = cw / pNum;
/*https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia*/
navigator.mediaDevices
.getUserMedia({ audio: {noiseCancellation: false, echoCancellation: false, autoGainControl: false}, video: false })
.then(function(stream) {
var audioSource = audioCtx.createMediaStreamSource(stream);
audioSource.connect(analyser);
for (var i = 0; i < bands.length; i++) {
audioSource.connect(filterBank[i]);
filterBank[i].connect(filterBank2[i]);
filterBank2[i].connect(filterBank3[i]);
filterBank3[i].connect(filterBank4[i]);
filterBank4[i].connect(filterBank5[i]);
filterBank5[i].connect(spectrum[i]);
}
Draw();
})
.catch(function(err) {
txt("E R R O R");
});
init();
window.onresize = init;
function Draw() {
requestId = window.requestAnimationFrame(Draw);
analyser.getByteFrequencyData(dataArray);
ctx.clearRect(0, 0, cw, ch);
var n = ~~(analyser.frequencyBinCount / pNum);
var barHeight = 0;
/*for (var i = 0; i < points.length; i++) {
points[i].y = ch - dataArray[i * n] - 50;
}*/
ctx.fillStyle = "hsla(210,95%,45%,.75)";
for (var i = 0; i < spectrum.length; i++) {
spectrum[i].getFloatTimeDomainData(dataArrays);
barHeight = 0;
for (var j = 0; j < spectrum[i].fftSize; j++) {
barHeight += Math.abs(dataArrays[j]);
}
barHeight = barHeight / spectrum[i].fftSize;
//barHeight = 20*Math.log10(barHeight);
/*if (barHeight > points[i].peak) {
points[i].peak = barHeight;
}*/
//barHeight = points[i].peak;
barHeight = normalize(barHeight, 0, 0.01);
ctx.fillRect(i * (cw / spectrum.length), ch, (cw / spectrum.length) - 1, -Math.max(barHeight, 0)*ch);
//points[i].peak -= 1;
}
//drawCurves(points);
//txt("Make Some Noise");
}
function drawCurves(points) {
ctx.beginPath();
ctx.moveTo(points[0].x, points[0].y);
for (var i = 1; i < points.length - 2; i++) {
var cp = {};
cp.x = (points[i].x + points[i + 1].x) / 2;
cp.y = (points[i].y + points[i + 1].y) / 2;
ctx.quadraticCurveTo(points[i].x, points[i].y, cp.x, cp.y);
}
ctx.quadraticCurveTo(
points[i].x,
points[i].y,
points[i + 1].x,
points[i + 1].y
);
ctx.lineTo(cw, ch);
ctx.lineTo(0, ch);
ctx.closePath();
ctx.fill();
}
function init() {
/*if (requestId) {
window.cancelAnimationFrame(requestId);
requestId = null;
}*/
cw = canvas.width = window.innerWidth;
ch = canvas.height = window.innerHeight;
points.length = 0;
pointW = cw / pNum;
for (var i = 0; i < pNum; i++) {
var point = {};
point.x = i * pointW;
point.y = ch;
point.peak = -Infinity;
points.push(point);
}
//Draw();
}
/*window.setTimeout(function() {
init();
addEventListener("resize", init, false);
}, 15);*/
function txt(mensaje) {
var t = mensaje.split("").join(" ");
ctx.font = "1.5em Lucida Console";
ctx.textAlign = "center";
ctx.fillText(t, cw * 0.5, ch * 0.5);
}