audio visualizer with canvas
Created
October 12, 2018 02:16
-
-
Save aahedi/c96f4c5eaaa5a3dee9d82047d02198e4 to your computer and use it in GitHub Desktop.
Staccato
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<body style='overflow: hidden;'> | |
<div style='z-index: -1; position: absolute; top: 0; left: 0'> | |
<canvas id='canvas'></canvas> | |
</div> | |
<span id='menu' style='display:;'> | |
<input type = 'button' value = 'Start' onclick = 'start();' /> | |
<input type = 'button' value = 'Stop' onclick = 'stop();' /> | |
<input type = 'button' value = 'Options' onclick = 'options();' /> | |
</span> | |
<input type = 'button' value = '<<' id = 'hider' onclick = 'menu();' /> | |
<br><br> | |
<div id='loading' style='background-color: white; display: none;'> | |
Loading Audio... | |
</div> | |
<div id = 'options' style = 'display: none; width: 200px; height: 500px; float: left; overflow-y: auto; background-color: white'> | |
Enter Url: | |
<input type = 'text' id = 'mp3url' /> | |
<br><br> | |
Choose File: | |
<input type="file" id="files" multiple/> | |
<br><br> | |
<div id='queue' style='display:none;'></div><br> | |
Preset: | |
<select id = 'preset'> | |
<option>Default</option> | |
<option>Floaty Snow</option> | |
<option>Rain</option> | |
<option>Waveform</option> | |
</select> | |
<br><br> | |
Draw Path: | |
<input type = 'checkbox' id = 'grow' /> | |
<br><br> | |
Bounce: | |
<input type = 'checkbox' id = 'bounce' /> | |
<br><br> | |
Mic Mode: | |
<input type = 'checkbox' id = 'mic' /> | |
<br><br> | |
Sort Shapes: | |
<input type = 'checkbox' id = 'sort' /> | |
<br><br> | |
Shape Mode: | |
<select id = 'shape'> | |
<option>Pill</option> | |
<option>Words</option> | |
</select> | |
<br><br> | |
<div id = 'wordsOptions' style = 'display: none;'> | |
Text to display:<br><br> | |
<textarea id = 'words'></textarea><br><br> | |
</div> | |
Direction: | |
<select id = 'direction'> | |
<option>Up</option> | |
<option>Down</option> | |
<option>Random</option> | |
</select> | |
<br><br> | |
Number of Shapes: | |
<input type = 'text' id = 'numShapes' size = '1' /> | |
<br><br> | |
Spread: | |
<input type = 'text' id = 'amp' size = '1' /> | |
<br><br> | |
Speed: | |
<input type = 'text' id = 'speedMin' size = '1' /> | |
- | |
<input type = 'text' id = 'speedMax' size = '1' /> | |
<br><br> | |
Spin: | |
<input type = 'text' id = 'spinMin' size = '1' /> | |
- | |
<input type = 'text' id = 'spinMax' size = '1' /> | |
<br><br> | |
Length: | |
<input type = 'text' id = 'sizeMin' size = '1' /> | |
- | |
<input type = 'text' id = 'sizeMax' size = '1' /> | |
<br><br> | |
Scale: | |
<input type = 'text' id = 'scaleMin' size = '1' /> | |
- | |
<input type = 'text' id = 'scaleMax' size = '1' /> | |
<br><br> | |
Opacity: | |
<input type = 'text' id = 'alphaMin' size = '1' /> | |
- | |
<input type = 'text' id = 'alphaMax' size = '1' /> | |
<br><br> | |
Dimension: | |
<input type = 'text' id = 'width' size = '1'/> | |
x | |
<input type = 'text' id = 'height' size = '1'/> | |
<br><br> | |
Background Color: | |
<input type='color' id='bgColor'/> | |
<br><br> | |
Colors: | |
<div id = 'colors'> | |
</div> | |
<input type='button' value='Add' onClick='addColor();'/> | |
</div> | |
<script src = 'staccato.js'></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var g, canvas; // canvas stuff | |
var visual; // intervals | |
var pills, words; // shape storage | |
var colorFields, color, BGCOLOR; // color options | |
var colorDef = [ // pretty colors | |
'#69D2E7', | |
'#1B676B', | |
'#BEF202', | |
'#EBE54D', | |
'#00CDAC', | |
'#1693A5', | |
'#F9D423', | |
'#FF4E50', | |
'#E7204E', | |
'#0CCABA', | |
'#FF006F' | |
]; | |
var AMP, SPEED, SPIN, SIZE, SCALE, NUM, DELAY, ALPHA; // init var | |
var GROW, DIRECTION, BOUNCE, TYPE, SORT; // selection choices | |
/* | |
AMP: amplitude of cos, determines how much shapes move side to side: the spread | |
SPEED: how fast it moves | |
SPIN: how fast it spins | |
SIZE: how long the shape is | |
SCALE: how big the shape is | |
NUM: number of shapes added per interval | |
DELAY: delay for adding new shapes | |
ALPHA: opacity levels: 0 - 1 | |
GROW: show as growing lines or just the shapes | |
DIRECTION: shapes move up/down/random | |
BOUNCE: shapes bounce off top/bottom | |
TYPE: type of shape: pill/word | |
*/ | |
var idx; // for words array | |
// audio | |
var audioCtx, audio, source, analyzer, MP3, dataArray, FILE, MIC, micAudio; | |
// mic access stuff | |
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia; | |
// audio source from microphone | |
// doesn't work yet | |
function AudioMic() { | |
if (navigator.getUserMedia) { | |
navigator.getUserMedia({audio: true}, function(stream) { | |
if (audioCtx == null) { | |
audioCtx = new (window.AudioContext || window.webkitAudioContext)(); | |
} | |
analyzer = audioCtx.createAnalyser(); | |
analyzer.fftsize = 512; | |
source = audioCtx.createMediaStreamSource(stream); | |
source.connect(analyzer); | |
source.connect(audioCtx.destination); | |
analyzer.connect(audioCtx.destination); | |
micAudio = new Recorder(audioCtx.createGain()); | |
micAudio.record(); | |
dataArray = new Uint8Array(analyzer.frequencyBinCount); | |
analyzer.getByteFrequencyData(dataArray); | |
}, function(e) { | |
alert('Give me access pls'); | |
}); | |
} | |
} | |
var files; | |
// audio from user inputed file | |
// click options -> choose file -> start -> wait a little bit for audio to load | |
// works bests with songs with lots volume variations or snare beats | |
// or pauses or else it might look like a lot of random pulsing pills | |
function audioFromFile() { | |
document.getElementById('queue').style = 'block'; | |
document.getElementById('queue').innerHTML = 'Queue: <br>'; | |
files = document.getElementById('files').files; | |
index = 0; | |
for (let i = 0, file; file = files[i]; i++) { | |
document.getElementById('queue').innerHTML += | |
"<span id='song" + i + "' style='color:black'>" + (i + 1) + '. ' + file.name.match(/(.+)\./)[1] + '</span><br>'; | |
} | |
playFromFile(); | |
} | |
// if you press start with a queue playing it overlaps, since previous queue is still active | |
function playFromFile() { | |
var reader = new FileReader(); | |
if (audioCtx == null) { | |
audioCtx = new (window.AudioContext || window.webkitAudioContext)(); | |
} | |
analyzer = audioCtx.createAnalyser(); | |
analyzer.fftsize = 512; | |
document.getElementById('loading').style.display = 'block'; | |
// creates audio source and analyzer from inputed file | |
reader.onload = function (e) { | |
audioCtx.decodeAudioData(e.target.result, function (buf) { | |
document.getElementById('loading').style.display = 'none'; | |
document.getElementById('song' + index).style.color = 'green'; | |
source = audioCtx.createBufferSource(); | |
source.connect(analyzer); | |
//source.connect(audioCtx.destination); // causes distortion | |
analyzer.connect(audioCtx.destination); | |
source.buffer = buf; | |
source.start(0); | |
source.onended = function() {// plays next song if any in queue | |
document.getElementById('song' + index).style.color = 'black'; | |
if (index !== files.length - 1) { | |
index++; | |
playFromFile(); | |
} | |
}; | |
}) | |
}; | |
reader.readAsArrayBuffer(files[index]); | |
dataArray = new Uint8Array(analyzer.frequencyBinCount); | |
analyzer.getByteFrequencyData(dataArray); // sets audio data | |
} | |
function AudioAnalyzer() { | |
if (audioCtx == null) { | |
audioCtx = new (window.AudioContext || window.webkitAudioContext)(); | |
} | |
analyzer = audioCtx.createAnalyser(); | |
analyzer.fftsize = 512; | |
audio = new Audio(MP3); | |
audio.crossOrigin = 'anonymous'; // for cors access | |
audio.controls = true; | |
// sets up sources from url | |
audio.addEventListener('canplay', function() { | |
source = audioCtx.createMediaElementSource(audio); | |
source.connect(analyzer); | |
source.connect(audioCtx.destination); | |
analyzer.connect(audioCtx.destination); | |
}); | |
dataArray = new Uint8Array(analyzer.frequencyBinCount); | |
analyzer.getByteFrequencyData(dataArray); // sets audio data | |
} | |
window.onload = function init() { | |
document.getElementById('width').value = window.innerWidth; | |
document.getElementById('height').value = window.innerHeight; | |
document.getElementById('options').style.height = window.innerHeight - 50; | |
colorFields = 0; | |
defCond(); | |
start(); | |
} | |
window.addEventListener('resize', function(){ | |
canvas.width = window.innerWidth; | |
canvas.height = window.innerHeight; | |
document.getElementById('options').style.height = window.innerHeight - 50; | |
}); | |
// display word text area on change | |
document.getElementById('shape').addEventListener('change', function () { | |
document.getElementById('wordsOptions').style.display = | |
this.value == "Words" ? 'block' : 'none'; | |
}); | |
// switches options to preset values | |
document.getElementById('preset').addEventListener('change', function () { | |
switch(this.value) { | |
case "Floaty Snow": | |
floatySnow(); | |
break; | |
case "Rain": | |
rain(); | |
break; | |
case "Waveform": | |
waveform(); | |
break; | |
default: | |
defCond(); | |
} | |
}); | |
// adds more color options | |
function addColor() { | |
var newColorField = document.createElement('div'); | |
newColorField.innerHTML = | |
"<input type='color' value='#0000FF' id='color" + colorFields + | |
"' /><input type='button' id='button" + colorFields + | |
"' value='Remove' onClick='this.parentNode.parentNode.removeChild(this.parentNode);'/>"; | |
colorFields++; | |
document.getElementById('colors').appendChild(newColorField); | |
} | |
// start animation | |
function start() { | |
stop(); // stops previous plays so nothing messes up | |
document.getElementById('width').value = window.innerWidth; | |
document.getElementById('height').value = window.innerHeight; | |
document.getElementById('options').style.height = window.innerHeight - 50; | |
getCond(); | |
if (audio == null && !FILE && !MIC) { // audio from url | |
AudioAnalyzer(); | |
} | |
if (!FILE && !MIC) { // adds audio player to screen and starts audio | |
document.body.appendChild(audio); | |
audio.play(); | |
} | |
document.getElementById('canvas').style.background = BGCOLOR; | |
// sets words for word shapes; default: butts | |
if (TYPE == 'word') { | |
words = document.getElementById('words').value != "" ? | |
document.getElementById('words').value.split(" ") : ["butts"]; | |
idx = 0; | |
} | |
var pill; | |
pills = []; | |
// init canvas | |
canvas = document.getElementById('canvas') | |
canvas.width = toNum(document.getElementById('width').value, window.innerWidth); | |
canvas.height = toNum(document.getElementById('height').value, window.innerHeight); | |
g = canvas.getContext('2d'); | |
g.setTransform(1, 0, 0, 1, 0, 0); | |
if (!SORT) { | |
addP(); | |
} else { | |
addSorted(); | |
} | |
if (visual == null) { | |
draw(); // start drawing | |
} | |
} | |
function addSorted() { | |
var pill, band; | |
// offsets starts for smoother entry | |
var st = DIRECTION == -1 ? canvas.height + 20 : -20; | |
for (var i = 0; i < NUM; i++) { | |
pill = new Shape((i / NUM) * canvas.width, canvas.height / 2); | |
pill.band = i; | |
pills.push(pill); | |
} | |
} | |
// adds number of shapes to be drawn | |
function addP() { | |
var pill; | |
// offsets starts for smoother entry | |
var st = DIRECTION == -1 ? canvas.height + 20 : -20; | |
for (var i = 0; i < NUM; i++) { | |
pill = new Shape(round3(rand(0, canvas.width)), round3(rand(0,st))); | |
pills.push(pill); | |
} | |
} | |
// pauses audio from urls, stops audio from files | |
function stop() { | |
if (!FILE) { | |
if (audio != null) { | |
audio.pause(); | |
} | |
} else { | |
if (source != null) { | |
source.stop(0); | |
} | |
} | |
} | |
function menu() { | |
if (document.getElementById('menu').style.display == '') { | |
document.getElementById('hider').value = '>>'; | |
document.getElementById('menu').style.display = 'none'; | |
if (document.getElementById("options").style.display == 'block') | |
document.getElementById("options").style.display = 'none' | |
} else { | |
document.getElementById('hider').value = '<<'; | |
document.getElementById('menu').style.display = ''; | |
} | |
} | |
// hides/shows option menu | |
function options() { | |
document.getElementById("options").style.display = | |
document.getElementById("options").style.display == 'none' ? 'block' : 'none'; | |
} | |
// sets options | |
function setCond(cond) { | |
document.getElementById('amp').value = cond.amp; | |
document.getElementById('speedMin').value = cond.speedMin; | |
document.getElementById('speedMax').value = cond.speedMax; | |
document.getElementById('spinMin').value = cond.spinMin; | |
document.getElementById('spinMax').value = cond.spinMax; | |
document.getElementById('sizeMin').value = cond.sizeMin; | |
document.getElementById('sizeMax').value = cond.sizeMax; | |
document.getElementById('scaleMin').value = cond.scaleMin; | |
document.getElementById('scaleMax').value = cond.scaleMax; | |
document.getElementById('alphaMin').value = cond.alphaMin; | |
document.getElementById('alphaMax').value = cond.alphaMax; | |
document.getElementById('grow').checked = cond.grow; | |
document.getElementById('numShapes').value = cond.numShapes; | |
document.getElementById('direction').value = cond.direction; | |
document.getElementById('shape').value = cond.shape; | |
document.getElementById('words').value = cond.words; | |
document.getElementById('bounce').checked = cond.bounce; | |
document.getElementById('sort').checked = cond.sort; | |
document.getElementById('wordsOptions').style.display = 'none'; | |
document.getElementById('bgColor').value = cond.bgColor; | |
document.getElementById('width').value = window.innerWidth; | |
document.getElementById('height').value = window.innerHeight; | |
document.getElementById('colors').innerHTML = ''; // clears prev colors | |
// adds default colors | |
colorFields = 0; | |
for (var i = 0; i < cond.colors.length; i++) { | |
addColor(); | |
document.getElementById('color' + (colorFields - 1)).value = cond.colors[i]; | |
} | |
} | |
// default settings | |
function defCond() { | |
setCond({ | |
amp: 250, | |
speedMin: .2, | |
speedMax: 1, | |
spinMin: .001, | |
spinMax: .005, | |
sizeMin: .5, | |
sizeMax: 1.25, | |
scaleMin: 5, | |
scaleMax: 20, | |
alphaMin: .8, | |
alphaMax: .9, | |
grow: false, | |
numShapes: 100, | |
direction: "Up", | |
shape: "Pill", | |
words: "", | |
bounce: false, | |
bgColor: '#000000', | |
colors: colorDef | |
}); | |
} | |
// floaty snow preset settings | |
function floatySnow() { | |
setCond({ | |
amp: 250, | |
speedMin: .1, | |
speedMax: 1, | |
spinMin: .001, | |
spinMax: .005, | |
sizeMin: .1, | |
sizeMax: .2, | |
scaleMin: 1, | |
scaleMax: 10, | |
alphaMin: .7, | |
alphaMax: .9, | |
grow: false, | |
numShapes: 100, | |
direction: "Down", | |
shape: "Pill", | |
words: "", | |
bounce: false, | |
bgColor: '#7CD3D8', // blue greyish sky | |
colors: ['#FFFFFF'] // white snow | |
}); | |
} | |
// rain preset | |
function rain() { | |
setCond({ | |
amp: 0, | |
speedMin: 10, | |
speedMax: 15, | |
spinMin: 0, | |
spinMax: 0, | |
sizeMin: .1, | |
sizeMax: .2, | |
scaleMin: 1, | |
scaleMax: 3, | |
alphaMin: .8, | |
alphaMax: .9, | |
grow: false, | |
numShapes: 100, | |
direction: "Down", | |
shape: "Pill", | |
words: "", | |
bounce: false, | |
bgColor: '#000000', // black | |
colors: ['#2B7BDD'] // white snow | |
}); | |
} | |
function waveform() { | |
setCond({ | |
amp: 0, | |
speedMin: 0, | |
speedMax: 0, | |
spinMin: .001, | |
spinMax: .005, | |
sizeMin: .5, | |
sizeMax: 10, | |
scaleMin: 15, | |
scaleMax: 20, | |
alphaMin: .8, | |
alphaMax: .9, | |
grow: false, | |
numShapes: 128, | |
direction: "Up", | |
shape: "Pill", | |
words: "", | |
bounce: false, | |
sort: true, | |
bgColor: '#000000', | |
colors: colorDef | |
}); | |
} | |
// init vars based on settings | |
function getCond() { | |
TYPE = document.getElementById('shape').value == "Words" ? 'word' : 'pill'; | |
AMP = toNum(document.getElementById('amp').value, 250); | |
SPEED = { | |
MIN: toNum(document.getElementById('speedMin').value, .2), | |
MAX: toNum(document.getElementById('speedMax').value, .5) | |
}; | |
SPIN = { | |
MIN: toNum(document.getElementById('spinMin').value, .001), | |
MAX: toNum(document.getElementById('spinMax').value, .005) | |
}; | |
SIZE = { | |
MIN: toNum(document.getElementById('sizeMin').value, .5), | |
MAX: toNum(document.getElementById('sizeMax').value, 2) | |
}; | |
SCALE = { | |
MIN: toNum(document.getElementById('scaleMin').value, 1), | |
MAX: toNum(document.getElementById('scaleMax').value, 10) | |
}; | |
ALPHA = { | |
MIN: toNum(document.getElementById('alphaMin').value, .2), | |
MAX: toNum(document.getElementById('alphaMax').value, 1) | |
}; | |
GROW = document.getElementById('grow').checked; | |
NUM = toNum(document.getElementById('numShapes').value, 10); | |
BOUNCE = document.getElementById('bounce').checked; | |
BGCOLOR = document.getElementById('bgColor').value; | |
DIRECTION = document.getElementById('direction').value == "Up" ? -1 : 1; | |
if (document.getElementById('direction').value == "Random") { | |
DIRECTION = 0; // direction modifier doesn't matter for random | |
} | |
SORT = document.getElementById('sort').checked; | |
FILE = false; | |
MIC = document.getElementById('mic').checked; | |
if (document.getElementById('mp3url').value != '') { | |
// uses inputed url as audio source | |
// needs url to be actual audio file, tried to circumvent issues with cors | |
// by using passing urls through crossorigin.me, but it still doesn't | |
// always work. | |
MP3 = 'http://crossorigin.me/' + document.getElementById('mp3url').value; | |
// removes previous audio player if present | |
if (document.body.contains(audio)) { | |
document.body.removeChild(audio); | |
audio = null; | |
} | |
} else if (document.getElementById('files').value != '') { | |
// removes previous audio player if present | |
if (document.body.contains(audio)) { | |
document.body.removeChild(audio); | |
audio = null; | |
} | |
audioFromFile(); // gets audio source from file | |
FILE = true; | |
} else if (MIC) { | |
// TODO: makes this work haha | |
if (document.body.contains(audio)) { | |
document.body.removeChild(audio); | |
audio = null; | |
} | |
AudioMic(); | |
} else { | |
MP3 = 'http://crossorigin.me/https://s3-us-west-2.amazonaws.com/s.cdpn.io/1715/the_xx_-_intro.mp3'; | |
} | |
color = []; | |
for (var i = 0; i < colorFields; i++) { | |
if (document.getElementById('color' + i) != null) { | |
color.push(document.getElementById('color' + i).value); | |
} | |
} | |
} | |
// parses s into a num if it contains one, otherwise returns def | |
function toNum(s, def) { | |
return !isNaN(parseFloat(s)) ? parseFloat(s) : def; | |
} | |
// returns random number in between range | |
function rand(min, max) { | |
return Math.random() * (max - min) + min; | |
} | |
// rounds n to 3 places | |
function round3(n) { | |
return Math.round(n * 1000) / 1000; | |
} | |
function Shape(x, y) { | |
// init vars | |
this.x = x; | |
this.y = y; | |
this.scale = Math.floor(rand(SCALE.MIN, SCALE.MAX)); | |
this.speed = round3(rand(SPEED.MIN, SPEED.MAX)); | |
this.color = color[Math.floor(Math.random() * color.length)]; | |
this.size = round3(rand(SIZE.MIN, SIZE.MAX)); | |
this.spin = round3(rand(SPIN.MIN, SPIN.MAX)); | |
this.alpha = round3(rand(ALPHA.MIN, ALPHA.MAX)); | |
this.band = Math.floor(rand(0, 128)); | |
this.energy = 0; | |
this.decayScale = 0; | |
this.decayAlpha = 0; | |
this.smoothedScale = 0; | |
this.smoothedAlpha = 0; | |
//this.alphamod = Math.floor(rand(1,5)); | |
// sets each shape to different word | |
if (TYPE == 'word') { | |
this.idx = idx++%words.length; | |
} | |
if (Math.random() < 0.5) { | |
this.spin *= -1; | |
} | |
this.rotation = round3(rand(0, 2 * Math.PI)); | |
this.direction = DIRECTION != 0 ? DIRECTION : 1; | |
this.random = DIRECTION == 0 ? true : false; | |
this.amp = AMP; | |
// updates shape's pos | |
this.move = function() { | |
this.rotation = round3(this.rotation + this.spin); | |
this.y = round3(this.y + this.speed * this.direction); | |
} | |
// draws shape | |
this.draw = function() { | |
var scale, alpha; | |
// changes scale and alpha levels of shapes depending on audio band data | |
// decay is so the shapes look like they react to the audio | |
// smoothed makes changes in energy levels smoother and not too jittery | |
scale = this.scale * Math.exp(this.energy); | |
alpha = this.alpha * this.energy * 1.5; | |
this.decayScale = Math.max(this.decayScale, scale); | |
this.decayAlpha = Math.max(this.decayAlpha, alpha); | |
this.smoothedScale = round3(this.smoothedScale + (this.decayScale - this.smoothedScale) * 0.3); | |
this.smoothedAlpha = round3(this.smoothedAlpha + (this.decayAlpha - this.smoothedAlpha) * 0.3); | |
this.decayScale = round3(this.decayScale * .95); | |
this.decayAlpha = round3(this.decayAlpha * .95); | |
g.save(); | |
g.beginPath(); | |
/* not really random just rotates first so the translation axis is different | |
causes shapes to appear randomly, not starting at top/ bottom */ | |
if (this.random) { | |
g.rotate(this.rotation); | |
g.translate(this.x + Math.cos(this.rotation * this.speed) * this.amp, this.y); | |
} else { | |
g.translate(this.x + Math.cos(this.rotation * this.speed) * this.amp, this.y); | |
g.rotate(this.rotation); | |
} | |
g.scale(this.smoothedScale, this.smoothedScale); | |
g.globalAlpha = this.smoothedAlpha/3; | |
// drawing actual shape | |
if (TYPE == 'pill') { | |
g.moveTo(this.size, 0); | |
g.lineTo(this.size * -1, 0); | |
g.lineWidth = "5"; | |
g.lineCap = 'round'; | |
g.strokeStyle = this.color; | |
g.stroke(); | |
} else if (TYPE == 'word') { | |
g.font = '20pt Arial'; | |
g.fillStyle = this.color; | |
g.fillText(words[this.idx], 0, 0); | |
} | |
g.restore(); | |
} | |
} | |
// clear canvas | |
function clear() { | |
g.clearRect(0, 0, canvas.width, canvas.height); | |
} | |
// draws all shapes | |
function draw() { | |
var p; | |
visual = requestAnimationFrame(draw); // set draw interval | |
analyzer.getByteFrequencyData(dataArray); // update audio data | |
if (!GROW) // clear screen between each drawing or not | |
clear(); | |
for (var i = 0; i < pills.length; i++) { | |
p = pills[i]; | |
p.energy = round3(dataArray[p.band] / 256); // updates energy levels based on audio | |
if (p.y < 0 && p.direction == -1 || | |
p.y > canvas.height && p.direction == 1) { | |
if (BOUNCE) { | |
// checks direction so starting offset doesn't make it bounce | |
// swaps direction, doesn't function properly with random direction | |
p.direction *= -1; | |
} else { | |
// resets shape | |
var st = p.direction == -1 ? canvas.height + 20 : -20; | |
p = new Shape(round3(rand(0, canvas.width)), st); | |
pills[i] = p; | |
} | |
} | |
// updates and redraws shape when done | |
if (p.y >= 0 || p.y <= canvas.height || BOUNCE) { | |
p.move(); | |
p.draw(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment