离职的第一天,刷到了一个音频可视化的帖子,简单的学习了一下来跟大家分享一下我的学习成果。第一次写帖子大家望大家多指点

理解

首先音频处理需要跟多环节例如修音、混响等,每一个环节就是一个节点,每一个环节都有一个音频的源节点,例如下图的首先获取一个音频源节点,第一个环节去处理他的音色,在下一步在新引入一个音频源节点例如鼓点,节拍之类的在第二个环节添加进去最后通过输出设备播放出来就此完成了整个流程,节点的数量是可以任意数量的。 音频上下文就是所有的节点都连接起来后形成的一个环境就可以理解为音频上下文,相当于一个音频上下文为一个厂房,每个环节就是这个厂房里面运行生产设备的的每个流程节点

在本文音频可视化中不需要太多的节点,我们只需要将音频源获取进来通过分析器在交给输出设备进行播放,播放时分析器一直分析他的波形图在讲分析完其波形数据交给canvas绘制,进行可视化显示

分析器节点的功能通过(快速傅里叶变换[FFT])将现实中的时域图变成频率图

实现

接下来进行实现,首先创建上下文,拿到音频源,音频源与分析器连接,分析器在与扬声器连接进行输出,这样就形成了一个音频源到扬声器的输出通路

 1 
 2    const audCtx=new AudioContext()
 3    
 4    const source=audCtx.createMediaElementSource(audioEle)
 5    
 6    analyser = audCtx.createAnalyser()
 7      
 8    source.connect(analyser)
 9     
10    analyser.connect(audCtx.destination)

下一步就是通过对分析器进行操作,分析器节点的功能通过(快速傅里叶变换)将现实中的时域图变成频率图

 1
 2    analyser.fftSize=512;
 3    
 4    dataArray=new Uint8Array(analyser.frequencyBinCount)

isInit参数是在播放之前为false,防止初次加载报错,这里循环操作使用requestAnimationFrame 采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销。每次循环时第一步将画布清空,getByteFrequencyData方法是将播放时分析器分析出的数据存入dataArray中

 1function draw(){
 2    
 3    requestAnimationFrame(draw)
 4    
 5    
 6    const{width,height}=cvs
 7    ctx.clearRect(0,0,width,height);
 8    
 9    if(!isInit){
10        return
11    }
12    
13    analyser.getByteFrequencyData(dataArray)
14    console.log(dataArray);
15}
16

成功打印结果

最后一步就是根据数据绘制图表,我这边绘制的为柱状图,如果有需要其他类型图表可以自行选择

 1
 2const len=dataArray.length/2.5
 3    const barWidth=width/len
 4    ctx.fillStyle='#78c5F7'
 5    for(let i =0;i<len;i++){
 6        const data=dataArray[i]
 7        const barHeight=data/255*height
 8        const x=i*barWidth
 9        const y =height-barHeight
10        ctx.fillRect(x,y,barWidth-2,barHeight)
11    }

最终效果

个人笔记记录 2021 ~ 2025