// use XHR to load an audio track, and // decodeAudioData to decode it and stick it in a buffer. // Then we put the buffer into the source function getData() { var request = new XMLHttpRequest(); //开一个请求 request.open('GET', url, true); //往url请求数据 request.responseType = 'arraybuffer'; //设置返回数据类型 request.onload = function() { var audioData = request.response; //数据缓冲完成之后,进行解码 audioCtx.decodeAudioData(audioData, function(buffer) { source.buffer = buffer; }, function(err) { alert(‘!Fail to decode the file!’); //解码出错处理 }); }; request.send(); }
本地获取的话需要通过文件类型的input标签来进行文件选择,监听input的onchnage事件,一担文件选中便开始在代码中进行文件读入,此处用到file reader来读取文件,同样的读取结果的数据类型也设置为'ArrayBuffer'。我的项目使用了file reader本地读取的办法,兼顾移动端。
var audioInput = document.getElementById("uploader"); //HTML语句:<input type="file" /> audioInput.onchange = function() { //文件长度不为0则真的选中了文件,因为用户点击取消也会触发onchange事件。 if (audioInput.files.length !== 0) { files = audioInput.files[0]; //得到用户选取的文件 //文件选定之后,马上用FileReader进行读入 fr = new FileReader(); fr.onload = function(e) { var fileResult = e.target.result; //文件读入完成,进行解码 audioCtx.decodeAudioData(fileResult, function(buffer) { source.buffer = buffer;//将解码出来的数据放入source中 //转到播放和分析环节 }, function(err) { alert('!Fail to decode the file'); //解码出错 }); }; fr.onerror = function(err) { alert('!Fail to read the file'); //文件读入出错 }; fr.readAsArrayBuffer(rfile); //同样的,ArrayBuffer方式读取 } };
3、创建效果节点,选择输出并将源、效果器和输出连接起来。前面也说过了,效果有非常多种,本文是建立分析节点。这里的连接是音源>>分析节点>>输出,为什么不直接将音源和输出连接起来呢?其实也可以直连,但因为分析节点需要做一定的处理,如果直接将音源和输出连接的话会有一定的延迟。另外,这里定义了一个status参数,用来指示状态值。最后的启动有两种写法,有兴趣的同学再去MDN上查查吧。
var status = 0, //状态,播放中:1,停止:0 arraySize = 128, //可以得到128组频率值 analyser = audioCtx.createAnalyser(); //创建分析节点 source.connect(analyser); //将音源和分析节点连接在一起 analyser.connect(audioCtx.destination); //将分析节点和输出连接在一起 source.start(0); //启动音源 status = 1; //更改音频状态
4、可视化绘图为了得到可视化效果,还需要对分析节点做一个傅里叶变换将信号从时域转到频域中,此处原理省略一万字。。。有兴趣的同学可以去看看信号处理相关的书籍。但是,这么难得的装逼机会,我舍不得呀!看不惯的同学可以跳过,也可以微信转账给我(什么鬼。。。)。
项目中getByteFrequencyData(array)这个函数来获取所需频率的能量值,其中array数组的长度为频率的个数。有看过资料的同学会发现这里很多时候用的是analyser.frequencyBinCount和analyser.fftsize两个值,其中analyser.fftsize是快速傅立叶变换(FFT)用于频域分析的尺寸,默认为2048。analyser.frequencyBinCount是fftsize的一半,这里我不需要那么多组数据,所以自定义了一个长度为128的8位无符号整形数组(谭浩强C语言后遗症,勿怪)。另外需要注意的是频率值的范围,是0到255,如果需要精度更高的值,可以使用AnalyserNode.getFloatFrequencyData()得到32位浮点数。经过上面的得到了这些值之后,我们就可以用它来跟某些视觉元素关联起来,比如说常见的柱状频谱的高度、圆的半径、线条的密度等等。我的项目里面采用的是能量球的方式。