使用 Web Audio API

讓我們來看看如何開始使用 Web Audio API。我們將簡要介紹一些概念,然後研究一個簡單的 Boombox 示例,該示例允許我們載入一個音訊軌道,播放和暫停它,並更改其音量和立體聲聲像。

Web Audio API 不會取代 <audio> 媒體元素,而是對其進行補充,就像 <canvas><img> 元素並存一樣。您的用例將決定您使用何種工具來實現音訊。如果您想控制音訊軌道的播放,<audio> 媒體元素比 Web Audio API 提供了更好、更快的解決方案。如果您想執行更復雜的音訊處理以及播放,Web Audio API 提供了更強大的功能和控制。

Web Audio API 的一個強大功能是它沒有嚴格的“聲音呼叫限制”。例如,一次沒有 32 或 64 次聲音呼叫的上限。一些處理器可能能夠同時播放超過 1000 種聲音而不會出現卡頓。

示例程式碼

我們的 Boombox 看起來像這樣

A boombox with play, pan, and volume controls

請注意帶有播放按鈕的復古磁帶播放器,以及音量和聲像滑塊,讓您能夠更改音量和立體聲聲像。我們可以使其複雜得多,但在現階段,這對於簡單的學習來說是理想的。

在此處檢視最終的線上演示,或檢視 GitHub 上的原始碼

音訊圖

Web Audio API 中的一切都基於音訊圖的概念,而音訊圖由節點組成。

Web Audio API 在 **音訊上下文 (audio context)** 中處理音訊操作,並被設計為允許 **模組化路由 (modular routing)**。基本音訊操作透過 **音訊節點 (audio nodes)** 執行,這些節點相互連線形成一個 **音訊路由圖 (audio routing graph)**。您有輸入節點,它們是您正在操作的聲音的來源;修改節點,它們會根據需要更改這些聲音;以及輸出節點(目的地),它們允許您儲存或聽到這些聲音。

即使在單個上下文中,也支援具有不同通道佈局的多個音訊源。由於這種模組化設計,您可以建立具有動態效果的複雜音訊功能。

音訊上下文

為了能夠使用 Web Audio API 執行任何操作,我們需要建立一個音訊上下文例項。然後,這將使我們能夠訪問 API 的所有功能。

js
const audioContext = new AudioContext();

那麼,當我們這樣做時,發生了什麼?一個 BaseAudioContext 會自動為我們建立,並擴充套件為一個線上音訊上下文。我們需要這個,因為我們要播放即時聲音。

注意:如果您只想處理音訊資料,例如,緩衝和流式傳輸它但不播放它,您可能需要建立 OfflineAudioContext

載入聲音

現在,我們建立的音訊上下文需要一些聲音來播放。使用 API 有幾種方法可以做到這一點。讓我們從一個簡單的方法開始——正如我們有一個 Boombox,我們很可能想要播放一首完整的歌曲。此外,為了可訪問性,最好在 DOM 中公開該音軌。我們將使用 <audio> 元素在頁面上公開歌曲。

html
<audio src="myCoolTrack.mp3"></audio>

注意:如果載入的聲音檔案位於不同的域上,您將需要使用 crossorigin 屬性;有關更多資訊,請參閱 跨域資源共享 (CORS)

要使用 Web Audio API 提供的所有便利功能,我們需要從該元素獲取源並將其“管道”到我們建立的上下文中。幸運的是,有一個方法可以讓我們做到這一點——AudioContext.createMediaElementSource

js
// get the audio element
const audioElement = document.querySelector("audio");

// pass it into the audio context
const track = audioContext.createMediaElementSource(audioElement);

注意:上面的 <audio> 元素在 DOM 中由 HTMLMediaElement 型別物件表示,它帶有一系列自己的功能。所有這些都已保留;我們只是允許 Web Audio API 使用聲音。

控制聲音

