努力翻譯一篇中文最友好的,Web Audio API的使用相關的文章

前言

本文翻譯自MDN上的《Web Audio APIの利用》,這是HTML5中的Web Audio API的一個入門教程。原文是英文,但有日本同志翻譯的日文版。我更熟悉日文,因此主要根據日文版翻譯成簡體中文,也會對照英文版的。node

Web Audio API的使用

Web Audio API提供給你一個簡單卻強大的機制,你能夠利用它去實現與操做web應用內的音頻內容。經過它,在網頁中你也能夠進行混音、音效、平移等各類複雜的音頻處理功能的開發。這篇文章主要想經過兩個簡單的例子來講明Web Audio API的基礎使用方法。git

Web Audio API並非替代<audio> 標籤的東西,換句話說Web Audio API實際上是對<audio> 標籤功能上的補充。兩者的關係能夠類比<img>標籤與<canvas> 標籤。具體改選用哪一個取決於你的目的是什麼。若是隻是爲了簡單地控制音頻的播放的話,<audio>標籤更適合吧。可是若是有更復雜的音頻處理需求的話,就必須使用Web Audio API。github

Web Audio API的一個強大之處是它沒有嚴格的[發出聲音的數目的限制]。例如,一秒內能夠同時發出32個聲音或64個聲音,但這並非上限。CPU的處理能力足夠的話,1000多種聲音也能夠不通過壓縮直接播放。若是這樣發展下去的話,幾年以後的中高端聲卡的負荷會大大下降的吧。web

PS:補充點背景知識,這裏提到的32,64指的是複音數。複音數指MIDI樂曲在一秒鐘內發出的最大聲音數目。關於複音數和MIDI樂曲能夠百度一下。聲卡硬件會限制複音數,部分軟件使用CPU實現聲音播放的也會限制複音數。但理論上只要CPU處理能力夠強複音數是不受限的。因此上段說起Web Audio Api是軟件,但它沒有複音數限制,因此說到只要CPU處理能力夠強,將來或許可以下降對中高端聲卡性能的需求chrome

例子

爲了展現Web Audio API的用法,咱們編寫了一些例子,這些例子會不斷地增長更新。請你們發揚開源
精神爲項目添加用例或者提出更好的改善意見!canvas

PS:這些例子最好在最新版chrome中運行segmentfault

首先介紹一下 Voice-change-O-matic 。這是一個有變聲及聲音可視化功能的網頁應用,且有一些變聲效果與可視化效果可供選擇。雖然這個應用還有許多能夠改善的地方,但也不失爲綜合使用Web Audio API的許多功能的一個好例子。(能夠在這裏運行 Voice-change-O-matic)瀏覽器

voice-change-o-matic.png

PS:上面的這個例子我運行沒效果啊,不知道怎麼玩
*PS:感謝vino24補充的,該例子須要https,在chrome下可運行網絡

爲了理解Web Audio而編寫的另外一個例子就是這個Violent Theremin。這是一個簡單的應用,它容許你經過鼠標指針的移動來改變頻率和音量。另外,鼠標移動過程還有迷幻光彩的視覺效果。(Violent Theremin的源碼在這裏)架構

violent-theremin.png

基本思路

備註:下面列舉的大多數的代碼片斷都在Violent Theremin中有使用。

Web Audio API的架構設計使得它可以輕鬆實現模塊路由,其中包括對上下文中的音頻內容的操做。基本的音頻編輯可使用audio node進行。但這些節點相互能夠鏈接起來,能夠構成一個節點圖。多個音源或者不一樣種類的頻道最終均可以對應到一個上下文中。這樣模塊化的設計是爲了提供足夠靈活的特性以便開發能夠動態改變效果的複雜的音頻編輯功能。

audio node有入口和出口,多個節點構成相似鏈表同樣的結構。從一個或者多個音源出發,通過一個或者多個處理節點,最終輸出到輸出節點(輸出終端,通常是揚聲器)。(若是有需求的話,也能夠不指定輸出節點。例如,想把音頻數據用圖表的形式展示的場合等。)web audio的一個簡單的典型的流程類是下面這樣子:

  1. 建立AudioContext對象

  2. 在AudioContext對象內設置音源,例如<audio>標籤,震動發聲器,音頻流

  3. 建立effect node(效果節點)。例如reverb, biquad filter, panner, compressor(這些都是音頻特效)

  4. 選擇音頻的最終輸出節點。例如,你的電腦的揚聲器

  5. 音頻通過效果節點處理後,而後輸出到下一個節點,這些節點鏈接起來

建立AudioContext對象

首先,爲了構建audio節點圖,咱們首先要建立建立AudioContext對象。最簡單的方法就像這樣:

var audioCtx = new AudioContext();

備註:雖然能夠在一個document中建立多個AudioContext對象,但這恐怕沒什麼卵用。

可是,Webkit/Blink內核的瀏覽器不須要前綴,Firefox(desktop/mobile/OS)的瀏覽器可能須要前綴,因此爲了兼容性考慮,最好寫成這樣:

var audioCtx = new (window.AudioContext || window.webkitAudioContext)();

建立AudioSource

經過建立的AudioContext對象的方法,咱們能夠進行各類各樣的操做。最初進行的就是,準備要播放的音源。下面列出的東西均可以做爲音源:

簡單地把震動發聲器做爲音源,使用gain節點控制音量,這就構成我咱們接下來要說的例子:

oscillator = audioCtx.createOscillator();
var gainNode = audioCtx.createGain();

備註:若是要播放音樂文件(mp3之類的),通常要利用XHR載入文件數據,那以後建立BufferSource。在這個示例Voice-change-O-matic有代碼。

備註:Scott Michaud封裝了載入和解碼音頻的代碼,開源了一個庫,叫AudioSampleLoader。使用這個的話,XHR以及buffer的操做都會變得異常簡單。

輸入與輸出的鏈接

要想音源(輸入)經過揚聲器(輸出)播放出來,就必需要把二者鏈接起來。將被鏈接的節點做爲參數,調用原來節點的的connect方法就能夠創建節點間的鏈接。大多數類型的節點對象都擁有這個方法。

關於標準的輸出節點能夠參考,AudioContext.destination。標準的輸出節點一般是設備的揚聲器。把oscillator鏈接到gainNode上,gainNode的輸出鏈接到標準輸出上,代碼以下:

oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);

但若是像Voice-change-O-matic同樣,比較複雜的狀況的話。須要像下面同樣將多個節點鏈接起來,造成一張圖。:

source = audioCtx.createMediaStreamSource(stream);
source.connect(analyser);
analyser.connect(distortion);
distortion.connect(biquadFilter);
biquadFilter.connect(convolver);
convolver.connect(gainNode);
gainNode.connect(audioCtx.destination);

上面的代碼建立出的audio圖以下:

voice-change-o-matic-graph.png

多個節點能夠同時鏈接同一個節點。也可讓多個音源經過一個效果節點,達到混音的效果。

備註:Firefox 32 以上版本,在Firefox開發工具中Web Audio編輯器了。有了它以後大大提升了對audio節點圖進行debug的效率。

播放與音調的設定

建立完audio節點圖後,就能夠經過設定audio節點的屬性值或者調用方法來調整節點的效果。下面的例子,咱們來設定下震動發聲器的音調,使用Hz這個單位,以下:

oscillator.type = 0; // sine wave,正弦波
oscillator.frequency.value = 2500; // value in hertz
oscillator.start();

在Violent Theremin這個程序中,設定了音量與周波數的最大值,以下:

var WIDTH = window.innerWidth;
var HEIGHT = window.innerHeight;

var maxFreq = 6000;
var maxVol = 1;

var initialFreq = 3000;
var initialVol = 0.5;

// set options for the oscillator

oscillator.type = 0; // sine wave
oscillator.frequency.value = initialFreq; // value in hertz
oscillator.start();

gainNode.gain.value = initialVol;

加下來是隨着鼠標的移動,按照設定改變周波數。鼠標指針的X座標和Y座標以及周波數和音量的最大值,這些決定了最終輸出聲音的周波數和音量。代碼以下:

// Mouse pointer coordinates

var CurX;
var CurY;

// Get new mouse pointer coordinates when mouse is moved
// then set new gain and putch values

document.onmousemove = updatePage;

function updatePage(e) {   
    CurX = (window.Event) ? e.pageX : event.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
    CurY = (window.Event) ? e.pageY : event.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
    
    oscillator.frequency.value = (CurX/WIDTH) * maxFreq;
    gainNode.gain.value = (CurY/HEIGHT) * maxVol;

    canvasDraw();
}

利用Canvas實現簡單的可視化效果

canvasDraw()是一個每次鼠標移動都會調用的方法。每次調用這個方法,都會在鼠標指針位置所在的地方,把輸出音頻的周波數和音量用不一樣大小和不一樣顏色表現(畫)出來。

