Created
August 6, 2015 20:17
-
-
Save srajagop/5d6690601f3bcae65df7 to your computer and use it in GitHub Desktop.
Revisions
-
srajagop created this gist
Aug 6, 2015 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,11 @@ Prism music visualizer ---------------------- My first music visualizer! Made using DOM with a lot of customization ability. Play with the controls and have some fun! For solid colors (including animating it through the spectrum), the darks are the lows and the light ones are the highs. For the rainbow configuration, the red is low and pink is high. Based on https://24.media.tumblr.com/cca3fc8094b89dc1a597e039a413c0f4/tumblr_n4euxkZcjo1sns7veo1_500.gif A [Pen](http://codepen.io/Zeaklous/pen/zGePqa) by [Zach Saucier](http://codepen.io/Zeaklous) on [CodePen](http://codepen.io/). [License](http://codepen.io/Zeaklous/pen/zGePqa/license). This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,15 @@ .musicControls input#audiofile(type='file') //- button.listenButton ...or listen to one of mine // Silly CORS button.playPauseButton ▶ label#loading(for="audiofile") Select an audio file... // This should match the values in the js - var maxSideNum = 24 - var maxRectangleNum = 24 .prism - for (var x = 0; x < maxSideNum; x++) .side.hide - for (var y = 0; y < maxRectangleNum; y++) .rectangle.hide This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,344 @@ var maxSideNum = 24, maxRectangleNum = 24; // Dat.gui setup var Options = function() { this.height = 400; this.radius = 185; this.sideCount = 12; this.rectangleCount = 12; this.rectangleWidth = 80; this.vertMargin = 10; this.borderWidth = 3; this.color = 200; this.solidBG = false; this.rainbowMode = false; this.animateThroughSpectrum = false; this.fade = false; }; window.onload = function() { // dat.gui setup var myOptions = new Options(), gui = new dat.GUI(), f1 = gui.addFolder('Prism Controls'), f2 = gui.addFolder('Rectangle Controls'), f3 = gui.addFolder('Color Controls'), mySideCount = f1.add(myOptions, 'sideCount', 3, maxSideNum).step(1), myRadius = f1.add(myOptions, 'radius', 30, 600).step(15), myHeight = f1.add(myOptions, 'height', 50, 750).step(50), myRectangleCount = f2.add(myOptions, 'rectangleCount', 3, maxRectangleNum).step(1), myRectangleWidth = f2.add(myOptions, 'rectangleWidth', 1, 100).step(5), myVertMargin = f2.add(myOptions, 'vertMargin', 0, 15).step(1), myBorderWidth = f2.add(myOptions, 'borderWidth', 0, 15).step(1), myColor = f3.add(myOptions, 'color', 0, 360).step(1), mySolidBG = f3.add(myOptions, 'solidBG'), myRainbow = f3.add(myOptions, 'rainbowMode'), myAnimateThroughSpectrum = f3.add(myOptions, 'animateThroughSpectrum'), myFade = f3.add(myOptions, 'fade'); f2.open(); var audio, analyser, audioctx, sourceNode, stream; var audioInput = document.getElementById('audiofile'), listenButton = document.querySelector(".listenButton"), playPauseButton = document.querySelector(".playPauseButton"); var c = 0, // Used to change color over time paused = true; /*var myMusic = [ "http://zachsaucier.com/music/Initiation.mp3", "http://zachsaucier.com/music/High%20Tide.mp3", "http://zachsaucier.com/music/Dolphin%20Style.mp3", "http://zachsaucier.com/music/King.mp3" ];*/ var prism = document.querySelector(".prism"), sides = document.querySelectorAll(".side"), rectangleArray = [maxSideNum], lastTime = Date.now(), timeGap = 50; function rectangleSetup() { for(var i = 0; i < maxSideNum; i++) { rectangleArray[i] = sides[i].querySelectorAll(".rectangle"); } } rectangleSetup(); // dat.gui listeners // f1 listeners function sideCountChange(newCount) { [].forEach.call(sides, function(elem, i) { if(i < myOptions.sideCount) { // The circle is inscribed inside of the prism, so we can use this formula to calculate the side length var sideLength = 2 * (myOptions.radius) * Math.tan(Math.PI / newCount); prism.style.width = sideLength + "px"; prism.style.left = "calc(50% - " + sideLength / 2 + "px)"; sides[i].style.transform = "rotateY(" + i * (360 / newCount) + "deg) translateZ(" + myOptions.radius + "px) rotateX(180deg)"; sides[i].classList.remove("hide"); } else { sides[i].classList.add("hide"); } }); } mySideCount.onFinishChange(sideCountChange); sideCountChange(myOptions.sideCount); function radiusChange(newRadius) { sideCountChange(myOptions.sideCount); } myRadius.onFinishChange(radiusChange); radiusChange(myOptions.radius); function heightChange(newHeight) { prism.style.height = newHeight + "px"; prism.style.top = "calc(50% - " + newHeight / 2 + "px)" rectangleCountChange(myOptions.rectangleCount); } myHeight.onFinishChange(heightChange); heightChange(myOptions.height); // f2 listeners function rectangleCountChange(newCount) { [].forEach.call(rectangleArray, function(side, i) { [].forEach.call(side, function(rect, i) { if(i < myOptions.rectangleCount) { rect.style.height = (myOptions.height - myOptions.vertMargin) / newCount - myOptions.vertMargin + "px"; rect.classList.remove("hide"); } else { rect.classList.add("hide"); } }); }); } myRectangleCount.onFinishChange(rectangleCountChange); rectangleCountChange(myOptions.rectangleCount); function rectangleWidthChange(newWidth) { [].forEach.call(rectangleArray, function(side, i) { [].forEach.call(side, function(rect, i) { rect.style.width = newWidth + "%"; }); }); } myRectangleWidth.onFinishChange(rectangleWidthChange); rectangleWidthChange(myOptions.rectangleWidth); function vertMarginChange(newMargin) { [].forEach.call(rectangleArray, function(side, i) { [].forEach.call(side, function(rect, i) { rect.style.margin = newMargin + "px auto"; }); }); rectangleCountChange(myOptions.rectangleCount); } myVertMargin.onFinishChange(vertMarginChange); vertMarginChange(myOptions.vertMargin); function borderWidthChange(newWidth) { [].forEach.call(rectangleArray, function(side, i) { [].forEach.call(side, function(rect, i) { rect.style.borderWidth = newWidth + "px"; }); }); } myBorderWidth.onFinishChange(borderWidthChange); borderWidthChange(myOptions.borderWidthChange); // f3 listeners function colorChange(value) { if(!myOptions.rainbowMode) [].forEach.call(sides, function(elem, i) { sides[i].style.color = "hsl(" + value + ", 55%, " + (20 + (i / myOptions.sideCount) * 40) + "%)"; }); } myColor.onFinishChange(colorChange); colorChange(myOptions.color); mySolidBG.onFinishChange(function(value) { if(value === true) prism.classList.add("solid"); else prism.classList.remove("solid"); }); function goRainbowMode(value) { [].forEach.call(sides, function(elem, i) { if(value === true) sides[i].style.color = "hsl(" + 360 * (i / myOptions.sideCount) + ", 80%, 55%)"; else colorChange(myOptions.color); }); } myRainbow.onFinishChange(goRainbowMode); function checkAnimateThroughSpectrum() { if(myOptions.animateThroughSpectrum) [].forEach.call(sides, function(elem, i) { sides[i].style.color = "hsl(" + c + ", 80%, " + (20 + (i / myOptions.sideCount) * 40) + "%)"; }); else if(myOptions.rainbowMode) goRainbowMode(true); else colorChange(myOptions.color); } // The music player listeners audioInput.addEventListener('change', function(event) { if(event.target.files[0]) { // No error checking of file here, could be added stream = URL.createObjectURL(event.target.files[0]); loadSong(stream); } }, false); if(listenButton) listenButton.addEventListener('click', chooseOneOfMine, false); playPauseButton.addEventListener('click', togglePlayPause, false); // The music functions function setup() { // Stop the previous song if there is one if(audio) togglePlayPause(); audio = new Audio(); audioctx = new AudioContext(); analyser = audioctx.createAnalyser(); analyser.smoothingTimeConstant = 0.75; analyser.fftSize = 512; audio.addEventListener('ended', songEnded, false); sourceNode = audioctx.createMediaElementSource(audio); sourceNode.connect(analyser); sourceNode.connect(audioctx.destination); } function loadSong(stream) { setup(); audio.src = stream; togglePlayPause(); document.body.classList.add('loaded'); update(); } function songEnded() { document.body.classList.remove('loaded'); togglePlayPause(); } function togglePlayPause() { if(paused) { document.body.classList.add('loaded'); audio.play(); playPauseButton.innerText = "▮▮"; } else if(!audio.paused && !audio.ended) { audio.pause(); playPauseButton.innerText = "▶"; } paused = !paused; } function chooseOneOfMine() { var num = Math.round(Math.random() * (myMusic.length - 1)) + 1; loadSong(myMusic[num]); } // The drawing functions function drawSide(freqSequence, freqPercent) { // Get the number of rectangles based on the freqValue drawRectangles(freqSequence, Math.floor(freqPercent * myOptions.rectangleCount / 100)) } function drawRectangles(sideNum, numRectanglesShowing) { for(var i = 0; i < myOptions.rectangleCount; i++) { var cl = rectangleArray[sideNum][i].classList; if(i <= numRectanglesShowing) { cl.remove("hide"); cl.remove("faded"); } else { if(!myOptions.fade) cl.add("hide"); else cl.add("faded"); } } } var sectionsAveraged = [maxSideNum], countSinceLast = [maxSideNum]; function update() { var currTime = Date.now(); var freqArray = new Uint8Array(analyser.frequencyBinCount); analyser.getByteTimeDomainData(freqArray); // Find the average of the values near to each other (grouping) var average = 0, count = 0, numPerSection = 256 / (myOptions.sideCount + 1), nextSection = numPerSection; for (var i = 0; i < freqArray.length; i++) { var v = freqArray[i]; average += Math.abs(128 - v); // 128 is essentially 0 count++; if(i > nextSection) { var currentSection = Math.floor(i / numPerSection - 1); sectionsAveraged[currentSection] += average / count; countSinceLast[currentSection]++; average = 0; count = 0; nextSection += numPerSection; } } // Find the average of the values since the last time checked per section (smoothing) if(currTime - lastTime > timeGap) { for (var i = 0; i < myOptions.sideCount; i++) { drawSide(i, (sectionsAveraged[i] / countSinceLast[i]), c); sectionsAveraged[i] = 0; countSinceLast[i] = 0; } lastTime = currTime; } checkAnimateThroughSpectrum(); c += 0.5; requestAnimationFrame(update); } }; This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1 @@ <script src="http://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js"></script> This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,99 @@ // All of the commented out things are from the static, pre-dat.gui version that are no longer necessary //$sideNum: 12; //$rectNum: 12; //$width: 100px; //$margin: 1% * 7.3; $border: 3px solid #4DA16F; /* Default all same color */ * { box-sizing: border-box; } html, body { height:100%; } body { background: rgb(30,30,30); font-family: 'Helvatica', sans-serif; color: #FFF; position:relative; perspective: 1000px; perspective-origin: 50% 50%; } .hide { display:none; } .faded { opacity: 0; } .prism { position:absolute; //top:calc(50% - #{$width * 2}); //left:calc(50% - #{$width * 0.5}); //width:$width; //height:$width * 4; transform-style: preserve-3d; animation:rotate 8s linear infinite; } .side { width:100%; height:100%; border-top: $border; border-bottom: $border; border-color:currentColor; position:absolute; } .rectangle { //height: (100% / $rectNum) - 2%; //width:80%; //margin:10px auto; border: $border; border-color:currentColor; transition: opacity 150ms; } .solid .rectangle { background:currentColor; } //@for $i from 1 through $sideNum { // .side:nth-child(#{$i}) { // color: hsl(144, 55%, 20% + ($i / $sideNum) * 40%); // // transform: rotateY($i * (360 / $sideNum) + deg) translateZ($width * 1.85) rotateX(180deg); // } // .side.rainbow:nth-child(#{$i}) { // color: hsl(360*($i / $sideNum), 80%, 55%); // } //} @keyframes rotate { from { transform:rotateY(0); } to { transform:rotateY(-360deg); } } .musicControls, label { position: absolute; border-radius: 5px; border: 1px solid rgba(255, 255, 255, 0.3); padding: 10px; } .musicControls { top: 20px; left: 20px; } label { left: 20px; top: 100px; font-style:italic; } body.loaded { #loading { display: none; } }