在網頁上播放聲音時,允許使用者控制它很重要。根據用例,有多種選擇,但我們將提供播放/暫停聲音、更改音軌音量以及從左到右進行聲像的功能。

透過 JavaScript 程式碼以程式設計方式控制聲音受瀏覽器的自動播放支援策略的約束,因此在未獲得使用者許可(或允許列表)的情況下很可能會被阻止。自動播放策略通常要求在指令碼觸發音訊播放之前獲得明確許可或使用者與頁面的互動。

這些特殊要求的存在主要是因為意外的聲音可能令人討厭且具有侵擾性,並可能導致可訪問性問題。您可以在我們的文章 媒體和 Web Audio API 的自動播放指南 中瞭解更多關於此的資訊。

由於我們的指令碼是在響應使用者輸入事件(例如,單擊播放按鈕)時播放音訊,所以我們處於有利地位,不應遇到自動播放阻止問題。因此,讓我們開始看看我們的播放和暫停功能。我們有一個播放按鈕,在音軌播放時會變成暫停按鈕。

html
<button data-playing="false" role="switch" aria-checked="false">
  <span>Play/Pause</span>
</button>

在播放音軌之前,我們需要將音訊圖從音訊源/輸入節點連線到目的地。

我們已經透過將音訊元素傳遞到 API 來建立了一個輸入節點。在大多數情況下,您不需要建立輸出節點,只需將其他節點連線到 BaseAudioContext.destination 即可,它會為您處理這種情況。

js
track.connect(audioContext.destination);

視覺化這些節點的最佳方法是繪製音訊圖,這樣您就可以視覺化它。這就是我們當前的音訊圖的樣子。

an audio graph with an audio element source connected to the default destination

現在我們可以新增播放和暫停功能。

js
// Select our play button
const playButton = document.querySelector("button");

playButton.addEventListener("click", () => {
  // Check if context is in suspended state (autoplay policy)
  if (audioContext.state === "suspended") {
    audioContext.resume();
  }

  // Play or pause track depending on state
  if (playButton.dataset.playing === "false") {
    audioElement.play();
    playButton.dataset.playing = "true";
  } else if (playButton.dataset.playing === "true") {
    audioElement.pause();
    playButton.dataset.playing = "false";
  }
});

我們還需要考慮音軌播放完畢後該怎麼做。當 HTMLMediaElement 播放完畢時,它會觸發一個 ended 事件,因此我們可以偵聽該事件並相應地執行程式碼。

js
audioElement.addEventListener("ended", () => {
  playButton.dataset.playing = "false";
});

修改聲音

讓我們深入研究一些基本的修改節點,以更改我們擁有的聲音。這就是 Web Audio API 真正派上用場的地方。首先,讓我們更改音量。這可以透過 GainNode 來完成,它表示我們的聲波有多大。

您可以透過兩種方式使用 Web Audio API 建立節點。您可以使用上下文字身的工廠方法(例如,audioContext.createGain()),或者透過節點的建構函式(例如,new GainNode())。我們將在程式碼中使用工廠方法。

js
const gainNode = audioContext.createGain();

現在我們必須更新之前的音訊圖,以便將輸入連線到增益,然後將增益節點連線到目的地。

js
track.connect(gainNode).connect(audioContext.destination);

這將使我們的音訊圖看起來像這樣。

an audio graph with an audio element source, connected to a gain node that modifies the audio source, and then going to the default destination

增益的預設值為 1;這會使當前音量保持不變。增益可以設定為最小值約為 -3.4028235E38,最大值約為 3.4028235E38(JavaScript 中的浮點數範圍)。在這裡,我們將允許 Boombox 將增益提高到 2(原始音量的兩倍),並將音量降低到 0(這將有效地靜音我們的聲音)。

讓我們讓使用者能夠控制這一點——我們將使用一個 範圍輸入 (range input)

html
<input type="range" id="volume" min="0" max="2" value="1" step="0.01" />

