HTML5可以不借助其他的插件仅仅通过浏览器实现非常酷炫的事情,而这篇文章就是关于借助three.js以及Web Audio接口来实现声音可视化的。Web Audio允许你在浏览器端操作音频,需要了解更多关于Web Audio的相关信息请移步至这 MDN Web Audio API。而关于THREE.JS,官网上说是一个让创建WebGL应用变得简单的javascript 3D库。这篇文章的目的就是以Web Audio接口获取音频信息并且通过three.js实现3D可视化。
让我们首先把过程分成单个的任务:
…
可以点这来查看已经完成的示例
…
创建一个3d场景并能让其看到需要下面三个最主要的元素:
function AudioVisualizer(){
//渲染
this.scene;
this.camera;
this.renderer;
this.controls;
}
AudioVisualizer类里面放置了所有必要的东西,下面需要一个一个地初始化three.js的必要元素,这里展示的函数用于创建一个Threejs场景,一个WebGL渲染器,一个相机以及一个光源,如果你想要更多关于Three.js的信息,我建议你去看看专注前端30年的博客。当然官网也是不错的选择(最好的选择)。
AudioVisualizer.prototype.initialize = function(){
//创建ThreeJS 场景
this.scene = new THREE.Scene();
//获取窗口长宽
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
//获取渲染器
this.renderer = new THREE.WebGLRenderer({antialias:true});
this.renderer.setSize(WIDTH,HEIGHT);
//创建并且加入相机
this.camera = new THREE.PerspectiveCamera(40,WIDTH/HEIGHT,0.1,20000);
this.camera.position.set(0,45,0);
this.scene.add(this.camera);
var that = this;
//update renderer size, aspect ratio and projection matrix on resize
//更新渲染器大小,方向(横竖)以及投影矩阵
window.addEventListener('resize', function () {
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
that.renderer.setSize(WIDTH, HEIGHT);
that.camera.aspect = WIDTH / HEIGHT;
that.camera.updateProjectionMatrix();
});
//背景颜色
this.renderer.setClearColor(0x333F47, 1);
//创建光源并添加到场景中
var light = new THREE.PointLight(0xffffff);
light.position.set(-100, 200, 100);
this.scene.add(light);
}
一旦3d场景创建好之后,我们就能在里面加入3d几何体,createBars 函数创建了0.5x0.5x0.5的长方体(当然目前是正方体),每个长方体都有一个随机的颜色,这样看起来更酷炫一点23333,每个创建的条状物(长方体)都存储在一个数组中,便于之后根据音频信息来改变它们的形状。
//创建可视化所需的条状物(长方体)
AudioVisualizer.prototype.createBars = function () {
//重复创建长方体
for (var i = 0; i < this.numberOfBars; i++) {
//长方体
var barGeometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);
//材质
var material = new THREE.MeshPhongMaterial({
color: this.getRandomColor(),
ambient: 0x808080,
specular: 0xffffff
});
//创建几何体框架并且放到特定的位置上
this.bars[i] = new THREE.Mesh(barGeometry, material);
this.bars[i].position.set(i - this.numberOfBars/2, 0, 0);
//将长方体放到场景中
this.scene.add(this.bars[i]);
}
};
…
现在我们有用来可视化的3d场景和3d块状物(条状物/长方体),下面就要从服务器或者用户自己的电脑里获得音频文件了,从服务器请求一个特定的文件并让它可视化确实没啥问题,但是如果用户自己可以把自己喜欢的音乐拉到里面,让他能够亲眼看到这牛逼的画面不是更有趣么。
下面的代码块可以直接读取拖到浏览器页面的文件,HTML真是牛逼坏了=。=
AudioVisualizer.prototype.handleDrop = function () {
//丢下文件
document.body.addEventListener("drop", function (e) {
e.stopPropagation();
e.preventDefault();
//获取文件
var file = e.dataTransfer.files[0];
var fileName = file.name;
$("#guide").text("Playing " + fileName);
var fileReader = new FileReader();
fileReader.onload = function (e) {
var fileResult = e.target.result;
visualizer.start(fileResult); //这里其实并没有真的开始
};
fileReader.onerror = function (e) {
debugger
};
fileReader.readAsArrayBuffer(file);
}, false);
}
…
终于到了最为关键的时刻了!音频文件信息获取之后,我们得把它传递给之前创建的3d场景中,为了能够可视化,还需创建一些Web Audio元素并且将它们连接起来,没错,你没听错就是连接
这些元素是:
这些节点要以下面这样的方式链接起来,我们不需要知道这些功能的具体细节,因为我们又不是给好莱坞做一个重磅音频可视化产品-。-
我们需要创建一个脚本处理器(Script Processor),脚本处理器是一个可以用javascript来做音频输出处理的音频处理节点。
提醒一下,脚本处理器已经被弃用了,具体细节请查看这里,本译者将在另外一篇博客中介绍更好的方法。
注意:这个特性在2014年8月29日发布的Web Audio API规范中已经标记为不推荐,将很快会被Audio Workers代替.
下面我们将创建一个源缓冲来放置音频,分析器(analyser)可以提供音频的实时信息,便于我们渲染与之相关的3d场景
首先将源缓冲与分析器连接起来,分析器连接javascript节点源缓冲连接destination,destination其实就是音频输出,如果不将destination与源缓冲连接起来的话,就算我们能看到显示出来的东西,也不能听到声音
AudioVisualizer.prototype.setupAudioProcessing = function () {
//获取AudioContext
this.audioContext = new AudioContext();
//创建javascript节点
this.javascriptNode = this.audioContext.createScriptProcessor(2048, 1, 1);//此处参数为缓冲区大小(2的倍数),输入声道与输出声道
this.javascriptNode.connect(this.audioContext.destination);
//创建音源
this.sourceBuffer = this.audioContext.createBufferSource();
//创建分析器
this.analyser = this.audioContext.createAnalyser();
this.analyser.smoothingTimeConstant = 0.3;
this.analyser.fftSize = 512;
//将音源与分析器连接
this.sourceBuffer.connect(this.analyser);
//分析器与javascript节点连接
this.analyser.connect(this.javascriptNode);
//分析器与音频输出连接(就是喇叭--。耳机等等)
this.sourceBuffer.connect(this.audioContext.destination);
var that = this;
//这里就是将喇叭信息经过javascript处理并且可视化的过程
this.javascriptNode.onaudioprocess = function () {
// 通过分析器解析出音频频率与音强信息
var array = new Uint8Array(that.analyser.frequencyBinCount);
that.analyser.getByteFrequencyData(array);
//渲染
visualizer.renderer.render(visualizer.scene, visualizer.camera);
var step = Math.round(array.length / visualizer.numberOfBars);
//循环改变不同长方体在z轴上的缩放
for (var i = 0; i < visualizer.numberOfBars; i++) {
var value = array[i * step] / 4;
value = value < 1 ? 1 : value;
visualizer.bars[i].scale.z = value;
}
}
};
'onaudioprocess’事件会在有声音播放的时候一直触发并提供音频信息,这个方法可以从分析器那获取频率信息,渲染场景,根据不同频率的音强变化改变长方体的z轴上的缩放
(译者按:此处使用的onaudioprocess事件有性能上的问题,当创建的ScriptProcessor缓冲区大小为2048时,每秒只有22次左右的触发,使用谷歌浏览器69.0,所以在显示的时候长方体的变化看起来有点卡卡的,而且这个函数在没有播放声音的时候也会触发,将其改为1024会好很多 (值越小则可能导致一定的延迟)(取值256, 512, 1024, 2048, 4096, 8192, 16384),其实也可以不写)
…
所有用于处理的函数都设置好了,下面就要开始进行音频处理。我们从文件读取器(fileReader)读取文件并且用"audioContext.decodeAudioData"这个方法来解析出音频信息。这个方法有两个回调,一个是解析失败,一个是解析成功,解析成功之后将其放置在一个缓冲之中,然后就可以通过"start()"函数开始播放音频,当音频播放的时候"javascriptNode.onaudioprocess"将会被持续触发并输出当前时间的音频频率信息,在3d场景中获得这些信息并把它展现出来
//开始处理音频信息
AudioVisualizer.prototype.start = function (buffer) {
this.audioContext.decodeAudioData(buffer, decodeAudioDataSuccess, decodeAudioDataFailed);
var that = this;
function decodeAudioDataSuccess(decodedBuffer) {
//decodedBuffer为解析成功之后的音频缓冲
that.sourceBuffer.buffer = decodedBuffer
that.sourceBuffer.start(0);
}
function decodeAudioDataFailed() {
debugger
}
};
…
下面的方法用于生成一个随机的颜色,来源于stackoverflow上面的一个问题的答案:随机颜色生成
AudioVisualizer.prototype.getRandomColor = function () {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
};
可以让场景放大缩小旋转的three.js小工具,OrbitControls.js,
将其添加到初始化的函数中(initialize)
this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
并将下面这行代码放到’onaudioprocess’函数中
visualizer.controls.update();
…
下面为作者的完整代码
https://github.com/Raathigesh/HTML5AudioVisualizer
这篇文章提供了一个用WebAudio接口和three.js将音频信息可视化的方法,目前看来javascriptNode,HTML5的WebAudio 接口还不够稳定,这些代码可能会失效(但是我会跟进的),html5可以做很多疯狂而又酷炫的事情,敲下这些代码的时候我还是蛮开心的,做出来的结果也非常满意,继续用html5震撼世界吧 233333.
文章来源
作者 Raathigeshan
译者 角角兔
相关作品: