Skip to content

Instantly share code, notes, and snippets.

@hjoseph96
Created January 1, 2016 16:00
Show Gist options
  • Save hjoseph96/2fe03fddee5cc6f6ded1 to your computer and use it in GitHub Desktop.
Save hjoseph96/2fe03fddee5cc6f6ded1 to your computer and use it in GitHub Desktop.
Visualizr
<div class="visualizr">
<div class="controls">
<div class="field">
<label for="width">Width</label>
<input type="range" name="width" value="20">
</div>
<div class="field">
<label for="height">Height</label>
<input type="range" name="height" value="50">
</div>
<div class="field">
<label for="gap">Gap</label>
<input type="range" name="gap" value="25">
</div>
<div class="field">
<label for="delay">Delay</label>
<input type="range" name="delay" value="8">
</div>
<div class="field">
<label for="hue">Hue Offset</label>
<input type="range" name="hue" value="0">
</div>
<div class="field">
<label style="margin-right:1em">Animate</label>
<input type="radio" name="animate" value="out" checked> <span>Out</span>
<input type="radio" name="animate" value="in"> <span>In</span>
<input type="radio" name="animate" value="auto"> <span>Auto</span>
</div>
<div class="field">
<label>Delay</label>
<input type="range" name="auto-delay" value="50">
</div>
</div>
<button class="playpause"></button>
<canvas></canvas>
</div>
window.addEventListener( 'load', init, false );
var context;
var $body = $( 'body' );
var playing = false;
var songSource = null;
var songBuffer = null;
var startOffset = 0;
var startTime = 0;
var analyser;
var canvas = $( 'canvas' )[ 0 ];
var ctx = canvas.getContext( '2d' );
var bars = Array( 300 );
var forward = true;
// Settings
var globalHash;
var hash = globalHash = getHash();
if ( hash.hide_controls ) {
$( '.controls' ).addClass( 'hide' );
}
if ( hash.small ) {
$body.addClass( 'small' );
}
console.log( hash );
var barCount = 60;
var lineWidth = hash.width || 10;
var lineGap = hash.gap || 10;
var heightFactor = hash.height || 5;
var delay = hash.delay || 10;
var animate = hash.animate || 'out';
var animateSwitch = hash.auto_delay || 5 * 1000;
var hue = hash.hue || 0;
var songUrl = hash.song ?
'https://s3.amazonaws.com/tybenz.assets/visualizr/' + hash.song + '.mp3' :
"https://dl.dropboxusercontent.com/u/15727879/T4IgFQfHfPFO.128.mp3";
var songName = hash.song || 'do_it_like';
var $out = $( '[name=animate][value=out]' );
var $in = $( '[name=animate][value=in]' );
var $auto = $( '[name=animate][value=auto]' );
var $hue = $( '[name=hue]' );
var $delay = $( '[name=delay]' );
var $width = $( '[name=width]' );
var $height = $( '[name=height]' );
var $gap = $( '[name=gap]' );
var $autoDelay = $( '[name=auto-delay]' );
function init() {
try {
window.AudioContext = window.AudioContext || window.webkitAudioContext;
context = new AudioContext();
resize();
$( window ).on( 'resize', resize );
flip();
loadSong( songUrl );
} catch ( err ) {
console.error( 'Web Audio API is not supported in this browser' );
}
}
function flip() {
if ( animate == 'auto' ) {
if ( forward ) {
forward = false;
} else {
forward = true;
}
}
setTimeout( flip, animateSwitch );
}
function loadSong( url ) {
var request = new XMLHttpRequest();
request.open( 'GET', url, true );
request.responseType = 'arraybuffer';
request.onload = function() {
context.decodeAudioData( request.response, function( buffer ) {
songBuffer = buffer;
analyser = context.createAnalyser();
analyser.smoothingTimeConstant = 0.3;
analyser.fftSize = 1024;
$body.addClass( 'loaded' );
update();
play();
}, onError );
}
request.send();
}
function resize( evt ) {
var $win = $( window );
var winWidth = $win.width();
var winHeight = $win.height();
barCount = ( winWidth / ( lineWidth * 2 ) ) / 2;
canvas.width = winWidth;
canvas.height = winHeight;
}
function update() {
// get the average, bincount is fftsize / 2
var array = new Uint8Array( analyser.frequencyBinCount );
analyser.getByteFrequencyData( array );
var average = getAverageVolume( array );
var average = average * heightFactor;
bars[ 0 ] = average;
average *= 0.8;
if ( playing ) {
var reduce = 0;
for ( var i = 1; i < barCount; i++ ) {
average = average - Math.sqrt( average ) + 1;
if ( average < 0 ) {
average = 0;
}
(function( i, average ) {
setTimeout( function() {
bars[ i ] = average;
}, delay * ( forward ? i : 60 - i ) );
})( i, average );
}
}
draw();
updateHash();
requestAnimationFrame( update );
}
function draw() {
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
// clear the current state
ctx.clearRect( 0, 0, canvasWidth, canvasHeight );
// set the fill style
var average = bars[ 0 ];
var color = getColor( average );
rect( ( canvasWidth / 2 ) - ( lineWidth / 2 ), ( canvasHeight / 2 ) - ( average / 2 ), lineWidth, average, color );
for ( var i = 1; i < barCount; i++ ) {
var average = bars[ i ];
color = getColor( average );
if ( average === undefined || average <= 0 ) {
average = 0;
} else {
rect( ( canvasWidth / 2 ) - ( lineWidth / 2 ) + ( ( lineWidth + lineGap ) * i ), ( canvasHeight / 2 ) - ( average / 2 ), lineWidth, average, color );
rect( ( canvasWidth / 2 ) - ( lineWidth / 2 ) - ( ( lineWidth + lineGap ) * i ), ( canvasHeight / 2 ) - ( average / 2 ), lineWidth, average, color );
}
}
}
var originalColors = [
'#333',
'purple',
'magenta',
'pink',
'red',
'orange',
'yellow',
'green',
'cyan',
'blue'
];
var colors = _.extend( [], originalColors );
function getColor( val ) {
// account for hue index
if ( hue == 0 ) {
colors = _.extend( [], originalColors );
for ( var i = 0; i < hue; i++ ) {
colors.unshift( colors.pop() );
}
var whiteIndex = colors.indexOf( '#333' );
colors.splice( whiteIndex, 1 );
colors.unshift( '#333' );
} else {
colors = Array( 10 );
colors[ 0 ] = '#333';
var lightness = 49;
for ( var i = 9; i >= 1; i-- ) {
colors[ i ] = 'hsl(' + hue + ', 100%, ' + lightness + '%)'
lightness -= 5;
}
}
var colorIndex = Math.floor( val / ( 10 * heightFactor ) );
if ( colorIndex > 9 ) {
colorIndex = 9;
} else if ( colorIndex < 0 ) {
colorIndex = 0;
}
return colors[ colorIndex ];
}
function rect( x, y, width, height, color ) {
ctx.save();
ctx.beginPath();
ctx.rect( x, y, width, height );
ctx.stroke();
ctx.clip();
ctx.fillStyle = color;
ctx.fillRect( 0,0,canvas.width,canvas.height );
ctx.restore();
}
function getAverageVolume( array ) {
var values = 0;
var average;
var length = array.length;
// get all the frequency amplitudes
for ( var i = 0; i < length; i++ ) {
values += array[ i ];
}
average = values / length;
return average;
}
function play() {
startTime = context.currentTime;
songSource = context.createBufferSource();
songSource.connect( analyser );
songSource.buffer = songBuffer;
songSource.connect( context.destination );
songSource.loop = true;
songSource.start( 0, startOffset % songBuffer.duration );
togglePlaying();
}
function stop() {
songSource.stop( 0 );
startOffset += context.currentTime - startTime;
togglePlaying();
}
function togglePlaying() {
if ( playing ) {
$body.removeClass( 'playing' );
playing = false;
} else {
$body.addClass( 'playing' );
playing = true;
}
}
function updateHash() {
var props = [];
var hash = '';
hash = 'width=' + lineWidth + '&' +
'height=' + heightFactor + '&' +
'gap=' + lineGap + '&' +
'delay=' + delay + '&' +
'hue=' + hue + '&' +
'animate=' + animate + '&' +
'auto_delay=' + animateSwitch + '&' +
'song=' + songName + '&' +
'hide_controls=' + ( globalHash.hide_controls || 0 ) + '&' +
'small=' + ( globalHash.small || 0 );
if ( window.location.hash != hash ) {
window.location.hash = hash;
}
}
function getHash() {
return window.location.hash
.replace( /^\#/, '' )
.split( '&' )
.reduce( function( memo, keyVal ) {
var key = keyVal.split( '=' )[ 0 ];
var val = keyVal.split( '=' )[ 1 ];
if ( key != 'animate' && key != 'song' ) {
val = parseInt( val );
}
memo[ key ] = val;
return memo;
}, {} );
}
function onError( err ) {
console.error( err );
}
$( '.playpause' ).on( 'click', function() {
if ( playing ) {
stop();
} else {
play();
}
});
$out.on( 'click', function( evt ) {
if ( evt.currentTarget.checked ) {
forward = true;
animate = 'out';
}
});
$in.on( 'click', function( evt ) {
if ( evt.currentTarget.checked ) {
forward = false;
animate = 'in';
}
});
$auto.on( 'click', function( evt ) {
if ( evt.currentTarget.checked ) {
animate = 'auto';
}
})
$delay.on( 'input', function() {
var val = $delay.val();
// console.log( val * 1.2 );
delay = Math.floor( val * 1.2 );
});
$width.on( 'input', function() {
var winWidth = $( window ).width();
barCount = ( winWidth / ( lineWidth + lineGap ) ) / 2;
lineWidth = 1 + Math.floor( ( $width.val() / 2 ) );
});
$gap.on( 'input', function() {
lineGap = Math.floor( ( $gap.val() / 2.5 ) );
});
$height.on( 'input', function() {
heightFactor = 1 + ( $height.val() / 10 );
});
$autoDelay.on( 'input', function() {
animateSwitch = Math.floor( $autoDelay.val() / 10 ) * 1000;
})
$hue.on( 'input', function() {
// hue = Math.floor( $hue.val() / 10 );
hue = Math.floor( ( 361 * ( $hue.val() / 100 ) ) );
});
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://use.edgefonts.net/source-sans-pro:n2,i2,n3,i3,n4,i4,n6,i6,n7,i7,n9,i9.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
html {
box-sizing: border-box;
color: white;
font-family: 'source-sans-pro', sans-serif;
}
.controls {
z-index: 1;
position: absolute;
top: 50px;
right: 50px;
text-align: right;
}
.controls.hide {
display: none;
}
* {
box-sizing: inherit;
}
html, body {
height: 100%;
}
body {
margin: 0;
background: #111;
}
canvas {
display: block;
background: #111;
position: absolute;
top: 50%;
transform: translateY(-50%);
-webkit-transform: translateY(-50%);
}
.visualizr {
position: relative;
height: 100%;
}
.playpause {
z-index: 1;
position: absolute;
top: 50px;
left: 35px;
/* width: 35px; */
width: 48px;
height: 48px;
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center center;
background-image: url(https://s3.amazonaws.com/tybenz.assets/spinner.png);
-webkit-appearance: none;
background-color: transparent;
border: none;
outline: none;
cursor: pointer;
-webkit-animation: rotate .75s infinite linear;
-moz-animation: rotate .75s infinite linear;
animation: rotate .75s infinite linear;
}
.small .playpause {
width: 24px;
height: 24px;
}
@-webkit-keyframes rotate {
from {-webkit-transform: rotate(0deg);}
to {-webkit-transform: rotate(-360deg);}
}
@-moz-keyframes rotate {
from {-moz-transform: rotate(0deg);}
to {-moz-transform: rotate(-360deg);}
}
@keyframes rotate {
from {transform: rotate(0deg);}
to {transform: rotate(-360deg);}
}
.playing .playpause {
background-image: url(https://s3.amazonaws.com/tybenz.assets/pause.png) !important;
}
.loaded .playpause {
width: 35px;
height: 48px;
background-image: url(https://s3.amazonaws.com/tybenz.assets/play.png);
background-position: center center;
color: transparent;
-webkit-animation: none;
-moz-animation: none;
animation: none;
top: 50px;
left: 50px;
}
.small.loaded .playpause {
width: 17px;
height: 24px;
}
.controls {
font-size: 0.8em;
font-weight: 100;
}
input[type=range] {
position: relative;
top: 4px;
}
.field {
margin-bottom: 0.4em;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment