<bdo id="4g88a"><xmp id="4g88a">
  • <legend id="4g88a"><code id="4g88a"></code></legend>

    Web Audio API 第1章 基礎篇

    webaudioapi

    Web Audio API 第1章 基礎篇

    我查了一下 Web Audio API 蝙蝠書居然在 2013 年就出版了

    我又看了一下我的“豆瓣讀書”頻道內,這本書加入到“在讀”標簽是在 2021 年了

    一直沒有堅持看這本書的原因有兩點,

    一是本書是英文版的,不像中文看的那么流暢

    二是在前端開發業務中一直沒有遇到復雜到需要用到 Web Audio API 的場景

    這不在 2023 年末業務上就遇上了需要處理音頻的業務么,督促自己看下去,順便翻譯了

    因為此書已是 10 年前寫的了,代碼有些可能比較古早,我將會用 JavaScript 重新實現相關 demo

    demo 會放在 https://github.com/willian12345/WebAudioAPI/tree/master/examples

    我并非音樂相關專業人士,所以對一些專業用語可能翻的沒那么專業,但這不重要,重要的就是先過一遍

    對 Web Audio API 能做啥有個印象,用到的時候再仔細深入

    總之沒用的知識又可以增加了??!
    譯者 (王二狗 Sheldon 池中物) 注

    正文開始

    此章將描述從何處入手 Web Audio API, 哪些瀏覽器支持,如何檢測哪些 API 可用,什么是音頻可視化,音頻節點是什么,如何將音頻節點組合連接在一起,介紹一些基礎的音頻節點類型,最后加載音頻并播放

    Audio 音頻在網頁中的歷史小知識

    最早在網頁中播放音頻使用的是 標簽,當有人訪問網頁時,網頁創作者使用此標簽就可自動播放背景音頻。這個特性只能 IE 瀏覽器上可用,它從未被標準化或被其它瀏覽器所實現過。網景瀏覽器實現了一個類似的 標簽, 提供了相似的播放功能。

    Flash 最早在網頁中實現了跨瀏覽器播放音頻的功能,但它有個比較大的缺點就是需要以插件方式運行。最近瀏覽器開發商都投向了 HTML5

    盡管在網頁上播放音頻不再需要插件了,但

    • 沒有精確的可控定時器
    • 一次可播放的音頻數量太少
    • 沒有可靠的預緩沖能力
    • 無法應用實時音頻特效
    • 沒有可用的方法對音頻進行分析

    他們多次嘗試推出強大的 audio API 來解決我上面提到的這些音頻限制。推出的這些 API 中值得注意的就是火狐瀏覽器設計的 Audio Data API 原型實現。Mozilla 試圖用

    相比于 Audio Data API, Web Audio API 使用了全新的模式,完全獨立于

    游戲與交互

    音頻是交互體驗的重要組成部分。如果你不信,試著觀看一部關掉聲音的電影。

    在游戲中更是如此!我最愛的電子游戲令我記憶最深的就是其中的音樂與音效。就算過了將近20年,塞爾達和暗黑破壞神的音效在我的腦海中仍然揮之不去。
    無論是暴雪的《魔獸爭霸》和《星際爭霸》系列中的圈點士兵音效還是任天堂經典游戲中的各種音效,這些精心設計的游戲音效立馬就可以被識別出來。

    音效在游戲外的應用也同樣重要。它們在命令行工具內交互之始就被應用于 UI 的交互上,當輸出出錯時就發出“嗶”的一聲。同樣被應用現代交互 UI 上,一般用于提醒功能,鈴聲,也應用于音視頻通訊比如 Skype。像 Google Now 和 Siri 這樣的助手軟件同樣提供了豐富的音效反饋。當我們深入發掘這個世界,通用計算設備,語音和手勢交互等可脫離屏幕的交互方式更加的依賴于音頻的反饋。最后,對于視障視弱的計算機用戶來說,音頻提示,語音合成與識別提供了最主要的用戶體驗原則

    可交互的音頻也代表著一些有趣的挑戰。為了創建合適的游戲音頻,設計師需要調整好游戲玩家所有不可預知的狀態。在實踐中,游戲中某部分的時長可能是未知的,音效與周邊環境交互產生更復雜的混音,需要環境特效音且取決于相關的音頻位置。最終可能同一時刻播放著一堆音頻,全都得組合在一起的音效即保證質量又不影響渲染性能

    Audio Context

    Web Audio API 是建立在 audio context 音頻上下文的概念之上的。音頻上下文是描述音頻所有節點的,這些節點定義了音頻流是如何從起點(一般是音頻文件)到目的地(一般就是你的揚聲器)。當音頻通過每個節點時,音頻的屬性可被修改和查看。最簡單的音頻上下文就是起始節點到結束節點的直連如圖 1-1

    圖 1-1

    一個音頻上下文可能會非常復雜,在音頻的起點與結束節點之間包含眾多的音頻節點(圖1-2)進行任意眾多的高級合成或分析。

    圖 1-1 和 1-2 方塊表示音頻節點。箭頭代表節點之間的連接。這些節點經常擁有眾多的輸入和輸出連接。默認情況下,如果一個音頻節點擁有多個輸入源,Web Audio API 會簡單的混成一個音頻信號。

    音頻節點圖的概念并不新鮮,它來源于一些流行的音頻處理框架,如 Apple 的 CoreAudio, 它提供了類似的音頻處理 圖像 API。它本身的概念很久遠了,可追溯到1960年代的早期處理音頻,比如 Moog 模塊化混成系統(Moog modular synthesizer systems)。

    圖 1-2

    初始化音頻上下文

    Web Audio API 現已被 Chrome 和 Safari 瀏覽器實現(包含 IOS 6 手機版 Safari )并且通過 JavaScript 開放給了網頁開發者。在這些瀏覽器上,音頻上下文創建時需要加上 webkit 前綴,你不能直接使用 new AudioContext 而應該使用 new webkitAudioContext 創建。然而在未來在 API 足夠穩定且多數瀏覽器供應商都實現了后前綴可去掉。Mozilla 已宣布在火狐瀏覽器上實現 Web Audio API,Opera 也開始參與進工作組。記得這一點即可,下面是通用的兼容寫法:

    var contextClass = (window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.oAudioContext || window.msAudioContext);
    if (contextClass) {
      // Web Audio API is available. 
      var context = new contextClass();
    } else {
      // Web Audio API is not available. Ask the user to use a supported browser.
    }
    

    一個音頻上下文即可支持多個音頻的輸入與復雜的音頻圖譜,一般來講,一個應用使用一個音頻上下文即可。音頻上下文的實例包含了眾多的方法用于創建音頻節點以及操作全局音頻屬性。幸運的是這些方法不需要加前綴,且相對穩定。 API 仍在變更,所以還是要小心會有大的變化。

    音頻節點的類型

    音頻上下文主要的一個功能就是創建新的音頻節點。廣義上來講,一般包含以下幾個節點類型:

    • 源節點(Source nodes)
      音源,如音頻緩沖,直播音頻輸入,

    • 修飾節點(Modification nodes)
      Filters, convolvers, panners, JS 處理器 等等

    • 分析節點(Analysis nodes)
      分析器, JS 處理器

    • 結束節點(Destination nodes)
      音頻輸出和結束處理緩存

    音頻源不限于音頻文件,可用直播音頻流或麥克風,

    連接音頻圖

    使用 connect() 方法可以將任意音頻節點輸出連接至任意其它的音頻節點。在以下例子,我們連接了音源節點的輸出到 gain 節點,并將其輸出連接到了結束節點:

    // Create the source.
    var source = context.createBufferSource(); 
    // Create the gain node.
    var gain = context.createGain();
    // Connect source to filter, filter to destination.
    source.connect(gain);
    gain.connect(context.destination);
    

    注意,context.destination 是一個特殊的節點,一般為系統的默認音頻輸出。上述代碼形成的音頻圖如下 1-3:

    圖 1-3

    一旦像上面這樣我們連接了音頻圖就可以動態改變它。我們可以調用 node.disconnect(outputNumber) 來斷開節點連接。例如,重新直連源音頻節點至結束音頻節點,避開中間 gain 節點 代碼如下:

    source.disconnect(0);
    gain.disconnect(0);
    source.connect(context.destination);
    

    模塊化路由的力量

    在很多游戲中,通常要將多個音源最終混成一個聲音。這些音源包含了背景音樂,游戲音效,UI反饋音,在多人游戲中還有其它玩家的聊天音頻。Web Audio API 的一個非常重要的特性就是它允許你單獨且完整的控制某個音或者組合在一起控制。音頻圖看起來應該像下面這樣圖 1-4:

    我們分別使用 gain 音頻節點將分開的聲道音源聯合在一起,并使用一個主 gain 節點來控制它們。 通過這樣的設置,非常方便按需精準控制單獨的聲道級別。例如,非常多的用戶在玩游戲過程中更喜歡把背景音關掉。

    重要理論:什么是聲音?

    就物理上而言,聲音是一種縱波(有時也被稱為壓力波)它們通過空氣或其它媒介傳播。 音源產生是由于空氣內分子之間的振動與碰撞。它們的聚散導致了不同區域的高低壓。如果你有能力凍結時間那么就可以觀察到聲波圖像,可能類似于圖 1-5

    圖 1-5

    圖 1-6

    數學上來講,聲音可被表示為函數,通過時間軸上的壓力范圍值。 圖 1-6 展示了函數圖像。 可以看到它模擬的是圖 1-5 ,值高的地方表示粒子稠密的區域(高壓),值低則表示粒子稀疏的區域(低壓)

    首次捕獲并重建聲音的能力得追溯到 20 世紀初了。麥克風捕獲壓力波并轉化成電子信號,(舉例)用 +5 伏電壓代表最高壓,-5 伏電壓代表最低壓。與之相反,音頻播放器獲取這些電壓并將其轉換回壓力波,這樣我們才能聽到。

    無論我們是在分析聲音還是合成聲音, 對于音頻編程者來說感興趣的比特信息都在黑盒內操作音頻信號圖 1-7 。早期操作音頻這個空間被模擬濾波器和其他硬件占據,按照今天的標準,這些硬件會被認為是過時的?,F在有更多數字處理設備代替老的模擬設備。但在使用軟件處理音頻前,我們需要先將聲音轉換成電腦能處理的信息

    圖 1-7 聲音的記錄與回放

    重要理論:什么是數字聲音?

    我們可以這樣做,對模擬信號按時間進行一定頻率的采樣,對每個信號進行編碼,編成一個數字。 對模擬信號的采樣被稱為采樣率。一般音頻軟件處理通常采樣率為44.1kHz。這意味著每一秒對聲音進行記錄 44100 個數值。這些數值限定在某個范圍內。每個值通常分配一定數量的位,稱為位深度(bit depth)。對于大多數數字音頻錄制,包括CD,位深度 16 對于大多數人來說足夠了。

    對于音樂發燒友來說,24位深度也夠了,已經有足夠的精度,使用再高的位深度人耳已很難區別開來了。

    模擬信號轉數字信號被稱為數字化(或采樣),可抽象為 圖 1-8

    圖 1-8

    在圖 1-8 ,數字化信號的版本的長條與模擬信號版本光滑的曲線看起來區別非常大。隨著采樣率增高與采樣深度的增加區別會越來越?。ㄋ{色部分)。然而這些值的增加也意謂著更多存儲內空間的付出。為了節約空間,電話系統通常使用的采樣率低至 8 kHz, 因為使人類聲音清晰可聽的頻率范圍遠遠小于我們可聽到的全部頻率范圍.

    對于聲音的數字化,計算機通常會像對待長數字的數組一樣處理。這樣的編碼被稱為脈沖編碼調制 PCM(pulse-code modulation)。因為計算機非常善于處理數組,PCM 對于大多數數字音頻應用來說是一個非常強大的基元。在 Web Audio API 的世界,長數字的數組的聲音被表示為音頻緩沖(AudioBuffer). 音頻緩沖可以存儲多條音頻通道(通常在立體聲中,包含左聲道和右聲道)被表示為標準化從 -1 到 1 后的浮點數數組。同樣的信號當然也可以被表示為整形數組,在 16 位長度下,范圍從 -215 至 215 - 1。

    重要理論:音頻編碼格式

    原始的音頻 PCM 格式非常巨大, 它會造成額外的存儲浪費,在下載時也會造成額外的帶寬浪費。正因如此,音頻通常會存儲為壓縮后的格式。有兩種類型的壓縮方式:有損壓縮和無損壓縮。無損壓縮(如, FLAC)保證在壓縮與解壓后比特位信息完全相同。有損壓縮(如,MP3) 利用人類聽覺特性會丟棄掉部人類聽不到的分比特位信息用于節約存儲空間。有損壓縮對于大多數人來說足夠用了,音樂發燒友除外。

    通常度量音頻壓縮量被稱作比特率,它代表著重放每秒音頻所需要的比特位數量。比特率越高單位時間內可利用的數據就越多所需的壓縮就越少(更精確)。通常有損壓縮格式,比如 MP3 定義為它們的比特率(一般為 128 到 192 Kb/s)。有損格式的編解碼有可能使用任意的比特率。舉個例子,電話人聲音頻通常使用 8Kb/s MP3 格式。一些格式支持可變比特率如 OGG 格式。比特率會隨著時間變化而變。注意此處的比特率別和采樣率或比特深度混淆了

    瀏覽器對不同音頻格式的支持差別很大。一般來說,如果是在瀏覽器上, Web Audio API 的實現與

    Firefox Chrommium 現在是支持 mp3 格式的。

    聲音的加載與播放

    Web Audio API 將緩沖與音源(source)節點區別的很清晰。這樣的架構有利于解構音頻資源與播放狀態。以唱片機為例,緩沖區就像唱片,而源就像播放指針,而在 Web Audio API 的世界中你可以同時在多個播放指針處播放同一個唱片。由于許多應用程序涉及同一緩沖區的多個版本同時播放,因此這種模式是必不可少的。舉個例子,
    如果您希望快速連續地發出多個彈跳球的聲音,則只需要加載一次彈跳緩沖并安排多個音源(source)。

    在 Web Audio API 加載一個音頻樣本,我們可以使用一個 XMLHttpRequest 加載并對加載的結果用context.decodeAudioData進行音頻解碼處理。這些都是異步的不會阻塞主 UI 進程:

    var request = new XMLHttpRequest(); 
    request.open('GET', url, true); 
    request.responseType = 'arraybuffer';
    // Decode asynchronously
    request.onload = function() {
      context.decodeAudioData(request.response, function(theBuffer) { 
        buffer = theBuffer;
      }, onError);
    }
    request.send();
    

    此代碼較老,用 fetch 請求數據更簡單,我的 demo 里就是用 fetch 代替了 XMLHttpRequest

    音頻緩沖只是播放源的一種。其它播放源包括直接來自麥克風或其它音源輸入設備,或者

    一旦你加載了緩沖,你可以為它創建一個(source node)源節點(AudioBufferSource Node),把它連接到音頻圖并在源節點(source node)調用 start(0)。結束播放調用 stop(0).注意,這兩個函數在當前音頻上下文的坐標系統調用都需要消耗時間(見第2章)

    function playSound(buffer) {
      var source = context.createBufferSource(); 
      source.buffer = buffer; 
      source.connect(context.destination); 
      source.start(0);
    }
    

    游戲中通常都有循環播放的背景音樂。然而,需要注意不要過度重復你的選擇:如果玩家被困在了某地或某個關卡,同樣的樣本在背景中不斷播放,為了防止玩家沮喪,背景音聲道的逐漸淡出可能是值得考慮的。另一種策略是根據游戲情境將不同強度的元素混合在一起(文章后續會提到)。

    將它們整合在一起

    如你所見以上的代碼,Web Audio API 需要一些初始化的程序設置。在真正的游戲中,可以考慮圍繞 Web Audio API 執行 JavaScript 抽象。例如后續的 BufferClass 類。它將所有東西都整合進一個簡單的加載器上,加載器提供了設置路徑,返回音頻緩沖的功能。以下是如何使用 BufferLoader 類的代碼:

    window.onload = init; 
    var context;
    var bufferLoader;
    function init() {
      context = new webkitAudioContext();
      bufferLoader = new BufferLoader( context,
                [
                  '../sounds/hyper-reality/br-jam-loop.wav',
                  '../sounds/hyper-reality/laughter.wav',
                ],
                finishedLoading
            );
      bufferLoader.load();
    }
    
    function finishedLoading(bufferList) {
        // 創建兩具音源并把它們整合到一起播放
        var source1 = context.createBufferSource();
        var source2 = context.createBufferSource(); 
        source1.buffer = bufferList[0];
        source2.buffer = bufferList[1];
        source1.connect(context.destination);
        source2.connect(context.destination);
        source1.start(0);
        source2.start(0);
    }
    

    BufferLoader 類的實現可參 https://github.com/willian12345/WebAudioAPI/blob/master/examples/Bufferloader.js

    音頻播放例子可參考 https://github.com/willian12345/WebAudioAPI/blob/master/examples/ch01/index.html


    注:轉載請注明出處博客園:王二狗Sheldon池中物 (willian12345@126.com)

    posted @ 2024-03-14 17:31  池中物王二狗  閱讀(427)  評論(0編輯  收藏  舉報
    轉載入注明博客園 王二狗Sheldon Email: willian12345@126.com https://github.com/willian12345
    免费视频精品一区二区_日韩一区二区三区精品_aaa在线观看免费完整版_世界一级真人片
    <bdo id="4g88a"><xmp id="4g88a">
  • <legend id="4g88a"><code id="4g88a"></code></legend>