Sonogram
by Licson Lee
HTML
<canvas id="screen"></canvas>
<a class="start-btn" href="#">▶ Play</a>
CSS
body {
margin: 0;
padding: 0;
outline: none;
background: #000;
}
canvas#screen {
position: absolute;
top: 0;
left: 0;
}
.start-btn {
display: block;
position: absolute;
left: calc(50vw - 45px);
top: calc(50vh - 15px);
width: 90px;
height: 30px;
background: #eee;
color: #000;
font-size: 22px;
font-family: Consolas, Courier, sans-serif;
text-align: center;
}
JavaScript
class Sonogram {
constructor(canvasSel) {
this.canvasEl = document.querySelector(canvasSel);
this.tmpCanvas = document.createElement('canvas');
this.gctx = this.canvasEl.getContext('2d');
this.tctx = this.tmpCanvas.getContext('2d');
this.actx = new AudioContext();
this.anodes = {
src: null,
analyser: null
};
this.buf = null;
this.freqBins = new Uint8Array(256);
this.loaded = false;
this.loadprogress = 0;
this.setupAudioRouting();
this.canvasEl.width = window.innerWidth;
this.canvasEl.height = window.innerHeight;
this.tmpCanvas.width = window.innerWidth;
this.tmpCanvas.height = window.innerHeight;
window.addEventListener('resize', () => {
this.canvasEl.width = window.innerWidth;
this.canvasEl.height = window.innerHeight;
this.tmpCanvas.width = window.innerWidth;
this.tmpCanvas.height = window.innerHeight;
}, false);
this.render();
}
load(url) {
this.loaded = false;
let xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';
xhr.onprogress = (e) => {
if (e.lengthComputable) {
this.loadprogress = (e.loaded / e.total);
}
}
xhr.onload = () => {
this.actx.decodeAudioData(xhr.response, (buffer) => {
this.buf = buffer;
this.loaded = true;
if (this.anodes.src) {
this.anodes.src.buffer = this.buf;
this.anodes.src.start(0);
}
});
}
xhr.open('GET', url);
xhr.send(null);
}
setupAudioRouting() {
let srcNode = this.actx.createBufferSource();
let analyserNode = this.actx.createAnalyser();
analyserNode.fftSize = 2048;
analyserNode.smoothingTimeConstant = 0.3;
analyserNode.maxDecibels = 0;
analyserNode.minDecibels = -65;
srcNode.loop = true;
srcNode.connect(analyserNode);
analyserNode.connect(this.actx.destination);
this.anodes.src = srcNode;
this.anodes.analyser =...