标题: [转载代码] 音频可视化效果 [打印本页]
作者: aa77dd@163.com 时间: 2016-10-22 22:06 标题: 音频可视化效果
转自: http://codepen.io/raurir/pen/ZQVrzg
演示地址:
https://a7d.000webhostapp.com/audio-visualiser/index_s_dread_rock.html- <!DOCTYPE html>
- <html >
- <head>
- <meta charset="UTF-8">
- <title>Audio Visualiser</title>
-
- <style>
- body {
- background-color: #000;
- }
- canvas {
- margin: 50px auto;
- display: block;
- }
- </style>
-
- </head>
-
- <body>
- </body>
- </html>
-
- <script>
- (function() {
- var Alien, Aliencon, Analyse, Music, con,
- bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
-
- Alien = (function() {
- Alien.prototype.grid = null;
-
- Alien.prototype.cellSize = 30;
-
- Alien.prototype.numberOfRows = 10;
-
- Alien.prototype.numberOfColumns = 10;
-
- Alien.prototype.halfColumns = 0;
-
- Alien.prototype.colReflected = 0;
-
- Alien.prototype.ticks = 0;
-
- Alien.prototype.canvas = null;
-
- Alien.prototype.drawingContext = null;
-
- Alien.prototype.canvasWidth = 0;
-
- Alien.prototype.canvasHeight = 0;
-
- function Alien() {
- this.step = bind(this.step, this);
- this.getAlien = bind(this.getAlien, this);
- this.halfColumns = this.numberOfColumns / 2;
- this.canvasWidth = this.cellSize * (this.numberOfColumns + 2);
- this.canvasHeight = this.cellSize * (this.numberOfRows + 2);
- this.canvas = document.createElement('canvas');
- this.drawingContext = this.canvas.getContext('2d');
- this.canvas.height = this.canvasWidth;
- this.canvas.width = this.canvasHeight;
- this.canvas.aliens = {
- x: 0,
- y: 0
- };
- }
-
- Alien.prototype.clearCanvas = function() {
- return this.drawingContext.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
- };
-
- Alien.prototype.seed = function() {
- var column, k, ref, results, row, seedCell;
- this.grid = [];
- results = [];
- for (row = k = 0, ref = this.numberOfRows; 0 <= ref ? k < ref : k > ref; row = 0 <= ref ? ++k : --k) {
- this.grid[row] = [];
- results.push((function() {
- var n, ref1, results1;
- results1 = [];
- for (column = n = 0, ref1 = this.halfColumns; 0 <= ref1 ? n < ref1 : n > ref1; column = 0 <= ref1 ? ++n : --n) {
- seedCell = this.createSeedCell(column);
- results1.push(this.grid[row][column] = seedCell);
- }
- return results1;
- }).call(this));
- }
- return results;
- };
-
- Alien.prototype.createSeedCell = function(probability) {
- var chance, cutoff, tobe;
- chance = Math.random();
- cutoff = (probability + 1) / (this.halfColumns + 1);
- tobe = chance < cutoff;
- return tobe;
- };
-
- Alien.prototype.generateAlien = function() {
- var q, r;
- r = (function(_this) {
- return function(m) {
- return ~~(Math.random() * m + 1);
- };
- })(this);
- q = (function(_this) {
- return function() {
- var a, g, i, j, l;
- l = r(11);
- g = r(5);
- a = [];
- i = 0;
- while (i < l) {
- j = i * g;
- a.push(j);
- if (i) {
- a.unshift(-j);
- }
- i++;
- }
- return a;
- };
- })(this);
- return {
- x: q(),
- y: q()
- };
- };
-
- Alien.prototype.drawGrid = function(pixels) {
- var b, b1, colourFill, colourLine, column, g, g1, k, n, o, r, r1, ref, ref1, ref2, results, row;
- this.canvas.aliens = this.generateAlien();
- r = ~~(Math.random() * 128 + 64);
- g = ~~(Math.random() * 128 + 64);
- b = ~~(Math.random() * 128 + 64);
- colourLine = "rgba(" + r + ", " + g + ", " + b + ", 1)";
- r1 = ~~(r - Math.random() * 64);
- g1 = ~~(g - Math.random() * 64);
- b1 = ~~(b - Math.random() * 64);
- colourFill = "rgb(" + r1 + ", " + g1 + ", " + b1 + ")";
- for (row = k = 0, ref = this.numberOfRows; 0 <= ref ? k < ref : k > ref; row = 0 <= ref ? ++k : --k) {
- for (column = n = 0, ref1 = this.numberOfColumns; 0 <= ref1 ? n < ref1 : n > ref1; column = 0 <= ref1 ? ++n : --n) {
- this.drawCell(row, column, colourLine, 10);
- }
- }
- results = [];
- for (row = o = 0, ref2 = this.numberOfRows; 0 <= ref2 ? o < ref2 : o > ref2; row = 0 <= ref2 ? ++o : --o) {
- results.push((function() {
- var p, ref3, results1;
- results1 = [];
- for (column = p = 0, ref3 = this.numberOfColumns; 0 <= ref3 ? p < ref3 : p > ref3; column = 0 <= ref3 ? ++p : --p) {
- results1.push(this.drawCell(row, column, colourFill, 0));
- }
- return results1;
- }).call(this));
- }
- return results;
- };
-
- Alien.prototype.drawCell = function(y, x, fillStyle, strokeWidth) {
- var colReflected, isOn;
- if (x >= this.halfColumns) {
- colReflected = this.numberOfColumns - x - 1;
- } else {
- colReflected = x;
- }
- isOn = this.grid[y][colReflected];
- if (isOn) {
- this.drawingContext.fillStyle = fillStyle;
- return this.drawingContext.fillRect((1 + x) * this.cellSize - strokeWidth, (1 + y) * this.cellSize - strokeWidth, this.cellSize + strokeWidth * 2, this.cellSize + strokeWidth * 2);
- }
- };
-
- Alien.prototype.getAlien = function() {
- return this.canvas;
- };
-
- Alien.prototype.step = function() {};
-
- Alien.prototype.change = function() {
- this.clearCanvas();
- this.seed();
- return this.drawGrid();
- };
-
- return Alien;
-
- })();
-
- window.Alien = Aliencon = console;
-
- Analyse = (function() {
- Analyse.prototype.waves = null;
-
- Analyse.prototype.node = null;
-
- Analyse.prototype.analyser = null;
-
- Analyse.prototype.audio = null;
-
- Analyse.prototype.frameBufferSize = Math.pow(2, 11);
-
- Analyse.prototype.channels = 4;
-
- Analyse.prototype.bufferSize = 0;
-
- Analyse.prototype.signal = null;
-
- Analyse.prototype.fft = null;
-
- Analyse.prototype.amplitude = 0;
-
- Analyse.prototype.spectrum = [];
-
- function Analyse() {
- this.step = bind(this.step, this);
- this.processAudio = bind(this.processAudio, this);
- this.bufferSize = this.frameBufferSize / this.channels;
- this.signal = new Float32Array(this.bufferSize);
- this.fft = new FFT(this.bufferSize, 44100);
- this.newAudioContext();
- // this.loadAudio('https://dl.dropboxusercontent.com/u/729503/Codepen/usee.mp3');
- this.loadAudio('https://cf-media.sndcdn.com/CmhscBlMZl1W.128.mp3?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiKjovL2NmLW1lZGlhLnNuZGNkbi5jb20vQ21oc2NCbE1abDFXLjEyOC5tcDMiLCJDb25kaXRpb24iOnsiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0NzcxMzk3MDN9fX1dfQ__&Signature=mCistR~h5En7Nk92Kq~bQIVWaSPmhz-PZ8CMB4OkboW-7Kg6zBGJ3Q5XQ~KDt-uMVYvelxaIZnmoB5rfyELS-ck0hX0WV4RRzHKsJXAAvQjEYES0SSpSueJFh4Vy6Oeh-xuwRK1gApq0S89Oo-km31w3cho4ix10WPcVu0Cgn0P57inrnDEq6NATn3T9iqNI47poxtqZk02VhL5GDr5DnxTvrWy7IqCTlci82LNKZEX1mY6quBP11R8EM7fUDd1BfbgEeZyjiP2IrrXsqpi9q3KDKOZtIIK24Kg2pWJWKzeHZBQu8zc8YQW-eeJYkAWpLDT132jvZ4CE3g1o3zSJow__&Key-Pair-Id=APKAJAGZ7VMH2PFPW6UQ');
-
-
- con.log("Analyse constructor", this.signal.length);
- }
-
- Analyse.prototype.newAudioContext = function() {
- var fok;
- fok = (function(_this) {
- return function(f) {
- return window[f] != null;
- };
- })(this);
- this.waves = false;
- if (fok('AudioContext')) {
- con.log("AudioContext");
- this.waves = new AudioContext();
- } else if (fok('webkitAudioContext')) {
- con.log("webkitAudioContext");
- this.waves = new webkitAudioContext();
- }
- return con.log("waves", this.waves);
- };
-
- Analyse.prototype.loadAudio = function(url) {
- con.log("loadAudio", url, this.waves);
- if (this.audio) {
- this.audio.remove();
- }
- if (this.node) {
- this.node.disconnect();
- }
- this.audio = new Audio();
- this.audio.crossOrigin = "anonymous";
- this.audio.preload = 'auto';
- this.audio.controls = true;
- document.body.appendChild(this.audio);
- if (this.waves) {
- con.log("waves created");
- this.audio.addEventListener('canplay', (function(_this) {
- return function(e) {
- return _this.setupAudioNodes(e);
- };
- })(this));
- } else {
-
- }
- return this.audio.src = url;
- };
-
- Analyse.prototype.setupAudioNodes = function(e) {
- con.log("setupAudioNodes");
- if (this.analyser == null) {
- this.analyser = this.analyser || this.waves.createScriptProcessor(this.bufferSize, 2, 2);
- this.analyser.onaudioprocess = this.processAudio;
- this.node = this.waves.createMediaElementSource(this.audio);
- this.node.connect(this.analyser);
- this.analyser.connect(this.waves.destination);
- }
- return this.audio.play();
- };
-
- Analyse.prototype.processAudio = function(e) {
- var i, inputArrayL, inputArrayR, k, outputArrayL, outputArrayR, ref;
- inputArrayL = e.inputBuffer.getChannelData(0);
- inputArrayR = e.inputBuffer.getChannelData(1);
- outputArrayL = e.outputBuffer.getChannelData(0);
- outputArrayR = e.outputBuffer.getChannelData(1);
- for (i = k = 0, ref = this.bufferSize; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) {
- outputArrayL[i] = inputArrayL[i];
- outputArrayR[i] = inputArrayR[i];
- this.signal[i] = (inputArrayL[i] + inputArrayR[i]) / 2;
- }
- this.fft.forward(this.signal);
- return this.fftChanged();
- };
-
- Analyse.prototype.fftChanged = function() {
- var i, k, magSum, ref, specLength;
- specLength = this.fft.spectrum.length;
- magSum = 0;
- for (i = k = 0, ref = specLength; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) {
- magSum += this.fft.spectrum[i];
- }
- return this.amplitude = 100 * magSum / specLength;
- };
-
- Analyse.prototype.step = function() {
- var bandTotal, currentBand, i, k, ref, results, specLength, totalBands;
- specLength = this.fft.spectrum.length;
- totalBands = specLength / 32;
- this.spectrum = [];
- currentBand = -1;
- results = [];
- for (i = k = 0, ref = specLength; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) {
- if (i % totalBands === 0) {
- bandTotal = 0;
- currentBand++;
- }
- bandTotal += this.fft.spectrum[i];
- if (i % totalBands === totalBands - 1) {
- results.push(this.spectrum[currentBand] = bandTotal);
- } else {
- results.push(void 0);
- }
- }
- return results;
- };
-
- Analyse.prototype.getAnalysis = function() {
- return {
- spectrum: this.spectrum,
- amplitude: this.amplitude,
- waveform: this.signal
- };
- };
-
- return Analyse;
-
- })();
-
- window.Analyse = Analyse;
-
-
- //------------------------------------------//
- //-------- STUFF FOR AUDIO ANALYSIS --------//
- function FourierTransform(bufferSize, sampleRate)
- {
- this.bufferSize = bufferSize;
- this.sampleRate = sampleRate;
- this.bandwidth = bufferSize * sampleRate;
- this.spectrum = new Float32Array(bufferSize/2);
- this.real = new Float32Array(bufferSize);
- this.imag = new Float32Array(bufferSize);
- this.peakBand = 0;
- this.peak = 0;
- this.getBandFrequency = function(index)
- {
- return this.bandwidth * index + this.bandwidth / 2;
- };
- this.calculateSpectrum = function()
- {
- var spectrum = this.spectrum,
- real = this.real,
- imag = this.imag,
- bSi = 2 / this.bufferSize,
- rval, ival, mag;
- this.peak = this.peakBand = 0;
- for (var i = 0, N = bufferSize*0.5; i < N; i++)
- {
- rval = real[i];
- ival = imag[i];
- mag = bSi * Math.sqrt(rval * rval + ival * ival);
- if (mag > this.peak)
- {
- this.peakBand = i;
- this.peak = mag;
- }
- spectrum[i] = mag;
- }
- };
- }
- function FFT(bufferSize, sampleRate)
- {
- FourierTransform.call(this, bufferSize, sampleRate);
- this.reverseTable = new Uint32Array(bufferSize);
- var limit = 1;
- var bit = bufferSize >> 1;
- var i;
- while (limit < bufferSize)
- {
- for (i = 0; i < limit; i++)
- this.reverseTable[i + limit] = this.reverseTable[i] + bit;
- limit = limit << 1;
- bit = bit >> 1;
- }
- this.sinTable = new Float32Array(bufferSize);
- this.cosTable = new Float32Array(bufferSize);
- for (i = 0; i < bufferSize; i++)
- {
- this.sinTable[i] = Math.sin(-Math.PI/i);
- this.cosTable[i] = Math.cos(-Math.PI/i);
- }
- }
- FFT.prototype.forward = function(buffer)
- {
- var bufferSize = this.bufferSize,
- cosTable = this.cosTable,
- sinTable = this.sinTable,
- reverseTable = this.reverseTable,
- real = this.real,
- imag = this.imag,
- spectrum = this.spectrum;
- var k = Math.floor(Math.log(bufferSize) / Math.LN2);
- if (Math.pow(2, k) !== bufferSize) { throw "Invalid buffer size, must be a power of 2."; }
- if (bufferSize !== buffer.length) { throw "Supplied buffer is not the same size as defined FFT. FFT Size: " + bufferSize + " Buffer Size: " + buffer.length; }
- var halfSize = 1,
- phaseShiftStepReal,
- phaseShiftStepImag,
- currentPhaseShiftReal,
- currentPhaseShiftImag,
- off,
- tr,
- ti,
- tmpReal,
- i;
- for (i = 0; i < bufferSize; i++)
- {
- real[i] = buffer[reverseTable[i]];
- imag[i] = 0;
- }
- while (halfSize < bufferSize)
- {
- phaseShiftStepReal = cosTable[halfSize];
- phaseShiftStepImag = sinTable[halfSize];
- currentPhaseShiftReal = 1;
- currentPhaseShiftImag = 0;
- for (var fftStep = 0; fftStep < halfSize; fftStep++)
- {
- i = fftStep;
- while (i < bufferSize)
- {
- off = i + halfSize;
- tr = (currentPhaseShiftReal * real[off]) - (currentPhaseShiftImag * imag[off]);
- ti = (currentPhaseShiftReal * imag[off]) + (currentPhaseShiftImag * real[off]);
- real[off] = real[i] - tr;
- imag[off] = imag[i] - ti;
- real[i] += tr;
- imag[i] += ti;
- i += halfSize << 1;
- }
- tmpReal = currentPhaseShiftReal;
- currentPhaseShiftReal = (tmpReal * phaseShiftStepReal) - (currentPhaseShiftImag * phaseShiftStepImag);
- currentPhaseShiftImag = (tmpReal * phaseShiftStepImag) + (currentPhaseShiftImag * phaseShiftStepReal);
- }
- halfSize = halfSize << 1;
- }
- return this.calculateSpectrum();
- };
-
- window.FFT = FFT;
- ;
-
- con = console;
-
- Music = (function() {
- Music.prototype.analyser = null;
-
- Music.prototype.aliendude = null;
-
- Music.prototype.canvas = null;
-
- Music.prototype.pixels = null;
-
- Music.prototype.canvasWidth = 1000;
-
- Music.prototype.canvasHeight = 500;
-
- Music.prototype.centreX = 0;
-
- Music.prototype.centreY = 0;
-
- Music.prototype.scale = 1;
-
- Music.prototype.float = 20;
-
- function Music() {
- this.step = bind(this.step, this);
- con.log("Music constructor");
- this.createCanvas();
- this.analyser = new Analyse(this.pixels, this.centreX, this.centreY);
- this.aliendude = new Alien();
- if (window.requestAnimationFrame) {
- con.log("native requestAnimationFrame");
- } else {
- con.log("creating requestAnimationFrame");
- window.requestAnimationFrame = window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame;
- }
- this.step();
- }
-
- Music.prototype.createCanvas = function() {
- this.centreX = this.canvasWidth / 2;
- this.centreY = this.canvasHeight / 2;
- this.canvas = document.createElement('canvas');
- document.body.appendChild(this.canvas);
- this.pixels = this.canvas.getContext('2d');
- this.canvas.width = this.canvasWidth;
- return this.canvas.height = this.canvasHeight;
- };
-
- Music.prototype.clearCanvas = function() {
- this.pixels.fillStyle = "rgb(0, 0, 0)";
- return this.pixels.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
- };
-
- Music.prototype.alienScale = 2;
-
- Music.prototype.alienRotate = 0.01;
-
- Music.prototype.step = function() {
- var amplitude, anal, b, bandWidth, c, g, i, img, k, len, len1, level, n, o, p, padding, r, ref, ref1, ref2, ref3, sc, specLength, spectrum, waveform, waveformLength, x, y;
- this.clearCanvas();
- this.analyser.step();
- this.aliendude.step();
- anal = this.analyser.getAnalysis();
- spectrum = anal.spectrum;
- amplitude = anal.amplitude;
- waveform = anal.waveform;
- this.pixels.fillStyle = "rgb(0, 20, 40)";
- this.pixels.fillRect(0, this.canvasHeight, this.canvasWidth, -amplitude * this.canvasHeight);
- specLength = spectrum.length;
- bandWidth = this.canvasWidth / specLength;
- padding = 5;
- for (i = k = 0, ref = specLength; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) {
- c = ~~(i / specLength * 55);
- r = 100;
- g = 200 + c;
- b = 255 - c;
- level = spectrum[i];
- this.pixels.fillStyle = "rgba(" + r + ", " + g + ", " + b + ", 0.5)";
- this.pixels.fillRect(i * bandWidth + padding, this.canvasHeight, bandWidth - padding * 2, -level * this.centreY);
- }
- waveformLength = waveform.length;
- bandWidth = this.canvasWidth / waveformLength;
- this.pixels.beginPath();
- for (i = n = 0, ref1 = waveformLength; 0 <= ref1 ? n < ref1 : n > ref1; i = 0 <= ref1 ? ++n : --n) {
- this.pixels.strokeStyle = '#0fe';
- this.pixels.lineWidth = 1;
- x = i * bandWidth;
- y = this.centreY + waveform[i] * this.centreY;
- if (i === 0) {
- this.pixels.moveTo(x, y);
- } else {
- this.pixels.lineTo(x, y);
- }
- }
- this.pixels.stroke();
- this.float += this.alienRotate;
- this.scale = spectrum[0];
- if (this.scale > this.alienScale * 4) {
- this.aliendude.change();
- this.alienScale = this.scale;
- this.alienRotate = (Math.random() - 0.5) * 0.1;
- } else {
- this.alienScale *= 0.9;
- }
- sc = this.alienScale * 1;
- img = this.aliendude.getAlien();
- this.pixels.save();
- this.pixels.translate(this.centreX, this.centreY);
- this.pixels.rotate(this.float);
- this.pixels.scale(sc, sc);
- this.pixels.translate(-img.width / 2, -img.height / 2);
- ref2 = img.aliens.x;
- for (o = 0, len = ref2.length; o < len; o++) {
- x = ref2[o];
- ref3 = img.aliens.y;
- for (p = 0, len1 = ref3.length; p < len1; p++) {
- y = ref3[p];
- this.pixels.drawImage(img, img.width * x, img.height * y);
- }
- }
- this.pixels.restore();
- return requestAnimationFrame(this.step);
- };
-
- return Music;
-
- })();
-
- window.Music = Music;
-
- new Music();
-
- }).call(this);
- </script>
复制代码
作者: happy886rr 时间: 2016-10-22 22:36
居然是傅里叶变换
作者: 523066680 时间: 2016-10-22 22:49
本帖最后由 523066680 于 2016-10-22 22:59 编辑
要是结合分形想必是极美妙的
我觉得图像方面我可以玩的有趣一些,但是不懂音频解析,所以就当吹吹牛啦。模拟信号处理是不是一定会涉及博里叶变换?
恰巧就在今天看到知乎的一个帖子:有哪些计算机生成的精美图形?
某个回答里介绍了一款强大的音乐可视化插件——MilkDrop
https://www.zhihu.com/question/19935130/answer/127674701
作者: aa77dd@163.com 时间: 2016-10-22 22:57
本帖最后由 aa77dd@163.com 于 2016-10-22 23:01 编辑
回复 3# 523066680
自学过一点高数, 早忘光了, 不懂 傅里叶变换
想起了 N 年前 有增强版的 nullsoft winamp 就自带 MilkDrop plug-in
作者: 523066680 时间: 2016-10-22 22:58
回复 4# aa77dd@163.com
准备辞职深造,趁年轻。
作者: aa77dd@163.com 时间: 2016-10-22 23:08
回复 5# 523066680
哈哈, 同意
MilkDrop 源码?
http://forums.winamp.com/showthread.php?t=214971
作者: aa77dd@163.com 时间: 2016-10-22 23:32
回复 3# 523066680
回味经典 含 MilkDrop2 可视化效果插件
http://meggamusic.co.uk/winamp/Winamp_Download.htm
Winamp 所属公司 Nullsoft 的吉祥物是 一只 大羊驼
欢迎光临 批处理之家 (http://bathome.net./) |
Powered by Discuz! 7.2 |