音频可视化实现以后真的很酷,虽然此次只是跟着MDN上的教程学习了一下,照着Demo敲了一遍而已。但收获颇多,记录于此。javascript
先来感觉一下 web audio api 的基础概念,下面截取一段MDN上的介绍。具体的请移步文档html
Web audio 概念与使用
Web Audio API使用户能够在音频上下文(AudioContext)中进行音频操做,具备模块化路由的特色。在音频节点上操做进行基础的音频, 它们链接在一块儿构成音频路由图。即便在单个上下文中也支持多源,尽管这些音频源具备多种不一样类型通道布局。这种模块化设计提供了灵活建立动态效果的复合音频的方法。html5
在跟着文档和Demo走了一遍以后,我本身的理解就是,咱们能够经过const audioCtx = new (window.AudioContext || window.webkitAudioContext)()
这样的形式来获取/建立一个音频上下文,这个audioCtx
中有许多可供使用的属性方法。这里只会稍微描述一下实现音频可视化要用的属性。具体的能够参考文档。java
其实这个AudioContext能作的事不光是音频可视化。首先它支持获取音频的输入,也就是接下来会提到的定义音频源。而后它可以定义音效,或许你要是知道怎么把一段声音作成电音的算法,那你能够试试,而后教教我。哈哈哈,固然一些基础的控制音频源的输出音量这些都是有的。git
接下来就继续谈音频但是化啦github
首页咱们须要选择一个用来展现音频的工具,这里其实用的就是Canvas,固然若是你会用Svg也能够尝试着作一下。这里我不会svg,嗯。打算学(but, who knows when)。web
那么这里就只剩下用来显示的数据了。算法
前面提到过,AudioContext中有许多属性和方法,其中就有createAnalyser()
方法,能够供咱们获取AnalyserNode这个对象。这个对象会提供给咱们用来显示(能够被咱们处理成用来显示的)的所须要的数据。canvas
这里仍是得简单提一下AnalyserNode,咱们接下来须要用到它的几个属性和方法api
一个无符号长整形(unsigned long)的值, 用于肯定频域的 FFT ( 快速傅里叶变换) 的大小。
AnalyserNode.getByteFrequencyData()
将当前频域数据拷贝进
Uint8Array
数组(无符号字节数组)。
AnalyserNode.getByteTimeDomainData()
将当前波形,或者时域数据拷贝进
Uint8Array
数组(无符号字节数组)。
这里直接copy了MDN的内容。而后我再根据本身的理解来描述一下。
AnalyserNode.fftSize
首先咱们能够经过设置AnalyserNode.fftSize
来控制将要用来显示的数据(数组,这里后面会处理成数组)的个数(长度),简单点说就是,若是咱们想用柱状图来显示数据,fftSize设置的越大,那咱们显示的柱子的数量就会越多。反之同理。不过这个值是有范围的,而且必须是2的n次幂。范围:[32, 32768],超出或小于会报错。
AnalyserNode.getByteFrequencyData()
这个在文档中描述是获取当前频域的数据,我理解成就是若是要显示成柱状图的形式,那么就用这个。由于我试过了用getByteTimeDomainData
结果并非很好。由于getByteTimeDomainData
是用用来展现波形的,这里我理解的就是文档的字面意思。不展开描述
好的,这里要用到的关键的基础知识介绍完毕。接下来就是要作事了,直接上代码了。
接下来是一些供描述的代码,具体的代码在个人Github上,其实直接看MDN提供的Demo的源代码也行。
// 获取页面中的audio对象 const myAudio = document.querySelector('audio') // 获取web audio 上下文对象 const audioCtx = new (window.AudioContext || window.webkitAudioContext)() // 获取声音源 const source = audioCtx.createMediaElementSource(myAudio) // 获取分析对象 const analyser = audioCtx.createAnalyser() // 设置fftSize analyser.fftSize = 1024 const bufferLength = analyser.fftSize // 由于这里analyser返回的数据js不能直接使用,因此要经过Uint8Array来转换一下,让js认识一下 const dataArray = new Uint8Array(bufferLength) // 链接解析器 source.connect(analyser) // 输出音频 source.connect(audioCtx.destination)
以上就已经能够获取当前audio对象所播放音频的可供咱们js使用的数据了,话有点绕,其实这里要用到的就是这个daraArray
,咱们须要在接下来编写canvas的代码中用到这个数组中的数据。
这里我踩了个坑,我一开始没写source.connect(audioCtx.destination)
便运行了上面剩余的代码,发现页面没有声音,可是我若是不写这些代码。直接用audio标签autoplay,声音是很洪亮的。可是用了上面的代码就是没声音。
而后我注意到Demo中还有一句source.connect(audioCtx.destination)
我没写。加上以后,确实出了声音。因而我看了一下文档得知,这个是用来定义音频目的地的。也就是说,在咱们把音频源传入AudioContext以后,这个音频源就被AudioContext托管了。而后AudioContext并不会自动播放声音,这里须要手动设置一下音频的归属地(一般是输出到你的扬声器)
那么接下来就是把数据显示出来了,这里我直接粘贴处理canvas的代码了(困了,如今半夜12:13)
const draw = () => { // 获取当前声音的波形;将当前波形,或者时域数据拷贝进 Uint8Array数组(无符号字节数组) analyser.getByteTimeDomainData(dataArray) ctx.clearRect(0, 0, W, H) ctx.fillStyle = 'rgb(200,200,200)' ctx.fillRect(0, 0, W, H) ctx.strokeStyle = 'rgb(0,0,0)' ctx.beginPath() const sliceWidth = W * 1.0 / bufferLength let x = 0 for (let i = 0; i < bufferLength; i++) { let v = dataArray[i] / 128.0 let y = v * H / 2 if (i === 0) { ctx.moveTo(x, y) } else { ctx.lineTo(x, y) } x += sliceWidth } ctx.lineTo(W, H / 2) ctx.stroke() requestAnimationFrame(draw) } const draw2 = () => { // 获取当前频域数据;将当前频域数据拷贝进Uint8Array数组(无符号字节数组) analyser.getByteTimeDomainData(dataArray) ctx.clearRect(0, 0, W, H) ctx.fillStyle = 'rgb(0,0,0)' ctx.fillRect(0, 0, W, H) const barWidth = (W / bufferLength) * 2.5 let barHeight let x = 0 for (let i = 0; i < bufferLength; i++) { barHeight = dataArray[i] / 2 ctx.fillStyle = `rgb(${barHeight + 100},50,50)` ctx.fillRect(x, H - barHeight, barWidth, barHeight) x += barWidth + 1 } requestAnimationFrame(draw2) }
这里有两个方法,分别:draw
是用来显示波形的,draw2
是能够显示成柱状图的样子,我我的更喜欢draw2
画出来的样子。
由于此次是分享web audio api,并且上面canvas的代码比较简单,看看就行了。就不展开讲了。
BB了很久,就总结一下了,但愿有人能看到这里。
此次知道写web audio api 也其实就是简单的介绍了一下这个强大的api能支持网页对音频做出来的各类骚操做。不光光是可视化,变声,换成立体环绕啥的都是不在话下的。有兴趣的同窗能够了解一下。嗯,了解一下,而后教教我。
其实此次写博客以前还完善了一下,给加上了经过设备的麦克风获取音频并可视化的方法。挺简单的,看看源码就知道了。
或许过两天会给这篇加上点图片,放个demo的地址吧。
不早了 睡了。世界晚安
- HTML5 Audio: createMediaElementSource breaks audio output
本文做者: Roy Luo本文连接: 利用 web audio api 实现音频可视化