前端音频可视化Web Audio如何实现
导读:本文共3175字符,通常情况下阅读需要11分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: 实现思路首先画肯定是用canvas去画,关于音频的相关数据(如频率、波形)如何去获取,需要去获取相关audio的DOM 或通过请求处理去拿到相关的音频数据,然后通过Web Audio API 提供相关的方法来实现。(当然还要考虑要音频请求跨域的问题,留在最后。)一个简单而典型的 web audio 流程如下(取自MDN):创建音频上下文在音频上下文里创建源 &a... ...
目录
(为您整理了一些要点),点击可以直达。实现思路
首先画肯定是用canvas去画,关于音频的相关数据(如频率、波形)如何去获取,需要去获取相关audio的DOM 或通过请求处理去拿到相关的音频数据,然后通过Web Audio API 提供相关的方法来实现。(当然还要考虑要音频请求跨域的问题,留在最后。)
一个简单而典型的 web audio 流程如下(取自MDN):
创建音频上下文
在音频上下文里创建源 — 例如
<audio>
, 振荡器,流创建效果节点,例如混响、双二阶滤波器、平移、压缩
为音频选择一个目的地,例如你的系统扬声器
连接源到效果器,对目的地进行效果输出
实现
一、频率图
实现第一种类型,首先我们需要通过fetch或xhr来获取一个线上音频的数据,这里以fetch为例;
//创建一个音频上下文、考虑兼容性问题letaudioCtx=new(window.AudioContext||window.webkitAudioContext)();//添加一个音频源节点letsource=audioCtx.createBufferSource();//res.arrayBuffer是将数据转换为arrayBuffer格式fetch(url).then((res)=>res.arrayBuffer()).then((res)=>{//decodeAudioData是将arrayBuffer格式数据转换为audioBufferaudioCtx.decodeAudioData(res).then((buffer)=>{//decodeAudioData解码完成后,返回一个AudioBuffer对象//绘制音频波形图draw(buffer);//连接音频源source.buffer=buffer;source.connect(audioCtx.destination);//音频数据处理完毕});});
需要明白的是,source.connect(audioCtx.destination)是将音频源节点链接到输出设备,否则会没声音哦。那么现在有了数据、我们只需要通过canvas将数据画出来即可。
functiondraw(buffer){//buffer.numberOfChannels返回音频的通道数量,1即为单声道,2代表双声道。这里我们只取一条通道的数据letdata=[];letoriginData=buffer.getChannelData(0);//存储所有的正数据letpositives=[];//存储所有的负数据letnegatives=[];//先每隔50条数据取1条for(leti=0;i<originData.length;i+=50){data.push(originData[i]);}//再从data中每10条取一个最大值一个最小值for(letj=0,len=data.length/10;j<len;j++){lettemp=data.slice(j*10,(j+1)*10);positives.push(Math.max(...temp));negatives.push(Math.min(...temp));}if(canvas.getContext){letctx=canvas.getContext("2d");canvas.width=positives.length;letx=0;lety=75;letoffset=0;vargrd=ctx.createLinearGradient(0,0,canvas.width,0);//为渐变添加颜色,参数1表示渐变开始和结束之间的位置(用0至1的占比表示),参数2位颜色grd.addColorStop(0,"yellow");grd.addColorStop(0.5,"red");grd.addColorStop(1,"blue");ctx.fillStyle=grd;ctx.beginPath();ctx.moveTo(x,y);//横坐标上方绘制正数据,下方绘制负数据//先从左往右绘制正数据//x+0.5是为了解决canvas1像素线条模糊的问题for(letk=0;k<positives.length;k++){ctx.lineTo(x+k+0.5,y-50*positives[k]);}//再从右往左绘制负数据for(letl=negatives.length-1;l>=0;l--){ctx.lineTo(x+l+0.5,y+50*Math.abs(negatives[l]));}//填充图形ctx.fill();}}
[参考文章](Web Audio - 绘制音频图谱
二、实时频率图
实现第二种类型,获取实时频率,用到的API与第一种有区别,但流程一直,都是通过一个音频源节点通过连接达到效果。只不过在连接的中间加入了一个分析器analyser,在将分析器连接到输出设备。
constaudio=document.querySelector('audio')//解决音频跨域问题audio.crossOrigin='anonymous'constcanvas=document.querySelector('canvas')constctx=canvas.getContext("2d")functioninitCanvas(){//初始化canvascanvas.width=window.innerWidth*devicePixelRatiocanvas.height=(window.innerHeight/2)*devicePixelRatio}initCanvas()//将数据提出来letdataArray,analyser;//播放事件audio.onplay=function(){//创建一个音频上下文实例constaudioCtx=new(window.AudioContext||window.webkitAudioContext)();//添加一个音频源节点constsource=audioCtx.createMediaElementSource(audio);//分析器节点analyser=audioCtx.createAnalyser();//fft分析器越大分析越细analyser.fftSize=512//创建一个无符号字节的数组dataArray=newUint8Array(analyser.frequencyBinCount);//音频源节点链接分析器source.connect(analyser)//分析器链接输出设备analyser.connect(audioCtx.destination,)}
那么接下来至于怎么把数据画出来,就凭大家的想法了。
requestAnimationFrame(draw)//const{width,height}=canvas;ctx.clearRect(0,0,width,height)//分析器节点分析出的数据到数组中ctx.fillStyle='#78C5F7'ctx.lineWidth=2;ctx.beginPath();//getByteFrequencyData,分析当前音频源的数据装到dataArray数组中去//获取实时数据analyser.getByteFrequencyData(dataArray)//console.log(dataArray);constlen=dataArray.length;constbarWidth=width/len;letx=0;for(leti=0;i<len;i++){constdata=dataArray[i];constbarHeight=data/255*height;//ctx.fillRect(x,y,barWidth,height)letv=dataArray[i]/128.0;lety=v*height/2;if(i===0){ctx.moveTo(x,y);}else{ctx.lineTo(x,y);}x+=barWidth;}//ctx.lineTo(canvas.width,canvas.height/2);ctx.stroke();}draw();
关于请求音频跨域问题解决方案
给获取的audio DOM添加一条属性即可
audio.crossOrigin='anonymous'
或者直接在 aduio标签中 加入 crossorigin="anonymous"
</div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
前端音频可视化Web Audio如何实现的详细内容,希望对您有所帮助,信息来源于网络。