function random(number1,number2) {
  var randomNo = number1 + (Math.floor(Math.random() * (number2 - number1)) + 1);
  return randomNo;
}

var canvas = document.querySelector('.canvas');
canvas.width = WIDTH;
canvas.height = HEIGHT;

var canvasCtx = canvas.getContext('2d');

function canvasDraw() {
  rX = CurX;
  rY = CurY;
  rC = Math.floor((gainNode.gain.value/maxVol)*30);
 
  canvasCtx.globalAlpha = 0.2;
 
  for(i=1;i<=15;i=i+2) {
    canvasCtx.beginPath();
    canvasCtx.fillStyle = 'rgb(' + 100+(i*10) + ',' + Math.floor((gainNode.gain.value/maxVol)*255) + ',' + Math.floor((oscillator.frequency.value/maxFreq)*255) + ')';
    canvasCtx.arc(rX+random(0,50),rY+random(0,50),rC/2+i,(Math.PI/180)*0,(Math.PI/180)*360,false);
    canvasCtx.fill();
    canvasCtx.closePath();     
  }    
}

靜音

按下靜音按鈕後,會執行下面的函數。經過把Gain節點與前面鏈接的節點切斷,使得聲音的輸出消失。再按一次按鈕,就會恢復節點之間的鏈接,使得聲音恢復輸出。

var mute = document.querySelector('.mute');

mute.onclick = function() {
  if(mute.id == "") {
    gainNode.disconnect(audioCtx.destination);
    mute.id = "activated";
    mute.innerHTML = "Unmute";
  } else {
    gainNode.connect(audioCtx.destination);
    mute.id = "";    
    mute.innerHTML = "Mute";
  }
}

其餘的節點

在 Web Audio API中其餘還有不少的種類的節點可使用。建立節點、節點與節點之間鏈接起來,造成節點圖,以後經過屬性和方法來改變聲音。從這些點來看,因此節點的使用方式都差很少。

下面,咱們概要地看一下幾個節點。各個節點的詳細狀況能夠在Web_Audio_API中看。

Wave shaper 節點

經過AudioContext.createWaveShaper這個方法,能夠建立WaveShaper節點。

var distortion = audioCtx.createWaveShaper();

要想讓這個對象工做,必須給予與決定波形的函數。經過將這個函數應用於輸入的波形,WaveShaper節點能夠扭曲聲音。對新手來講,一開始寫出這個函數是很困難的吧。經過在網絡上搜索,選用合適的方案就行了。下面是一個發佈在Stack Overflow上的例子:

function makeDistortionCurve(amount) {
  var k = typeof amount === 'number' ? amount : 50,
    n_samples = 44100,
    curve = new Float32Array(n_samples),
    deg = Math.PI / 180,
    i = 0,
    x;
  for ( ; i < n_samples; ++i ) {
    x = i * 2 / n_samples - 1;
    curve[i] = ( 3 + k ) * x * 20 * deg / ( Math.PI + k * Math.abs(x) );
  }
  return curve;
};

在Voice-Change-O-Metic這個例子中,建立了一個叫作distortion的WaveShaper節點,提供了必要的音頻扭曲效果。代碼以下:

source.connect(analyser);
analyser.connect(distortion);
distortion.connect(biquadFilter);

...

distortion.curve = makeDistortionCurve(400);

雙二階過濾器

雙二階過濾器的內部有多個配置項目。能夠經過AudioContext.createBiquadFilter這個方法建立。

var biquadFilter = audioCtx.createBiquadFilter();

在Voice-Change-o-Metic這個例子中,使用的是典型的lowshelf 過濾器。這是爲了提供一個基本的低音増幅效果:

biquadFilter.type = "lowshelf";
biquadFilter.frequency.value = 1000;
biquadFilter.gain.value = 25;

在這個例子中能夠設定過濾器的種類,周波數,甚至gain的值。若是是lowshelf過濾器的話,能夠提供一個比指定周波數低25dB的低音増幅。

關於其餘的Web Audio API的內容

使用Web Audio API的話,能夠作到音頻的可視化與立體化(例如音頻平移等)。關於這些,咱們在其餘的文檔中說明。

後記

終於完了。

翻譯技術文章遠比想象的要困難,特別是遇到不少陌生的某個領域下的專有詞彙。

日語真是神奇,不少硬是用片假名套英文的狀況,呵呵呵,讓我想起了,特律風。

文中難免有錯的地方,但願你們能指出來,幫助文章更好,謝謝。

感謝,@說說說說

相關文章
相關標籤/搜索