分类
Canvas JavaScript Web Audio API 例子demo 教程

做一个酷酷的音乐频谱

先上个demo


[dm href=’http://zxycc.cc/demo/music/’]音乐频谱[/dm]

AudioAPI的基本概念

H5的Web Audio API可以很方便的使用(虽然各家浏览器实现的标准都不太一样)各种音频功能,比如可以用麦克风录制声音然后生成音频文件,还可以对声源定位,做那种3D音效,混音等等,听过3D音效的都知道,声音一会左,一会右的,还支持实时的声音分析,根据分析的数据可以做一些可视化效果等等。
其中AudioContext是Web Audio API的基石,AudioContext对象可以“线性”处理字节流。
这个线性的意思就是用Web Audio的信号传递途径:
[v_act]首先要建立音频的前后境况(Context)[/v_act][v_act]在境况内设定音频的输入源[/v_act][v_act]加入各种音响效果[/v_act][v_act]设定音频的输出终点[/v_act][v_act]将音频的输入,效果,输出终点连接起来[/v_act]
如图

AudioAPI的大部分操作都是通过一个个连接的节点完成的,这些节点需要连通,从声源节点到输出节点都必须保持通畅才能正常工作。就像在电路上连接一个个元件来完成不同的工作,最后连接到扬声器上。
最简单的路线就是从声源直接连接到输出节点:source → destination
输出节点在AudioContext实例的destination上可以找到,而声源节点却有很多。MediaElementSource、MediaStreamSource、BufferSource、Oscillator、createScriptProcessor,这些都是声源节点。它们都是可以产生波,并传输给下一个节点的。所以要让AudioAPI发出声音,最简单的代码可以这么写:

var AudioContext = AudioContext||webkitAudioContext;
var context = new AudioContext;
var oscillator = context.createOscillator();
oscillator.connect(context.destination);
oscillator.start(0);

直接从声源连接到输出节点是最简单的用法,AudioAPI还提供了很多节点用于对音频的特殊处理。比如Gain节点用来调整音量、BiquadFilter节点用来过滤一些数据。当数据从这些节点上流过时就会被做相应的处理。
这些节点的连接也不是一对一那么简单的,它可能一对多,比如一个声源头可以同时给多个节点处理,之后再把这些中间节点汇总起来,这就要关心这些节点的分支与汇总的问题了。
总之,AudioAPI的设计就像是电路设计,有机地组合它所提供的节点就可以完成几乎所有音频处理。

直接上代码

通过HTML Media元素流式加载

使用audio元素流式加载音乐文件, 在JavaScript中调用createMediaElementSource方法, 直接操作HTMLMediaElement。


现在audio标签可以用来播放音乐了。

创建canvas画布


 

编写js脚本

var audio = document.getElementById("audio");
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
//创建境况
var AudioContext = window.AudioContext || window.webkitAudioContext;
var audioContext = new AudioContext();
//创建输入源
var source = audioContext.createMediaElementSource(audio);
//用createAnalyser方法,获取音频时间和频率数据,实现数据可视化。
var analyser = audioContext.createAnalyser();
//连接:source → analyser → destination
source.connect(analyser);
//声音连接到扬声器
analyser.connect(audioContext.destination);
/*存储频谱数据,Uint8Array数组创建的时候必须制定长度,
长度就从analyser.frequencyBinCount里面获取,长度是1024*/
var   arrData = new Uint8Array(analyser.frequencyBinCount), 
	count = Math.min(500,arrData.length), //能量柱个数,不能大于数组长度1024,没意义
	/*计算步长,每隔多少取一个数据用于绘画,意抽取片段数据来反映整体频谱规律,
           乘以0.6是因为,我测试发现数组长度600以后的数据基本都是0了,
           画出来能量柱高度就是0了,为了效果好一点,所以只取前60%,
           如果为了真实可以不乘以0.6
        */
	step = Math.round(arrData.length * 0.6 / count),
	value = 0, //每个能量柱的值
	drawX = 0, //能量柱X轴位置
	drawY = 0, //能量柱Y轴坐标
	height = canvas.height = window.innerHeight,//canvas高度
	width = canvas.width = window.innerWidth,//canvas宽度
	//能量柱宽度,设置线条宽度
	lineWidth = context.lineWidth = canvas.width / count;
	//设置线条宽度
	context.lineWidth = lineWidth;
//渲染函数
function render() {
	//每次要清除画布
	context.clearRect(0, 0, width, height);
	//获取频谱值
	analyser.getByteFrequencyData(arrData);
	for(var i = 0; i < count; i++) {
		//前面已经计算好步长了
		value = arrData[i * step + step];
		//X轴位置计算
		drawX = i * lineWidth;
		/*能量柱的高度,从canvas的底部往上画,那么Y轴坐标就是画布的高度减去能量柱的高度,
                   而且经测试发现value正常一般都比较小,要画的能量柱高一点,所以就乘以2,
                   又防止太高,取了一下最大值,并且canvas里面尽量避免小数值,取整一下
                 */
		drawY = parseInt(Math.max((height - value * 2), 10));
		//开始一条路径
		context.beginPath();
		/*设置画笔颜色,hsl通过这个公式出来的是很漂亮的彩虹色
		   H:Hue(色调)。0(或360)表示红色,120表示绿色,240表示蓝色,
                   也可取其他数值来指定颜色。取值为:0 - 360
		   S:Saturation(饱和度)。取值为:0.0% - 100.0%
		   L:Lightness(亮度)。取值为:0.0% - 100.0%
		 */
		context.strokeStyle = "hsl( " + Math.round((i * 360) / count) + ", 100%, 50%)";
		//从X轴drawX,Y轴就是canvas的高度,也就是canvas的底部
		context.moveTo(drawX, height);
		//从X轴drawX,Y轴就是计算好的Y轴,是从下往上画,这么理解
		context.lineTo(drawX, drawY);
		/*stroke方法才是真正的绘制方法,顺便也相当于结束了这次的绘画路径,
                   就不用调用closePath方法了
                */
		context.stroke();
	}
        //用requestAnimationFrame做动画
	requestAnimationFrame(render);
}
//调用render函数
render();
//自适应处理
function resize(){
	height = canvas.height = window.innerHeight;
	width = canvas.width = window.innerWidth;
        //能量柱宽度,设置线条宽度
	context.lineWidth = lineWidth = canvas.width / count;
}
window.addEventListener("resize",resize,false);

最后其实我还有一个功能更完善的demo

[dm href=’https://node.zxycc.cc/’]音乐频谱(手动点击播放,点击打开按钮,支持回车搜索)[/dm]

由a'ゞ『完美』

一个前端小白菜

“做一个酷酷的音乐频谱”上的16条回复

牛逼,在下佩服,这才是我一直追求的音乐播放器频谱效果,顺便求解几个疑问. 邮箱:504590446@qq.com

评论已关闭。