音谱可视化:Audio API开发

效果展示&介绍 本篇的可视化代码主要是根据MIT的2014年2月15日的开源代码修改而来的 MIT音谱可视化->Github MIT音谱可视化图:  

效果展示&介绍

本篇的可视化代码主要是根据MIT的2014年2月15日的开源代码修改而来的
MIT音谱可视化->Github
MIT音谱可视化图:
MIT音谱可视化图 
进行修改的音谱可视化图
这里写图片描述 

MIT的音频其实是从通过input标签来获取的,存入缓存中.但是其实我们用的比较多的是html5中的Audio标签,所以将其修改过后,便可对audio的src资源进行读取,并且可以用audio的控制按钮进行音频流的控制.

用audio的音谱可视化 

分析过程

要想做到音谱可视化的结果,那么我们需要什么?
1.获取音频,那么我们可以用audio直接获取音频资源(当然也可以input获取,本篇不做相关介绍)
2.得到音频的频率大小,我们可以使用web Audio API来获取到数值
3.通过频率数值画出波形线,我们可以用画布(canvas)来描绘图形.

获取音频

我们可以直接在html文档中加入audio标签即可:

audio的更多信息参考W3cschool

得到音频的频率大小

这里需要使用到的就是audio api了.我们可以在MSD了解到audio api 的使用方法(网址:https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Audio_API)
在这里我们做简要的介绍:首先创建audioContext对象->需考虑浏览器不同厂商的兼容问题.然后从audio标签中获得媒体资源,并通过audioContext对象的创造媒体节点的函数创造节点.将媒体节点连接到分析音频的处理上,最后输出(audioContext.deestination).我们在分析音频的这个节点上对音频的频率再做提取,并将其可视化.

画出可视化图形

很明显这里需要用到的就是canvas标签和其后的javascript的相关知识.在这里我们描绘的是曲线所以要了解如何用canvas描绘巴塞尔曲线
巴塞尔曲线
绘制一条二次巴塞尔曲线

代码呈现

在编写代码时,参考MIT的开源代码,我们可以创建一个Visualizer对象来实现我们的功能:


var Visualizer = function()
{this.audioContext = null;//音频上下文this.source = null;//音频资源this.animationId = null;//动画IDthis.status = 0;//标志来判断是否在播放this.forceStop = false;
}Visualizer.prototype =
{ini: function()//初始化函数{this._preparetionAPI();},_preparetionAPI: function()//准备Audio API{//针对不同浏览器厂商window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext;window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame;window.cancelAnimationFrame = window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.msCancelAnimationFrame;//requestAnimationFrame->请求动画//异常处理,若创建audioContext对象出错则警告其errortry{this.audioContext = new AudioContext();}catch( e ){alert( e );console.log(e);}//调用开始函数this._start();},_start:function(){var audioContext = this.audioContext;if( audioContext === null ){return ;}//开始可视化this._visualize(audioContext);},_visualize:function(audioContext){var myAudio = document.getElementById("audio");//获取音频资源var audioSourceNode = audioContext.createMediaElementSource(myAudio);//生成了媒体资源节点var gainNode = audioContext.createGain();//创建Gain节点var analyser = audioContext.createAnalyser();//创造分析节点var that = this;audioSourceNode.connect(gainNode);gainNode.connect(analyser);analyser.connect(audioContext.destination);//节点间的连接操作if (!audioSourceNode.start) {audioSourceNode.start = audioSourceNode.noteOn //in old browsers use noteOn methodaudioSourceNode.stop = audioSourceNode.noteOff //in old browsers use noteOff method};if( this.animationId !== null ){cancelAnimationFrame( this.animationId );//针对变换曲目的重新可视化的操作,取消上一曲目的可视化}if( this.source !== null ){this.source.stop(0);}this.status = 1;this.source = audioSourceNode;audioSourceNode.onended =function(){that._audioEnd(that);//结束操作};this._drawQuadratic(analyser);//开始描绘},_drawQuadratic: function( analyser ){var that = this;var canvas = document.getElementById("canvas");//获取画布对象var cwidth = canvas.width;var cheight = canvas.height;//获取画布的长和宽var meterNum = 110;//波形图的波数var ctx = canvas.getContext('2d'),gradient = ctx.createLinearGradient(0,0,0,300);gradient.addColorStop(1, "#bd4cce");gradient.addColorStop(0.6, '#005c58');gradient.addColorStop(0, '#6e00ff');//创建渐变stylevar drawMeter =function()//单次的描绘函数{var array = new Uint8Array( analyser.frequencyBinCount );analyser.getByteFrequencyData(array);//获取频率大小,并集合为一个数组if( !that.status ){cancelAnimationFrame( that.animationId );//判断是否终止动画return;}var step = Math.round( array.length / meterNum );//根据我们需要的波数设置跨度ctx.clearRect(0, 0, cwidth, cheight );//每次调用的清屏操作var field_ini = 5;//设置每个波的半个周期var sum_field = 0;//总的周期var value_low = 1;//降低波的频率大小,以适应画布的大小for( var i = 0; i < meterNum; i++ )//开始描绘{var value = array[array.length - (i+1) * step ];//获取频率,这里是从低频开始获取value /= value_low;//降低频率值if( i >= meterNum - 2 )//最后两个波不显示为直线,为了好看{value = 0;}if( i % 2 == 0 )//震荡效果{value = -value;}ctx.beginPath();ctx.strokeStyle = gradient; //set the strokeStyle to gradient for a better look//一下四步操作是为了描绘一个波的操作,这里不做详解,自行研究ctx.moveTo(sum_field, cheight / 2 );ctx.quadraticCurveTo(sum_field + 2 * ( field_ini / 6 ), cheight / 2 + value , sum_field + field_ini / 2, cheight / 2 + value);ctx.moveTo( sum_field + field_ini, cheight / 2);ctx.quadraticCurveTo(sum_field + 4 * ( field_ini / 6 ), cheight / 2 + value , sum_field + field_ini / 2, cheight / 2 + value);sum_field += field_ini;field_ini += 0;if( i < 10 ){value += 0.05;}else if( i > 10 && i < 45 ){value_low += 0.5;    }else if( i > 80 ){value_low -= 0.55;  }ctx.stroke();}//获取动画IDthat.animationId = requestAnimationFrame(drawMeter);}//调用函数,并获取动画IDthis.animationId = requestAnimationFrame(drawMeter);},_audioEnd: function(){if( this.forceStop ){this.forceStop = false;this.status = 1;return ;};this.status = 0;}
}

当然我们需要在页面加载的时候就生成这个对象,所以:

window.onload = function()
{new Visualizer().ini();
}