Superposition, baby!
A Pen by Riley Shaw on CodePen.
canvas | |
p loading audio... |
!function () { | |
// play with these | |
var MIN_RADIUS = 100; | |
var JITTER_RANGE = 35; | |
var HEIGHT = 100; | |
var RESOLUTION = 2; // one point every 2 | |
var NUM_NODES = 512; // only 1/2 of these are actually drawn | |
var COLOR = [255, 255, 255]; | |
// derived | |
var CENTER = HEIGHT / 2; | |
// math | |
var PI2 = Math.PI * 2; | |
var sin = Math.sin; | |
var cos = Math.cos; | |
// canvas | |
var canvas = document.querySelector('canvas'); | |
var ctx = canvas.getContext('2d'); | |
canvas.height = HEIGHT; | |
canvas.width = NUM_NODES; | |
// main loop | |
function animate (analyser, SAMPLE_RATE) { | |
var binCount = analyser.frequencyBinCount; | |
var freqArray = new Uint8Array(binCount); | |
!function draw () { | |
analyser.getByteFrequencyData(freqArray); | |
ctx.beginPath(); | |
ctx.strokeStyle = 'rgb(' + COLOR + ')'; | |
ctx.lineWidth = 2; | |
for (var t = 0, node; t < binCount; t += RESOLUTION) { | |
node = 0; | |
for (var i = 0, f, A; i < binCount; ++i) { | |
f = i * SAMPLE_RATE / NUM_NODES; | |
A = freqArray[i]; | |
node += A * sin(PI2 * f * t); | |
} | |
ctx.lineTo(t, CENTER + node / NUM_NODES * HEIGHT / 8); | |
} | |
// close the loop and draw the stroke | |
ctx.clearRect(0, 0, NUM_NODES, HEIGHT); | |
ctx.stroke(); | |
requestAnimationFrame(draw); | |
}(); | |
} | |
function loadSound (url, cb) { | |
var request = new XMLHttpRequest(); | |
request.open('GET', url, true); | |
request.responseType = 'arraybuffer'; | |
request.onload = function () { cb(request.response); }; | |
request.send(); | |
} | |
// load the mp3 and initialize our visualizer | |
loadSound('//katiebaca.com/tutorial/odd-look.mp3', function (res) { | |
var audioContext = new (window.AudioContext || window.webkitAudioContext)(); | |
var SAMPLE_RATE = audioContext.sampleRate; | |
audioContext.decodeAudioData(res, function (buffer) { | |
var analyser = audioContext.createAnalyser(); | |
var sourceNode = audioContext.createBufferSource(); | |
analyser.smoothingTimeConstant = 0.6; | |
analyser.fftSize = NUM_NODES * 2; | |
analyser.minDecibels = -90; | |
analyser.maxDecibels = -10; | |
sourceNode.buffer = buffer; | |
analyser.connect(audioContext.destination); | |
sourceNode.connect(analyser); | |
sourceNode.start(0); | |
animate(analyser, SAMPLE_RATE); | |
// add play/pause control | |
var playing = true; | |
var control = document.querySelector('p'); | |
control.className = 'fa fa-pause'; | |
control.textContent = ''; | |
canvas.addEventListener('click', function () { | |
sourceNode[(playing ? 'dis' : '') + 'connect'](analyser); | |
control.className = 'fa fa-' + (playing ? 'play' : 'pause'); | |
playing = !playing; | |
}, false); | |
}); | |
}); | |
}(); |
body | |
background: #000 | |
canvas, p | |
position: absolute | |
top: 50% | |
left: 50% | |
transform: translate(-50%, -50%) | |
canvas | |
cursor: pointer | |
&:hover + p.fa | |
display: block | |
p | |
pointer-events: none | |
margin: 0 | |
font-family: monospace | |
color: #fff | |
background: #000 | |
&.fa-play | |
padding-left: 0.8em | |
&.fa | |
display: none | |
padding: 0.6em | |
border: 4px solid #fff | |
border-radius: 50% | |
font-size: 24px | |
Superposition, baby!
A Pen by Riley Shaw on CodePen.