注意:範圍輸入是更新音訊節點值的非常方便的輸入型別。您可以指定範圍的值,並直接將其與音訊節點的引數一起使用。

因此,讓我們獲取此輸入的 قيمة,並在使用者更改輸入節點的值時更新增益值。

js
const volumeControl = document.querySelector("#volume");

volumeControl.addEventListener("input", () => {
  gainNode.gain.value = volumeControl.value;
});

注意:節點物件的值(例如,GainNode.gain)不是簡單值;它們實際上是 AudioParam 型別的物件——它們稱為引數。這就是為什麼我們必須設定 GainNode.gainvalue 屬性,而不是直接在 gain 上設定值。這使它們更加靈活,例如允許將一組特定的值傳遞給引數,以便在設定的時間段內進行更改。

太好了,現在使用者可以更新音軌的音量了!如果您想新增靜音功能,增益節點是 perfect 的節點。

為我們的應用新增立體聲聲像

讓我們再新增一個修改節點來練習我們剛才學到的東西。

有一個 StereoPannerNode 節點,它可以在左右揚聲器之間更改聲音的平衡,前提是使用者具有立體聲功能。

注意: StereoPannerNode 適用於您只想實現左右立體聲聲像的簡單情況。還有一個 PannerNode,它允許對 3D 空間或聲音空間化進行大量控制,以建立更復雜的效果。這在遊戲和 3D 應用中使用,例如建立鳥在頭頂飛過,或聲音從使用者身後傳來。

為了視覺化,我們將使我們的音訊圖看起來像這樣。

An image showing the audio graph showing an input node, two modification nodes (a gain node and a stereo panner node) and a destination node.

這次我們使用建構函式方法來建立節點。當我們以這種方式進行時,我們必須傳入上下文和該特定節點可能採用的任何選項。

js
const pannerOptions = { pan: 0 };
const panner = new StereoPannerNode(audioContext, pannerOptions);

注意:當前並非所有瀏覽器都支援使用建構函式方法建立節點。舊的工廠方法得到了更廣泛的支援。

在這裡,我們的值從 -1(最左邊)到 1(最右邊)不等。同樣,讓我們使用範圍型別的輸入來改變這個引數。

html
<input type="range" id="panner" min="-1" max="1" value="0" step="0.01" />

我們使用該輸入的 قيمة 來調整我們的聲像值,方式與我們之前一樣。

js
const pannerControl = document.querySelector("#panner");

pannerControl.addEventListener("input", () => {
  panner.pan.value = pannerControl.value;
});

讓我們再次調整我們的音訊圖,將所有節點連線在一起。

js
track.connect(gainNode).connect(panner).connect(audioContext.destination);

剩下的就是嘗試一下這個應用程式:在此處檢視最終的線上演示

總結

太棒了!我們有了一個可以播放“磁帶”的 Boombox,我們可以調整音量和立體聲聲像,這使我們擁有了一個相當基礎的、可用的音訊圖。

這構成了您開始在網站或 Web 應用中新增音訊所需的基礎知識。Web Audio API 還有更多功能,但一旦您掌握了節點和組裝音訊圖的概念,我們就可以繼續研究更復雜的功能。

更多示例

還有其他示例可供學習 Web Audio API。

Voice-change-O-matic 是一個有趣的語音處理器和聲音視覺化 Web 應用,它允許您選擇不同的效果和視覺化。該應用程式相當基礎,但它演示了 Web Audio API 功能的同時使用。(即時執行 Voice-change-O-matic)。

A UI with a sound wave being shown, and options for choosing voice effects and visualizations.

另一個專門用於演示 Web Audio API 的應用程式是 Violent Theremin,一個簡單的 Web 應用程式,允許您透過移動滑鼠指標來改變音高和音量。它還提供迷幻的燈光秀(檢視 Violent Theremin 原始碼)。

A page full of rainbow colors, with two buttons labeled Clear screen and mute.

還可以檢視我們的 webaudio-examples 倉庫 以獲取更多示例。