Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save transat/8bdf1624bbbc5b653651 to your computer and use it in GitHub Desktop.
Save transat/8bdf1624bbbc5b653651 to your computer and use it in GitHub Desktop.
[Autoplaying Audio] Playing with Web Audio & Canvas

[Autoplaying Audio] Playing with Web Audio & Canvas

I was working on an audio visualization animation at work and discovered the amazing, yet scary, Web Audio API for such a purpose.

I made this visualization with an inaccurate IE fallback that inserts an audio element on the page and generates a random waveform as the sound plays. There is also an event listener to play the default sound and animation on iOS devices that don't allow autoplay onload.

I took what I learned from that and made a simple demo. A full write-up should be published in the near future.

A Pen by Nick Hehr on CodePen.

License.

<div id="space">
<header>
<h1>Playing with Web Audio & Canvas</h1>
<h2>A Pen by Hipsterbrown</h2>
</header>
<article class="content">
<p>The Web Audio API is a tricky beast. It has no support in any version of IE and a really funky bunch of methods & properties to learn in order to use it. Those with some background knowledge is audio engineering may be able to make heads or tails of what is going on behind the scenes, but finding relevant and useful articles on how the Web Audio API works will be difficult for most. </p>
</article>
<canvas id="soundBar"></canvas>
</div>
// Cross-Browser check for the Web Audio API
var AudioContext = window.AudioContext || window.webkitAudioContext;
// shim layer with setTimeout fallback
window.requestAnimFrame = (function(){
'use strict';
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
document.addEventListener('DOMContentLoaded', function(){
'use strict';
var space = document.getElementById('space');
var shakeItBuffer = null;
var analyzer;
var bufferLength;
var dataArray;
var animateVisual = null;
var canvas = document.getElementById('soundBar');
var drawCtx = canvas.getContext('2d');
var WIDTH = space.getBoundingClientRect().width;
var HEIGHT = 100;
canvas.width = WIDTH;
canvas.height = HEIGHT;
function animate() {
animateVisual = requestAnimFrame(animate);
analyzer.getByteTimeDomainData(dataArray);
drawCtx.fillStyle = '#ecdfc8';
drawCtx.fillRect(0, 0, WIDTH, 100);
drawCtx.lineWidth = 6;
drawCtx.strokeStyle = '#093c4f';
drawCtx.beginPath();
var sliceWidth = WIDTH * 0.8 / bufferLength;
var x = 0;
var y;
for(var i = 0; i < bufferLength; i++) {
var v = dataArray[i] / 80.0;
y = v * HEIGHT / 3;
if(i === 0) {
drawCtx.moveTo(x, 53);
x = WIDTH / 9;
} else {
drawCtx.lineTo(x, y);
}
x += sliceWidth;
}
drawCtx.lineTo(canvas.width, 53);
drawCtx.stroke();
}
var fbRAF = null;
function fallBack() {
var audioEl = document.createElement('audio');
audioEl.src = 'BYC.mp3';
modal.appendChild(audioEl);
audioEl.addEventListener('canplaythrough', function(){
audioEl.play();
fbAnim();
});
audioEl.addEventListener('ended', function(){
window.cancelAnimationFrame(fbRAF);
drawCtx.fillStyle = '#ecdfc8';
drawCtx.fillRect(0, 0, WIDTH, 100);
drawCtx.lineWidth = 6;
drawCtx.strokeStyle = '#093c4f';
drawCtx.beginPath();
drawCtx.moveTo(0, 53);
drawCtx.lineTo(canvas.width, 53);
drawCtx.stroke();
});
}
function fbAnim() {
fbRAF = requestAnimFrame(fbAnim);
var len = 140;
var slice = WIDTH * 0.8 / len;
var X = 0;
drawCtx.fillStyle = '#ecdfc8';
drawCtx.fillRect(0, 0, WIDTH, 100);
drawCtx.lineWidth = 6;
drawCtx.strokeStyle = '#093c4f';
drawCtx.beginPath();
drawCtx.moveTo(0, 53);
X = WIDTH / 9;
drawCtx.lineTo(X, 53);
for(var f = 0; f < len; f++) {
var mix = Math.random() < 0.5 ? 1 : -1;
var Y = getRandomInt(60, 30);
console.log(mix, Y);
drawCtx.lineTo(X, Y);
X += slice;
}
drawCtx.lineTo(X, 53);
drawCtx.lineTo(canvas.width, 53);
drawCtx.stroke();
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
function playSound(buffer) {
analyzer = audio.createAnalyser();
analyzer.smoothingTimeConstant = 0.8;
analyzer.fftSize = 2048;
analyzer.connect(audio.destination);
bufferLength = analyzer.frequencyBinCount;
dataArray = new Uint8Array(bufferLength);
analyzer.getByteTimeDomainData(dataArray);
var src = audio.createBufferSource();
src.buffer = buffer;
src.connect(analyzer);
src.connect(audio.destination);
if ('ontouchstart' in window) {
space.addEventListener('touchstart', function(){
src.connect(audio.destination);
src.start(0);
});
animate();
} else {
src.start(0);
animate();
}
}
function loadShakeItSound(url) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
// Decode asynchronously
request.onload = function() {
audio.decodeAudioData(request.response, function(buffer) {
shakeItBuffer = buffer;
playSound(shakeItBuffer);
}, function(err) {
console.log('Error loading sound: ', err);
});
};
request.send();
}
if (!!AudioContext) {
var audio = new AudioContext();
loadShakeItSound('https://s3-us-west-2.amazonaws.com/s.cdpn.io/46323/ShakeItOff.m4r');
} else {
fallBack();
return;
}
}, false);
@import "bourbon";
// Demo Styles Settings
$brown: #bfb199;
$dark-blue: #093c4f;
$light-blue: #b8fef7;
$tan: #ecdfc8;
$body-bg: $brown;
$main-bg: $tan;
$main-color: $dark-blue;
$sans: 'Avenir Next', 'Avenir', 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif;
$main-font: $sans;
h1, h2, p {
margin: 0;
padding: 0;
}
body {
background: $body-bg;
}
#space {
background: $main-bg;
color: $main-color;
font-family: $main-font;
left: 50%;
min-width: em(300px);
padding: 5% 3%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
width: 75%
}
header {
margin-bottom: 1em;
}
h1 {
font-size: 300%;
font-size: 3vw;
letter-spacing: 0.05em;
line-height: 1em;
margin: 0;
text-transform: uppercase;
}
h2 {
font-size: 150%;
font-size: 2vw;
font-weight: 600;
letter-spacing: 0.025em;
}
p {
font-size: 1.2em;
margin: 0;
padding-bottom: 4em;
}
#soundBar {
bottom: 0;
height: 100;
left: 0;
position: absolute;
width: 100%;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment