A Pen by yoichi kobayashi on CodePen.
Created
June 11, 2019 01:52
-
-
Save armedoctopus/f4c91c447f5f5ce820b56caaec35183d to your computer and use it in GitHub Desktop.
Audio Visualizer ver2
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 characters
| <canvas id="canvas"></canvas> |
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 characters
| (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | |
| module.exports = function(object, eventType, callback){ | |
| var timer; | |
| object.addEventListener(eventType, function(event) { | |
| clearTimeout(timer); | |
| timer = setTimeout(function(){ | |
| callback(event); | |
| }, 500); | |
| }, false); | |
| }; | |
| },{}],2:[function(require,module,exports){ | |
| var Vector2 = require('./vector2'); | |
| var exports = { | |
| friction: function(acceleration, mu, normal, mass) { | |
| var force = acceleration.clone(); | |
| if (!normal) normal = 1; | |
| if (!mass) mass = 1; | |
| force.multiplyScalar(-1); | |
| force.normalize(); | |
| force.multiplyScalar(mu); | |
| return force; | |
| }, | |
| drag: function(acceleration, value) { | |
| var force = acceleration.clone(); | |
| force.multiplyScalar(-1); | |
| force.normalize(); | |
| force.multiplyScalar(acceleration.length() * value); | |
| return force; | |
| }, | |
| hook: function(velocity, anchor, rest_length, k) { | |
| var force = velocity.clone().sub(anchor); | |
| var distance = force.length() - rest_length; | |
| force.normalize(); | |
| force.multiplyScalar(-1 * k * distance); | |
| return force; | |
| } | |
| }; | |
| module.exports = exports; | |
| },{"./vector2":6}],3:[function(require,module,exports){ | |
| var Util = require('./util'); | |
| var Vector2 = require('./vector2'); | |
| var Force = require('./force'); | |
| var debounce = require('./debounce'); | |
| var Mover = require('./mover'); | |
| var body = document.body; | |
| var body_width = body.clientWidth * 2; | |
| var body_height = body.clientHeight * 2; | |
| var canvas = document.getElementById('canvas'); | |
| var ctx = canvas.getContext('2d'); | |
| var audio_ctx = new (window.AudioContext || window.webkitAudioContext)(); | |
| var audio_analyser = audio_ctx.createAnalyser(); | |
| var audio_buffer = new XMLHttpRequest(); | |
| //var audio_url = 'https://api.soundcloud.com/tracks/89297698/stream?client_id=0aaf73b4de24ee4e86313e01d458083d'; | |
| var audio_url = 'https://api.soundcloud.com/tracks/127070185/stream?client_id=0aaf73b4de24ee4e86313e01d458083d'; | |
| var fft_size = 512; | |
| var movers = []; | |
| var last_time_xxx = Date.now(); | |
| var vector_touch_start = new Vector2(); | |
| var vector_touch_move = new Vector2(); | |
| var vector_touch_end = new Vector2(); | |
| var is_touched = false; | |
| var init = function() { | |
| poolMover(); | |
| initAudio(); | |
| resizeCanvas(); | |
| renderloop(); | |
| debounce(window, 'resize', function(event){ | |
| resizeCanvas(); | |
| }); | |
| }; | |
| var initAudio = function() { | |
| audio_analyser.fft_size = fft_size; | |
| audio_analyser.connect(audio_ctx.destination); | |
| loadAudio(); | |
| }; | |
| var loadAudio = function() { | |
| var request = new XMLHttpRequest(); | |
| request.open('GET', audio_url, true); | |
| request.responseType = 'arraybuffer'; | |
| request.onload = function() { | |
| audio_ctx.decodeAudioData(request.response, function(buffer) { | |
| audio_buffer = buffer; | |
| playAudio(); | |
| }); | |
| }; | |
| request.send(); | |
| }; | |
| var playAudio = function() { | |
| var source = audio_ctx.createBufferSource(); | |
| source.buffer = audio_buffer; | |
| source.connect(audio_analyser); | |
| source.loop = true; | |
| source.loopStart = 0; | |
| source.loopEnd = audio_buffer.duration; | |
| source.playbackRate.value = 1.0; | |
| source.start(0); | |
| }; | |
| var poolMover = function() { | |
| for (var i = 0; i < fft_size; i++) { | |
| var mover = new Mover(); | |
| var deg = i / fft_size * 360; | |
| var rad = Util.getRadian(deg); | |
| var x = Math.cos(rad) + body_width / 2; | |
| var y = Math.sin(rad) + body_height / 2; | |
| var position = new Vector2(x, y); | |
| mover.init(position, 20); | |
| mover.h = Math.abs(deg - 180) / 4; | |
| movers.push(mover); | |
| } | |
| }; | |
| var updateMover = function() { | |
| var spectrums = new Uint8Array(audio_analyser.frequencyBinCount); | |
| var str = ''; | |
| var length = 0; | |
| audio_analyser.getByteTimeDomainData(spectrums); | |
| spectrum_length = audio_analyser.frequencyBinCount; | |
| for (var i = 0; i < movers.length; i++) { | |
| var mover = movers[i]; | |
| var rad = Util.getRadian(i / movers.length * 360); | |
| var r = body_height / 3; | |
| var x = Math.cos(rad) * r + body_width / 2; | |
| var y = Math.sin(rad) * r + body_height / 2; | |
| var size = Math.pow(Math.abs(spectrums[i * 2] - 128) / 128 + 1.1, 7); | |
| mover.h += 0.1 | |
| mover.radius = size; | |
| mover.velocity.set(x, y); | |
| mover.updateVelocity(); | |
| mover.updatePosition(); | |
| mover.draw(ctx); | |
| } | |
| }; | |
| var render = function() { | |
| ctx.globalCompositeOperation = 'lighter'; | |
| ctx.clearRect(0, 0, body_width, body_height); | |
| updateMover(); | |
| }; | |
| var renderloop = function() { | |
| var now = Date.now(); | |
| requestAnimationFrame(renderloop); | |
| render(); | |
| // if (now - last_time_xxx > 1000) { | |
| // function_name(); | |
| // last_time_xxx = Date.now(); | |
| // } | |
| }; | |
| var resizeCanvas = function() { | |
| body_width = body.clientWidth * 2; | |
| body_height = body.clientHeight * 2; | |
| canvas.width = body_width; | |
| canvas.height = body_height; | |
| canvas.style.width = body_width / 2 + 'px'; | |
| canvas.style.height = body_height / 2 + 'px'; | |
| }; | |
| init(); | |
| },{"./debounce":1,"./force":2,"./mover":4,"./util":5,"./vector2":6}],4:[function(require,module,exports){ | |
| var Util = require('./util'); | |
| var Vector2 = require('./vector2'); | |
| var Force = require('./force'); | |
| var exports = function(){ | |
| var Mover = function() { | |
| this.position = new Vector2(); | |
| this.velocity = new Vector2(); | |
| this.acceleration = new Vector2(); | |
| this.anchor = new Vector2(); | |
| this.radius = 0; | |
| this.mass = 1; | |
| this.direction = 0; | |
| this.h = 0; | |
| this.s = 80; | |
| this.l = 15; | |
| this.a = 0.5; | |
| this.time = 0; | |
| this.is_active = false; | |
| }; | |
| Mover.prototype = { | |
| init: function(vector, size) { | |
| this.radius = size; | |
| this.mass = this.radius / 100; | |
| this.position = vector.clone(); | |
| this.velocity = vector.clone(); | |
| this.anchor = vector.clone(); | |
| this.acceleration.set(0, 0); | |
| this.a = 1; | |
| this.time = 0; | |
| }, | |
| updatePosition: function() { | |
| this.position.copy(this.velocity); | |
| }, | |
| updateVelocity: function() { | |
| this.velocity.add(this.acceleration); | |
| if (this.velocity.distanceTo(this.position) >= 1) { | |
| this.direct(this.velocity); | |
| } | |
| }, | |
| applyForce: function(vector) { | |
| this.acceleration.add(vector); | |
| }, | |
| applyFriction: function() { | |
| var friction = Force.friction(this.acceleration, 0.1); | |
| this.applyForce(friction); | |
| }, | |
| applyDragForce: function(value) { | |
| var drag = Force.drag(this.acceleration, value); | |
| this.applyForce(drag); | |
| }, | |
| hook: function(rest_length, k) { | |
| var force = Force.hook(this.velocity, this.anchor, rest_length, k); | |
| this.applyForce(force); | |
| }, | |
| direct: function(vector) { | |
| var v = vector.clone().sub(this.position); | |
| this.direction = Math.atan2(v.y, v.x); | |
| }, | |
| draw: function(context) { | |
| context.fillStyle = 'hsla(' + this.h + ',' + this.s + '%,' + this.l + '%,' + this.a + ')'; | |
| context.beginPath(); | |
| context.arc(this.position.x, this.position.y, this.radius, 0, Math.PI / 180, true); | |
| context.fill(); | |
| }, | |
| activate: function () { | |
| this.is_active = true; | |
| }, | |
| inactivate: function () { | |
| this.is_active = false; | |
| } | |
| }; | |
| return Mover; | |
| }; | |
| module.exports = exports(); | |
| },{"./force":2,"./util":5,"./vector2":6}],5:[function(require,module,exports){ | |
| var exports = { | |
| getRandomInt: function(min, max){ | |
| return Math.floor(Math.random() * (max - min)) + min; | |
| }, | |
| getDegree: function(radian) { | |
| return radian / Math.PI * 180; | |
| }, | |
| getRadian: function(degrees) { | |
| return degrees * Math.PI / 180; | |
| }, | |
| getSpherical: function(rad1, rad2, r) { | |
| var x = Math.cos(rad1) * Math.cos(rad2) * r; | |
| var z = Math.cos(rad1) * Math.sin(rad2) * r; | |
| var y = Math.sin(rad1) * r; | |
| return [x, y, z]; | |
| } | |
| }; | |
| module.exports = exports; | |
| },{}],6:[function(require,module,exports){ | |
| // | |
| // このVector2クラスは、three.jsのTHREE.Vector2クラスの計算式の一部を利用しています。 | |
| // https://github.com/mrdoob/three.js/blob/master/src/math/Vector2.js#L367 | |
| // | |
| var exports = function(){ | |
| var Vector2 = function(x, y) { | |
| this.x = x || 0; | |
| this.y = y || 0; | |
| }; | |
| Vector2.prototype = { | |
| set: function (x, y) { | |
| this.x = x; | |
| this.y = y; | |
| return this; | |
| }, | |
| clone: function () { | |
| return new Vector2(this.x, this.y); | |
| }, | |
| copy: function (v) { | |
| this.x = v.x; | |
| this.y = v.y; | |
| return this; | |
| }, | |
| add: function (v) { | |
| this.x += v.x; | |
| this.y += v.y; | |
| return this; | |
| }, | |
| addScalar: function (s) { | |
| this.x += s; | |
| this.y += s; | |
| return this; | |
| }, | |
| sub: function (v) { | |
| this.x -= v.x; | |
| this.y -= v.y; | |
| return this; | |
| }, | |
| subScalar: function (s) { | |
| this.x -= s; | |
| this.y -= s; | |
| return this; | |
| }, | |
| multiply: function (v) { | |
| this.x *= v.x; | |
| this.y *= v.y; | |
| return this; | |
| }, | |
| multiplyScalar: function (s) { | |
| this.x *= s; | |
| this.y *= s; | |
| return this; | |
| }, | |
| divide: function (v) { | |
| this.x /= v.x; | |
| this.y /= v.y; | |
| return this; | |
| }, | |
| divideScalar: function (s) { | |
| if (this.x !== 0 && s !== 0) this.x /= s; | |
| if (this.y !== 0 && s !== 0) this.y /= s; | |
| return this; | |
| }, | |
| min: function (v) { | |
| if (this.x < v.x) this.x = v.x; | |
| if (this.y < v.y) this.y = v.y; | |
| return this; | |
| }, | |
| max: function (v) { | |
| if (this.x > v.x) this.x = v.x; | |
| if (this.y > v.y) this.y = v.y; | |
| return this; | |
| }, | |
| clamp: function (v_min, v_max) { | |
| if (this.x < v_min.x) { | |
| this.x = v_min.x; | |
| } else if (this.x > v_max.x) { | |
| this.x = v_max.x; | |
| } | |
| if (this.y < v_min.y) { | |
| this.y = v_min.y; | |
| } else if (this.y > v_max.y) { | |
| this.y = v_max.y; | |
| } | |
| return this; | |
| }, | |
| clampScalar: function () { | |
| var min, max; | |
| return function clampScalar(minVal, maxVal) { | |
| if (min === undefined) { | |
| min = new Vector2(); | |
| max = new Vector2(); | |
| } | |
| min.set(minVal, minVal); | |
| max.set(maxVal, maxVal); | |
| return this.clamp(min, max); | |
| }; | |
| }(), | |
| floor: function () { | |
| this.x = Math.floor(this.x); | |
| this.y = Math.floor(this.y); | |
| return this; | |
| }, | |
| ceil: function () { | |
| this.x = Math.ceil(this.x); | |
| this.y = Math.ceil(this.y); | |
| return this; | |
| }, | |
| round: function () { | |
| this.x = Math.round(this.x); | |
| this.y = Math.round(this.y); | |
| return this; | |
| }, | |
| roundToZero: function () { | |
| this.x = (this.x < 0) ? Math.ceil(this.x) : Math.floor(this.x); | |
| this.y = (this.y < 0) ? Math.ceil(this.y) : Math.floor(this.y); | |
| return this; | |
| }, | |
| negate: function () { | |
| this.x = - this.x; | |
| this.y = - this.y; | |
| return this; | |
| }, | |
| dot: function (v) { | |
| return this.x * v.x + this.y * v.y; | |
| }, | |
| lengthSq: function () { | |
| return this.x * this.x + this.y * this.y; | |
| }, | |
| length: function () { | |
| return Math.sqrt(this.lengthSq()); | |
| }, | |
| lengthManhattan: function() { | |
| return Math.abs(this.x) + Math.abs(this.y); | |
| }, | |
| normalize: function () { | |
| return this.divideScalar(this.length()); | |
| }, | |
| distanceTo: function (v) { | |
| var dx = this.x - v.x; | |
| var dy = this.y - v.y; | |
| return Math.sqrt(dx * dx + dy * dy); | |
| }, | |
| distanceToSquared: function (v) { | |
| var dx = this.x - v.x, dy = this.y - v.y; | |
| return dx * dx + dy * dy; | |
| }, | |
| setLength: function (l) { | |
| var oldLength = this.length(); | |
| if (oldLength !== 0 && l !== oldLength) { | |
| this.multScalar(l / oldLength); | |
| } | |
| return this; | |
| }, | |
| lerp: function (v, alpha) { | |
| this.x += (v.x - this.x) * alpha; | |
| this.y += (v.y - this.y) * alpha; | |
| return this; | |
| }, | |
| lerpVectors: function (v1, v2, alpha) { | |
| this.subVectors(v2, v1).multiplyScalar(alpha).add(v1); | |
| return this; | |
| }, | |
| equals: function (v) { | |
| return ((v.x === this.x) && (v.y === this.y)); | |
| }, | |
| fromArray: function (array, offset) { | |
| if (offset === undefined) offset = 0; | |
| this.x = array[ offset ]; | |
| this.y = array[ offset + 1 ]; | |
| return this; | |
| }, | |
| toArray: function (array, offset) { | |
| if (array === undefined) array = []; | |
| if (offset === undefined) offset = 0; | |
| array[ offset ] = this.x; | |
| array[ offset + 1 ] = this.y; | |
| return array; | |
| }, | |
| fromAttribute: function (attribute, index, offset) { | |
| if (offset === undefined) offset = 0; | |
| index = index * attribute.itemSize + offset; | |
| this.x = attribute.array[ index ]; | |
| this.y = attribute.array[ index + 1 ]; | |
| return this; | |
| } | |
| } | |
| return Vector2; | |
| }; | |
| module.exports = exports(); | |
| },{}]},{},[3]) |
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 characters
| * { | |
| margin: 0; | |
| padding: 0; | |
| } | |
| html { | |
| height: 100%; | |
| } | |
| body { | |
| height: 100%; | |
| overflow: hidden; | |
| font-family: 'source code pro'; | |
| background: radial-gradient(ellipse at center, #000000 44%, #222222 100%); | |
| } | |
| canvas { | |
| position: absolute; | |
| top: 0; | |
| right: 0; | |
| bottom: 0; | |
| left: 0; | |
| } | |
| p { | |
| line-height: 1.5; | |
| position: relative; | |
| z-index: 2; | |
| padding: 1em; | |
| color: #00ee00; | |
| word-wrap:break-word; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment