Web Audio API 实现音频可视化
声明:本文为原创文章,如需转载,请注明来源WAxes,谢谢!
一转眼就已经有三个月没写博客了,毕业季事情确实多,现在也终于完全毕业了,博客还是不能落下。偶尔还是要写一下。
玩HTML5的Audio API是因为之前看到博客园里有关于这个的博客,觉得挺好玩的,所以就学习了一下。本文仅作为自己的学习记录。如有错误之处请指出。
最终的效果也就如右图,园友们可以自己去玩一下
DEMO链接:请戳我!!! 可以选择本地音频文件进行播放,也可以听楼主的音乐哈
同时,这个API目前浏览器支持度不高,PC浏览器支持较好的仅firefox、chrome以及safari,移动端就更少的,android5.0才支持,safari是6.1以上版本支持。
因此,若要用于生产环境,请自行斟酌。
WebAudio从获取数据到播放整个流程可以用一张图解释:
有点像nodejs里的pipe流式传输,input是Audio的输入节点,可以为buffer,也可以为audio对象。Effects为各个操控音频的节点,我自己用到的就只有GainNode以及AnalyserNode,GainNode可以用来控制音频音量的大小,默认值为0,也就是静音,如果设为1才有声音,如果设的更高的值,就会更高音。而AnalyserNode是用来获取音频大小的数值。
还有其他很多节点,其他节点的话个人感觉是一些比较高级的音频处理,我是不知道怎么用,有兴趣的可以自行去mdn上查询。
回归正题:说下该效果改如何实现,首先,要做成这种效果,要分几步:
1、获取音频文件,实例化一个音频容器对象。
2、通过FileReader把音频文件转成ArrayBuffer后再对其进行解码。
3、用解码后的buffer实例化一个AudioBuffer对象。
4、使用AnalyserNode接口实例化一个分析器节点。
5、使用connect方法将AudioBuffer对象连接至AnalyserNode,如果想用GainNode,就再用connect方法,把AnalyserNode跟GainNode连接,然后再接到最终的音频播放节点:Destination,开始播放音频
6、在音频播放的时候通过AnalyserNode获取音频播放时的各个频率值并转成8bit的ArrayBuffer。
7、根据上面的arraybuffer里的各个值在canvas上画出相应的条形图即可。
大概说起来就以上几步,具体代码分析如下:
先将要用到的对象先定义好:其中包括audioContext音频容器对象,以及canvas的2d绘图环境对象,requestAnimationFrame的兼容性写法。
var music = document.getElementById("music"),canvas = document.getElementById("cas"),ctx=canvas.getContext("2d"); window.AudioContext= window.AudioContext||window.webkitAudioContext||window.mozAudioContext;
window.RAF = (function(){
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {window.setTimeout(callback, 1000 / 60); };
})();
var AC = new AudioContext();
然后就获取音频文件,可以直接通过input file来获取,或者用xhr也行。楼主为了方便,做的demo上就是直接用input file来获取音频文件。代码如下:通过onchange事件来获取到音频文件music.file[0]。再对音频文件进行解码,也就是changeBuffer方法要做的事。
music.onchange = function(){
if(music.files.length!==0){
changeBuffer(music.files[0]);
}
}
获取到了音频文件,先用FilreReader将文件转成ArrayBuffer对象,在加载完后可以通过e.target.result获取到文件内容。
然后再对文件内容进行解码,用到的就是audioContext对象里的decodeAudioData方法。根据官方API文档得知,该方法有三个参数:第一个是就是音频ArrayBuffer对象,第二个是成功解码完毕后的回调,第三个是解码失败后的回调
function changeBuffer(file){
var fr = new FileReader();
fr.onload = function(e){
var fileResult = e.target.result;
AC.decodeAudioData(fileResult , function(buffer){
playMusic(buffer)
}, function(e){
console.log(e)
alert("文件解码失败")
})
}
fr.readAsArrayBuffer(file);
}
解码成功后调用playMusic方法,并且传入解码后的buffer数据,此时实例化一个AudioBufferSource对象,AudioBufferSource对象的属性有五个。分别是:buffer、playbackRate、loop、loopstart和loopend,buffer自然就是音频buffer数据,playbackRate是渲染音频流的速度,其默认值是1。loop则是播放循环属性,默认为false,如果设为true则会循环播放音频。loopstart和loopend则是循环开始和结束的时间段,以秒为单位,默认值均为0,只有当loop的值为true的时候这两个属性才会起效。
下面的playMusic方法不仅处理了buffer的播放,如果传入的是audio dom对象也会进行相应的转换。但是注意,如果是audio对象转出来的audioSource,就不会有上面AudioBufferSource的方法,毕竟audio dom对象本身有方法可以控制自己的播放。
实例化AudioBufferSource对象后,就像上面说的一样,接入analyserNode,analyserNode再接入gainnode,然后最终gainnode再接入audioContext.destination。
准备完毕后,如果源是bufferSource则调用start方法播放音频,否则就是用audio 的play方法播放音频。
播放后就跳转到canvas的绘图方法animate中,将音谱绘制出来。
//音频播放
function playMusic(arg) {
var source;
//如果arg是audio的dom对象,则转为相应的源
if (arg.nodeType) {
audioSource = audioSource || AC.createMediaElementSource(arg);
source = audioSource;
} else {
bufferSource = AC.createBufferSource(); bufferSource.buffer = arg; bufferSource.onended = function () {
app.trigger(singleLoop ? nowIndex : (nowIndex + ));
}; //播放音频
setTimeout(function () {
bufferSource.start()
}, ); source = bufferSource;
} //连接analyserNode
source.connect(analyser); //再连接到gainNode
analyser.connect(gainnode); //最终输出到音频播放器
gainnode.connect(AC.destination);
}
然后获取到analyser节点里的频率长度,根据长度实例化一个8位整型数组,通过analyser.getByteFrequencyData将analyser节点中的频率数据拷贝进数组。因为数组为8位数组,即每个值的大小就为0~256,然后就可以根据这个值即各个频率的信号量进行绘制不同的条形图,每个条形图我也抽象成了对象,在每一帧对各个条形图进行修改就完成了最简单的音频动画了。
条形图对象代码:
//音谱条对象
function Retangle(w, h, x, y) {
this.w = w;
this.h = h; //小红块高度
this.x = x;
this.y = y;
this.jg = 3;
this.power = 0;
this.dy = y; //小红块位置
this.initY = y;
this.num = 0;
}; var Rp = Retangle.prototype; Rp.update = function(power){
this.power = power;
this.num = ~~(this.power / this.h + 0.5); //更新小红块的位置,如果音频条长度高于红块位置,则红块位置则为音频条高度,否则让小红块下降
var nh = this.dy + this.h;//小红块当前位置
if (this.power >= this.y - nh) {
this.dy = this.y - this.power - this.h - (this.power == 0 ? 0 : 1);
} else if (nh > this.y) {
this.dy = this.y - this.h;
} else {
this.dy += 1;
} this.draw();
}; Rp.draw = function(){
ctx.fillStyle = grd;
var h = (~~(this.power / (this.h + this.jg))) * (this.h + this.jg);
ctx.fillRect(this.x, this.y - h, this.w, h)
for (var i = 0; i < this.num; i++) {
var y = this.y - i * (this.h + this.jg);
ctx.clearRect(this.x - 1, y, this.w + 2, this.jg);
}
ctx.fillStyle = "#950000";
ctx.fillRect(this.x, ~~this.dy, this.w, this.h);
};
循环动画方法:
function animate() {
if(!musics[nowIndex].decoding){
ctx.clearRect(0, 0, canvas.width, canvas.height); //出来的数组为8bit整型数组,即值为0~256,整个数组长度为1024,即会有1024个频率,只需要取部分进行显示
var array_length = analyser.frequencyBinCount;
var array = new Uint8Array(array_length);
analyser.getByteFrequencyData(array); //将音频节点的数据拷贝到Uin8Array中 //数组长度与画布宽度比例
var bili = array_length / canvas.width; for (var i = 0; i < rt_array.length; i++) {
var rt = rt_array[i];
//根据比例计算应该获取第几个频率值,并且缓存起来减少计算
rt.index = ('index' in rt) ? rt.index : ~~(rt.x * bili);
rt.update(array[rt.index]);
} copy();
}else {
showTxt("音频解码中...")
} RAF(animate);
}
为了让整个条形图更美观,所以还加入了一个半透明投影效果:
//制造半透明投影
function copy() {
var outctx = outcanvas.getContext("2d");
var imgdata = ctx.getImageData(0, 0, canvas.width, canvas.height / 2);
for (var i = 0; i < imgdata.data.length; i += 4) {
imgdata.data[i + 3] = 30;
}
outctx.putImageData(imgdata, 0, 0);
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(Math.PI);
ctx.scale(-1, 1);
ctx.drawImage(outcanvas, -canvas.width / 2, -canvas.height / 2)
ctx.restore();
}
后期对代码有所更改,若要最新源码请见github地址:
https://github.com/whxaxes/canvas-test/blob/gh-pages/src/Funny-demo/musicPlayer/
Web Audio API 实现音频可视化的更多相关文章
- 【HTML5】Web Audio API打造超炫的音乐可视化效果
HTML5真是太多炫酷的东西了,其中Web Audio API算一个,琢磨着弄了个音乐可视化的demo,先上效果图: 项目演示:别说话,点我! 源码已经挂到github上了,有兴趣的同学也可以去st ...
- Web Audio API之手把手教你用web api处理声音信号:可视化音乐demo
1.Web Audio API 介绍 Web Audio API 提供了在Web上控制音频的一个非常有效通用的系统 ,这些通用系统通俗的讲就是我们可以利用Web Audio API提供的各种方法操作各 ...
- HTML5 ——web audio API 音乐可视化(二)
上一篇 web audio API 音乐可视化(一)介绍了一些基本的API,以及如何简单的播放一个音频,本篇介绍一下怎么对获取到的音频进行分析,并将分析后的数据绘制成图像. 最终效果请戳这里; 完整版 ...
- HTML5 ——web audio API 音乐可视化(一)
使用Web Audio API可以对音频进行分析和操作,最终实现一个音频可视化程序. 最终效果请戳这里; 完整版代码请戳这里,如果还看得过眼,请给一个start⭐ 一.API AudioContext ...
- 关于HTML5音频——audio标签和Web Audio API各平台浏览器的支持情况
对比audio标签 和 Web Audio API 各平台浏览器的支持情况: audio element Web Audio API desktop browsers Chrome 14 Yes ...
- H5的Web Audio Api
概述 研究Web Audio Api的主要原因是:工作中需要在ios中实现声音的淡出效果,主要是通过setInterval来改audio标签的volume属性实现的,但是ios上面volume属性是只 ...
- 关于Web Audio API的入门
Web Audio API提供了一个简单强大的机制来实现控制web应用程序的音频内容.它允许你开发复杂的混音,音效,平移以及更多. 可以先看一下MDN的这篇文章<Web Audio API的运用 ...
- 使用Web Audio API绘制音波图
摘要:Web Audio API是对<audio> 标签功能上的补充,我们可以用它完成混音.音效.平移等各种复杂的音频处理,本文简单的使用其完成音波图的绘制. PS:本例子使用ES6编程, ...
- 【Web Audio API】 — 那些年的 web audio
转 TAT.Jdo:[Web Audio API] - 那些年的 web audio 这主题主要是早期对 web audio api的一些尝试,这里整理一下以便以后翻阅,如有错误,诚请指正. 在这之前 ...
随机推荐
- 金士顿U盘,群联PS2251-60主控,量产CDROM教程
量产前准备: 1. 插上U盘,(台式机的话插机箱后面) 2. 一台电脑,最好不要装杀毒软件(特别是360) 3. ISO镜像文件 4. 下载MPALL v3.29.0B.zip 请先耐心看完教程: 1 ...
- linux rpm 安装和卸载
[root@wang Packages]# mount /dev/cdrom /mnt 挂载 [root@wang Packages]# rpm -ivh zip-3.0-1.el6.x86_64.r ...
- 通过vmstat命令判断服务器瓶颈
linux命令vmstat介绍 vmstat介绍 通过STATSPACK收集服务器信息,主要通过收集VMSTAT的信息来展现服务器状况.VMSTAT工具是最常见的UNIX监控工具,可以展现给定时 间间 ...
- IE10、IE11 User-Agent 网站无法写入Cookie 问题[转]
你是否遇到过当使用一个涉及到Cookie操作的网站或者管理系统时,IE 6.7.8.9下都跑的好好的,唯独到了IE10.11这些高版本浏览器就不行了?好吧,这个问题码农连续2天内遇到了2次.那么,我们 ...
- C#基础---委托的使用
一:什么是委托 委托是一种定义方法签名的类型当实例化委托时,您可以将其实例与任何具有兼容签名的方法相关联.您可以通过委托实例调用方法.委托是一个引用类型,所以它具有引用类型所具有的通性.它保存 ...
- Shell命令行操作
1.1 shell提示符 [me@linuxbox ~]$ 如果最后一个字符是"#",表示当前终端会话有超级用户权限.使用root用户登录或者使用能提供超级用户权限的终端能获得该权 ...
- libsvm Minist Hog 手写体识别(源码文件)
以上是我上一篇文章中的代码实现,里面分别用了opencv中的SVM和LibSVM,opencv的SVM用起来更方便,但貌似内部其实也是基于Libsvm,同样的参数训练出来的结果是一致的,里面有Libs ...
- AngularJs学习总结-了解基本特性(-)
现在的前端项目中基本上都会用到angularjs框架,之前并不了解这个框架,也是因为最近接手的项目,所以打算好好的学习下它.之前都是搞pc端,现在接手的是移动端的项目,移动端UI框架用的是ionic+ ...
- POJ1523 SPF[无向图割点]
SPF Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 8139 Accepted: 3723 Description C ...
- 面试题:return和finally执行
Demo类: public class Demo { public int get() { int x=1; try { x++; return x; }finally{ ++x; } } } Tes ...