在文章的开头,我们先来看下什么是音乐可视化:

音乐可视化–web audio

没错!这个类似音频解调器的东西就是音乐可视化。我们通过某种手段抓取音频数据,然后根据这些数据及时绘制到画布。要将数据绘制在画布中,我们需要准备一个canvas,有:

var canvas = document.getElementById("canvas");
canvasCtx = canvas.getContext("2d"),
canvasWidth = canvas.width,
canvasHeight = canvas.height;

而音频的播放,你必须需要一个audio音频元素。

var audio = document.getElementById("audio");

如果只是播放音频,则audio就足够了。但我们要分析音频数据,并将这些数据实时的反馈在画布上,所以需要另外一套方法,即使用本篇的主角–web audio,那让我们来看看如何使用它,步骤如下:

一、创建 web audio对象和分析器

运行web audio api前,我们必须先创建 web audio对象和分析器:

var audioCtx = new (window.AudioContext || window.webkitAudioContext)(),
analyser = audioCtx.createAnalyser(); // 提取音频数据,你需要AnalyserNode,它可以通过createAnalyser创建

音频分析器可以用来提取音频数据,当它创建完成后,接着需要落实到具体的音频上,即将音频元素和web audio对象关联起来:

var audioSource = audioCtx.createMediaElementSource(audio);

createMediaElementSource被用于创建一个MediaElementAudioSourceNode对象,它的使用方法如下:

audioCtx.createMediaElementSource(myMediaElement);

它有一个参数:myMediaElement,抓取音频数据的html多媒体元素,该方法返回html元素。

二、连接节点和设置数据输出格式

其次,我们需要将这些节点连接起来,音频源连接到分析器,分析器再连接到音频输出源。这里的输出源是web audio对象下的一个属性。要注意的是,analyser只是分析音频数据,并不会改变音频。

audioSource.connect(analyser);
analyser.connect(audioCtx.destination);。

一图胜千言:

然后,接下来就是设置音频信号输出格式。在web audio中,使用快速傅立叶变换(Fast Fourier Transform (fft) )来捕获音频数据,再通过分析器analyser的frequencyBinCount属性来获取存放音频缓冲区的数据长度,将这个数据长度设置为js数据化数组的长度:

analyser.fftSize = 256;
var bufferLength = analyser.frequencyBinCount,
dataArray = new Uint8Array(bufferLength);

三、将数据绘制画布

以上工作都完成后,则需要将数据绘制到canvas中,此处使用 requestAnimationFrame 定时器来更新音频信号。在绘制函数中,我们通过分析器analyser的getByteFrequencyData方法来获取波形数据:

var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame;

function draw() {

analyser.getByteFrequencyData(dataArray);

canvasCtx.fillStyle = 'rgb(0, 0, 0)';
canvasCtx.fillRect(0, 0, canvasWidth, canvasHeight);

var barWidth = (canvasWidth / bufferLength) * 2;
barHeight = 0 ,
barX = 0;

for(var i = 0; i < bufferLength; i++) {
barHeight = dataArray[i];
canvasCtx.fillStyle = "#f7d54e";
canvasCtx.fillRect(barX , canvasHeight-barHeight/2 , barWidth , barHeight);
barX += barWidth + 1;
}

drawTimer = requestAnimationFrame(arguments.callee);
}

参考: