Skip to content

Instantly share code, notes, and snippets.

@patrickhulce
Created November 22, 2016 01:20
Show Gist options
  • Save patrickhulce/89ecda29dc2b3ab506db7d71d28d723f to your computer and use it in GitHub Desktop.
Save patrickhulce/89ecda29dc2b3ab506db7d71d28d723f to your computer and use it in GitHub Desktop.
JsAudioVisualization
// TAKEN FROM https://icanbeyourlighthouse.firebaseapp.com/
(function() {
'use strict';
class Loader {
constructor(url=null) {
this.url = url;
}
loadSound(url=this.url) {
return fetch(url).then(resp => resp.arrayBuffer());
}
}
class SoundFile {
constructor(url=null) {
this.audioCtx = new AudioContext();
this.loader = new Loader(url);
this.buffer = null;
}
load(url) {
if (this.buffer) {
return Promise.resolve(this.buffer);
}
return this.loader.loadSound(url)
.then(ab => this.audioCtx.decodeAudioData(ab))
.then(decodeBuffer => {
this.buffer = decodeBuffer;
return this.buffer;
});
}
play() {
this.source = this.audioCtx.createBufferSource();
this.analyser = this.audioCtx.createAnalyser();
this.analyser.fftSize = 2048;
this.source.connect(this.analyser);
this.analyser.connect(this.audioCtx.destination);
this.source.buffer = this.buffer;
this.source.start();
this.source.loop = true;
// this.source.loopStart = 0.24;
// this.source.loopEnd = 0.34;
}
stop() {
if (!this.source) {
return;
}
this.source.loop = false;
this.source.stop();
}
}
class Visualizer {
constructor(sound, canvas, fft = true) {
this.canvasCtx = canvas.getContext('2d');
this.sound = sound;
this._rafId = null;
this.fft = fft;
this.WIDTH = document.documentElement.clientWidth;
this.HEIGHT = document.documentElement.clientHeight;
canvas.width = this.WIDTH;
canvas.height = this.HEIGHT;
// canvas.width = this.WIDTH * devicePixelRatio;
// canvas.height = this.HEIGHT * devicePixelRatio;
// this.canvasCtx.scale(devicePixelRatio, devicePixelRatio);
}
stop() {
cancelAnimationFrame(this._rafId);
this.canvasCtx.clearRect(0, 0, this.WIDTH, this.HEIGHT);
}
_drawLineGraph(dataArray) {
const bufferLength = this.sound.analyser.frequencyBinCount;
const sliceWidth = this.WIDTH * 1.0 / bufferLength;
let x = 0;
for (let i = 0; i < bufferLength; i++) {
const v = dataArray[i] / 128.0;
const y = v * this.HEIGHT / 2;
if (i === 0) {
this.canvasCtx.moveTo(x, y);
} else {
this.canvasCtx.lineTo(x, y);
}
x += sliceWidth;
}
this.canvasCtx.stroke();
}
_drawBarGraph(dataArray) {
const bufferLength = this.sound.analyser.frequencyBinCount;
const barWidth = Math.ceil((this.WIDTH / bufferLength) * 3);
let x = 0;
for (let i = 0; i < bufferLength; ++i) {
let barHeight = dataArray[i] / 2;
this.canvasCtx.fillStyle = '#448aff';
this.canvasCtx.fillRect(x, this.HEIGHT - barHeight, barWidth, barHeight);
x += barWidth + 1;
}
this.canvasCtx.stroke();
}
draw() {
this._rafId = requestAnimationFrame(this.draw.bind(this));
const bufferLength = this.sound.analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
if (this.fft) {
sound.analyser.getByteFrequencyData(dataArray);
} else {
sound.analyser.getByteTimeDomainData(dataArray);
}
this.canvasCtx.clearRect(0, 0, this.WIDTH, this.HEIGHT);
this.canvasCtx.lineWidth = 2;
this.canvasCtx.strokeStyle = 'rgb(255, 255, 255)';
this.canvasCtx.beginPath();
// this._drawLineGraph(dataArray);
this._drawBarGraph(dataArray);
}
}
// const sound = new SoundFile('longer2.mp3');
const sound = new SoundFile('looped.mp3');
const visualizer = new Visualizer(sound, document.querySelector('canvas'));
function play(e) {
e.preventDefault();
sound.stop();
sound.load().then(buffer => {
document.body.classList.add('playing');
sound.play();
visualizer.draw();
});
}
function stop(e) {
e.preventDefault();
sound.load().then(buffer => {
document.body.classList.remove('playing');
sound.stop();
visualizer.stop();
});
}
function init() {
//const logo = document.querySelector('.logo img');
document.addEventListener('mousedown', play);
document.addEventListener('touchstart', play);
document.addEventListener('keydown', function(e) {
if (e.keyCode === 13) {
play(e);
}
});
document.addEventListener('mouseup', stop);
document.addEventListener('touchend', stop);
sound.load();
}
init();
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js', {scope: './'})
.then(registration => {
console.log('Service Worker Registered');
});
navigator.serviceWorker.ready.then(registration => {
console.log('Service Worker Ready');
});
// // SW is already registered, load sound immediately.
// if (navigator.serviceWorker.controller) {
// sound.load();
// }
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment