Web Audio API DEMO - W·Axes

一转眼就已经有三个月没写博客了,毕业季事情确实多,现在也终于完全毕业了,博客还是不能落下。偶尔还是要写一下。

玩HTML5的Audio API是因为之前看到博客园里有关于这个的博客,觉得挺好玩的,所以就学习了一下。本文仅作为自己的学习记录。如有错误之处请指出。

最终的效果也就如右图,楼主只是简单的做了个demo,如果要有更复杂的效果,园友们可以自己去玩一下

DEMO链接: 请戳我!!!     选择音频文件后即可播放

同时,这个API目前浏览器支持度不高,若要用于生产环境,请自行斟酌。

首先,要做成这种效果,要分几步:

1、获取音频文件,实例化一个音频容器对象。

2、通过FileReader把音频文件转成ArrayBuffer后再对其进行解码。

3、将解码后的buffer数据通过AudioBufferSourceNode接口传给音频容器对象并且播放。

4、使用AnalyserNode接口实例化一个分析器。

5、使用分析器获取音频播放时的各个频率。

6、根据频率在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的时候这两个属性才会起效。

实例化AudioBufferSource对象后,要给与音频一个输出目的地,也就是要将音频连接到扬声器上,通过connect(audioContext.destination)连接。

然后创建一个分析器,直接通过createAnalyser方法创建一个分析器。同样,通过connect方法将音频跟分析器连接起来。

准备完毕后,则调用start方法,开始播放音频。然后再跳转到canvas的绘图方法animate中,将音谱绘制出来。

var analyser;
		function playMusic(buffer){
			var absn = AC.createBufferSource();
			analyser = AC.createAnalyser();
			absn.connect(analyser);
			absn.connect(AC.destination);
			absn.buffer = buffer;
			absn.loop = true;
			absn.start(0);
			animate()
		}

前面两段代码楼主也不是很懂,看了官方API得知analyser的frequencyBinCount的值为:Half the FFT size,而据楼主网上查的资料得知FFT是离散傅立叶变换的快速算法,可以将一个信号变换 到频域。有些信号在时域上是很难看出什么特征的,但是如 果变换到频域之后,就很容易看出特征了。同时FFT还可以将一个信号的频谱提取出来。也就是说这两段代码应该就是使用FFT算法将音频各个频率的信息提取出来转换成数组,数组里的每一个值都代表音频在当前频率的信号量。根据这些信号量就可以很清晰的看出各个频率的差别

获取到各个频率的信号量后,就可以通过这些参数进行绘制不同的条形图,就完成了最简单的音频动画了。

function animate(){
	var array = new Uint8Array(analyser.frequencyBinCount);
	analyser.getByteFrequencyData(array);
ctx.clearRect(
0,0,canvas.width,canvas.height); for(var i=0;i<array.length;i+=10){ ctx.fillRect(i,canvas.height-array[i] , 10 , array[i]); ctx.strokeStyle = "#FFF" ctx.strokeRect(i,canvas.height-array[i] , 10 , array[i]); } RAF(animate) }

下面贴出全部代码:

<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8" />
	<title>Document</title>
	<style type="text/css">
		#cas{
			position: absolute;
			left:0;top:0;bottom: 0;right: 0;
			margin: auto;
			border: 1px solid;
		}
	</style>
</head>
<body>
	<input type="file" name="" id="music" />
	<canvas id="cas" width="1000" height="540"></canvas>
	<script type="text/javascript" charset="utf-8">
		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();
		
		music.onchange = function(){
			if(music.files.length!==0){
				changeBuffer(music.files[0]);
			}
		}
		
		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);
		}
		
		var analyser;
		function playMusic(buffer){
			var absn = AC.createBufferSource();
			analyser = AC.createAnalyser();
			absn.connect(analyser);
			absn.connect(AC.destination);
			absn.buffer = buffer;
			absn.loop = true;
			absn.start(0);
			animate()
		}
		
		function animate(){
			var array = new Uint8Array(analyser.frequencyBinCount);
			analyser.getByteFrequencyData(array);
			ctx.clearRect(0,0,canvas.width,canvas.height);
			for(var i=0;i<array.length;i+=10){
				ctx.fillRect(i,canvas.height-array[i] , 10 , array[i]);
				ctx.strokeStyle = "#FFF"
				ctx.strokeRect(i,canvas.height-array[i] , 10 , array[i]);
			}
			RAF(animate)
		}
	</script>
</body>
</html>
View Code
我来评几句
登录后评论

已发表评论数()

相关站点

热门文章