利用 web audio api 實現音頻可視化

音頻可視化實現以後真的很酷,雖然此次只是跟着MDN上的教程學習了一下,照着Demo敲了一遍而已。但收穫頗多,記錄於此。javascript

web audio api

先來感覺一下 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

這裏仍是得簡單提一下AnalyserNode,咱們接下來須要用到它的幾個屬性和方法api

這裏直接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的地址吧。

不早了 睡了。世界晚安

參考

- 基於Web Audio API實現音頻可視化效果

- HTML5 Audio: createMediaElementSource breaks audio output

- AnalyserNode

- web audio api

本文做者: Roy Luo

本文連接: 利用 web audio api 實現音頻可視化

相關文章
相關標籤/搜索