音頻可視化實現以後真的很酷,雖然此次只是跟着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 實現音頻可視化