摘要:前言本文翻譯自上的利用,這是中的的一個(gè)入門教程。原文是英文,但有日本同志翻譯的日文版。這是為了提供一個(gè)基本的低音増幅效果在這個(gè)例子中可以設(shè)定過(guò)濾器的種類,周波數(shù),甚至的值。如果是過(guò)濾器的話,可以提供一個(gè)比指定周波數(shù)低的低音増幅。
前言
本文翻譯自MDN上的《Web Audio APIの利用》,這是HTML5中的Web Audio API的一個(gè)入門教程。原文是英文,但有日本同志翻譯的日文版。我更熟悉日文,所以主要根據(jù)日文版翻譯成簡(jiǎn)體中文,也會(huì)對(duì)照英文版的。
Web Audio API的使用Web Audio API提供給你一個(gè)簡(jiǎn)單卻強(qiáng)大的機(jī)制,你可以利用它去實(shí)現(xiàn)與操作web應(yīng)用內(nèi)的音頻內(nèi)容。通過(guò)它,在網(wǎng)頁(yè)中你也可以進(jìn)行混音、音效、平移等各種復(fù)雜的音頻處理功能的開發(fā)。這篇文章主要想通過(guò)兩個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明Web Audio API的基礎(chǔ)使用方法。
Web Audio API并不是替代
Web Audio API的一個(gè)強(qiáng)大之處是它沒有嚴(yán)格的[發(fā)出聲音的數(shù)目的限制]。例如,一秒內(nèi)可以同時(shí)發(fā)出32個(gè)聲音或64個(gè)聲音,但這并不是上限。CPU的處理能力足夠的話,1000多種聲音也可以不經(jīng)過(guò)壓縮直接播放。如果這樣發(fā)展下去的話,幾年之后的中高端聲卡的負(fù)荷會(huì)大大降低的吧。
PS:補(bǔ)充點(diǎn)背景知識(shí),這里提到的32,64指的是復(fù)音數(shù)。復(fù)音數(shù)指MIDI樂曲在一秒鐘內(nèi)發(fā)出的最大聲音數(shù)目。關(guān)于復(fù)音數(shù)和MIDI樂曲可以百度一下。聲卡硬件會(huì)限制復(fù)音數(shù),部分軟件使用CPU實(shí)現(xiàn)聲音播放的也會(huì)限制復(fù)音數(shù)。但理論上只要CPU處理能力夠強(qiáng)復(fù)音數(shù)是不受限的。所以上段提及Web Audio Api是軟件,但它沒有復(fù)音數(shù)限制,所以說(shuō)到只要CPU處理能力夠強(qiáng),未來(lái)或許能夠降低對(duì)中高端聲卡性能的需求
例子為了展示W(wǎng)eb Audio API的用法,我們編寫了一些例子,這些例子會(huì)不斷地增加更新。請(qǐng)大家發(fā)揚(yáng)開源
精神為項(xiàng)目添加用例或者提出更好的改善意見!
PS:這些例子最好在最新版chrome中運(yùn)行
首先介紹一下 Voice-change-O-matic 。這是一個(gè)有變聲及聲音可視化功能的網(wǎng)頁(yè)應(yīng)用,且有一些變聲效果與可視化效果可供選擇。雖然這個(gè)應(yīng)用還有許多可以改善的地方,但也不失為綜合使用Web Audio API的許多功能的一個(gè)好例子。(可以在這里運(yùn)行 Voice-change-O-matic)
PS:上面的這個(gè)例子我運(yùn)行沒效果啊,不知道怎么玩
*PS:感謝vino24補(bǔ)充的,該例子需要https,在chrome下可運(yùn)行
為了理解Web Audio而編寫的另一個(gè)例子就是這個(gè)Violent Theremin。這是一個(gè)簡(jiǎn)單的應(yīng)用,它允許你通過(guò)鼠標(biāo)指針的移動(dòng)來(lái)改變頻率和音量。另外,鼠標(biāo)移動(dòng)過(guò)程還有迷幻光彩的視覺效果。(Violent Theremin的源碼在這里)
基本思路備注:下面列舉的大多數(shù)的代碼片段都在Violent Theremin中有使用。
Web Audio API的架構(gòu)設(shè)計(jì)使得它能夠輕松實(shí)現(xiàn)模塊路由,其中包括對(duì)上下文中的音頻內(nèi)容的操作。基本的音頻編輯可以使用audio node進(jìn)行。但這些節(jié)點(diǎn)相互可以連接起來(lái),可以構(gòu)成一個(gè)節(jié)點(diǎn)圖。多個(gè)音源或者不同種類的頻道最終都可以對(duì)應(yīng)到一個(gè)上下文中。這樣模塊化的設(shè)計(jì)是為了提供足夠靈活的特性以便開發(fā)可以動(dòng)態(tài)改變效果的復(fù)雜的音頻編輯功能。
audio node有入口和出口,多個(gè)節(jié)點(diǎn)構(gòu)成類似鏈表一樣的結(jié)構(gòu)。從一個(gè)或者多個(gè)音源出發(fā),經(jīng)過(guò)一個(gè)或者多個(gè)處理節(jié)點(diǎn),最終輸出到輸出節(jié)點(diǎn)(輸出終端,一般是揚(yáng)聲器)。(如果有需求的話,也可以不指定輸出節(jié)點(diǎn)。例如,想把音頻數(shù)據(jù)用圖表的形式展現(xiàn)的場(chǎng)合等。)web audio的一個(gè)簡(jiǎn)單的典型的流程類是下面這樣子:
創(chuàng)建AudioContext對(duì)象
在AudioContext對(duì)象內(nèi)設(shè)置音源,例如
創(chuàng)建effect node(效果節(jié)點(diǎn))。例如reverb, biquad filter, panner, compressor(這些都是音頻特效)
選擇音頻的最終輸出節(jié)點(diǎn)。例如,你的電腦的揚(yáng)聲器
音頻經(jīng)過(guò)效果節(jié)點(diǎn)處理后,然后輸出到下一個(gè)節(jié)點(diǎn),這些節(jié)點(diǎn)連接起來(lái)
創(chuàng)建AudioContext對(duì)象首先,為了構(gòu)建audio節(jié)點(diǎn)圖,我們首先要?jiǎng)?chuàng)建創(chuàng)建AudioContext對(duì)象。最簡(jiǎn)單的方法就像這樣:
var audioCtx = new AudioContext();
備注:雖然可以在一個(gè)document中創(chuàng)建多個(gè)AudioContext對(duì)象,但這恐怕沒什么卵用。
但是,Webkit/Blink內(nèi)核的瀏覽器不需要前綴,F(xiàn)irefox(desktop/mobile/OS)的瀏覽器可能需要前綴,所以為了兼容性考慮,最好寫成這樣:
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();創(chuàng)建AudioSource
通過(guò)創(chuàng)建的AudioContext對(duì)象的方法,我們可以進(jìn)行各種各樣的操作。最初進(jìn)行的就是,準(zhǔn)備要播放的音源。下面列出的東西都可以作為音源:
使用震動(dòng)發(fā)聲器與JavaScript創(chuàng)建音源的情況:使用AudioContext.createOscillator這個(gè)方法創(chuàng)建OscillatorNode。之后就可以利用震動(dòng)發(fā)聲器做音源了。
使用原始的PCM數(shù)據(jù)的情況:如果是可以識(shí)別的特定的格式的話(mp3之類的),使用AudioContext的特定的decode方法,來(lái)獲得PCM數(shù)據(jù)。詳細(xì)情況可以看這些,AudioContext.createBuffer()、AudioContext.createBufferSource()、AudioContext.decodeAudioData() 。
使用
從WebRTC MediaStream(WebRTC媒體流)輸入音頻源的情況:可以使用麥克風(fēng)或者Web攝像頭。具體情況看這個(gè),AudioContext.createMediaStreamSource()
簡(jiǎn)單地把震動(dòng)發(fā)聲器作為音源,使用gain節(jié)點(diǎn)控制音量,這就構(gòu)成我我們接下來(lái)要說(shuō)的例子:
oscillator = audioCtx.createOscillator(); var gainNode = audioCtx.createGain();
備注:如果要播放音樂文件(mp3之類的),一般要利用XHR載入文件數(shù)據(jù),那之后創(chuàng)建BufferSource。在這個(gè)示例Voice-change-O-matic有代碼。
備注:Scott Michaud封裝了載入和解碼音頻的代碼,開源了一個(gè)庫(kù),叫AudioSampleLoader。使用這個(gè)的話,XHR以及buffer的操作都會(huì)變得異常簡(jiǎn)單。
輸入與輸出的連接要想音源(輸入)通過(guò)揚(yáng)聲器(輸出)播放出來(lái),就必須要把兩者連接起來(lái)。將被連接的節(jié)點(diǎn)作為參數(shù),調(diào)用原來(lái)節(jié)點(diǎn)的的connect方法就可以建立節(jié)點(diǎn)間的連接。大多數(shù)類型的節(jié)點(diǎn)對(duì)象都擁有這個(gè)方法。
關(guān)于標(biāo)準(zhǔn)的輸出節(jié)點(diǎn)可以參考,AudioContext.destination。標(biāo)準(zhǔn)的輸出節(jié)點(diǎn)通常是設(shè)備的揚(yáng)聲器。把oscillator連接到gainNode上,gainNode的輸出連接到標(biāo)準(zhǔn)輸出上,代碼如下:
oscillator.connect(gainNode); gainNode.connect(audioCtx.destination);
但如果像Voice-change-O-matic一樣,比較復(fù)雜的情況的話。需要像下面一樣將多個(gè)節(jié)點(diǎn)連接起來(lái),形成一張圖。:
source = audioCtx.createMediaStreamSource(stream); source.connect(analyser); analyser.connect(distortion); distortion.connect(biquadFilter); biquadFilter.connect(convolver); convolver.connect(gainNode); gainNode.connect(audioCtx.destination);
上面的代碼創(chuàng)建出的audio圖如下:
多個(gè)節(jié)點(diǎn)可以同時(shí)連接同一個(gè)節(jié)點(diǎn)。也可以讓多個(gè)音源通過(guò)一個(gè)效果節(jié)點(diǎn),達(dá)到混音的效果。
備注:Firefox 32 以上版本,在Firefox開發(fā)工具中Web Audio編輯器了。有了它之后大大提高了對(duì)audio節(jié)點(diǎn)圖進(jìn)行debug的效率。
播放與音調(diào)的設(shè)定創(chuàng)建完audio節(jié)點(diǎn)圖后,就可以通過(guò)設(shè)定audio節(jié)點(diǎn)的屬性值或者調(diào)用方法來(lái)調(diào)整節(jié)點(diǎn)的效果。下面的例子,我們來(lái)設(shè)定下震動(dòng)發(fā)聲器的音調(diào),使用Hz這個(gè)單位,如下:
oscillator.type = 0; // sine wave,正弦波 oscillator.frequency.value = 2500; // value in hertz oscillator.start();
在Violent Theremin這個(gè)程序中,設(shè)定了音量與周波數(shù)的最大值,如下:
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;
加下來(lái)是隨著鼠標(biāo)的移動(dòng),按照設(shè)定改變周波數(shù)。鼠標(biāo)指針的X坐標(biāo)和Y坐標(biāo)以及周波數(shù)和音量的最大值,這些決定了最終輸出聲音的周波數(shù)和音量。代碼如下:
// 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實(shí)現(xiàn)簡(jiǎn)單的可視化效果
canvasDraw()是一個(gè)每次鼠標(biāo)移動(dòng)都會(huì)調(diào)用的方法。每次調(diào)用這個(gè)方法,都會(huì)在鼠標(biāo)指針位置所在的地方,把輸出音頻的周波數(shù)和音量用不同大小和不同顏色表現(xiàn)(畫)出來(lái)。
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(); } }靜音
按下靜音按鈕后,會(huì)執(zhí)行下面的函數(shù)。通過(guò)把Gain節(jié)點(diǎn)與前面連接的節(jié)點(diǎn)切斷,使得聲音的輸出消失。再按一次按鈕,就會(huì)恢復(fù)節(jié)點(diǎn)之間的連接,使得聲音恢復(fù)輸出。
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"; } }其他的節(jié)點(diǎn)
在 Web Audio API中其他還有很多的種類的節(jié)點(diǎn)可以使用。創(chuàng)建節(jié)點(diǎn)、節(jié)點(diǎn)與節(jié)點(diǎn)之間連接起來(lái),形成節(jié)點(diǎn)圖,之后通過(guò)屬性和方法來(lái)改變聲音。從這些點(diǎn)來(lái)看,所以節(jié)點(diǎn)的使用方式都差不多。
下面,我們概要地看一下幾個(gè)節(jié)點(diǎn)。各個(gè)節(jié)點(diǎn)的詳細(xì)情況可以在Web_Audio_API中看。
Wave shaper 節(jié)點(diǎn)通過(guò)AudioContext.createWaveShaper這個(gè)方法,可以創(chuàng)建WaveShaper節(jié)點(diǎn)。
var distortion = audioCtx.createWaveShaper();
要想讓這個(gè)對(duì)象工作,必須給予與決定波形的函數(shù)。通過(guò)將這個(gè)函數(shù)應(yīng)用于輸入的波形,WaveShaper節(jié)點(diǎn)可以扭曲聲音。對(duì)新手來(lái)說(shuō),一開始寫出這個(gè)函數(shù)是很困難的吧。通過(guò)在網(wǎng)絡(luò)上搜索,選用合適的方案就好了。下面是一個(gè)發(fā)布在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這個(gè)例子中,創(chuàng)建了一個(gè)叫做distortion的WaveShaper節(jié)點(diǎn),提供了必要的音頻扭曲效果。代碼如下:
source.connect(analyser); analyser.connect(distortion); distortion.connect(biquadFilter); ... distortion.curve = makeDistortionCurve(400);雙二階過(guò)濾器
雙二階過(guò)濾器的內(nèi)部有多個(gè)配置項(xiàng)目。可以通過(guò)AudioContext.createBiquadFilter這個(gè)方法創(chuàng)建。
var biquadFilter = audioCtx.createBiquadFilter();
在Voice-Change-o-Metic這個(gè)例子中,使用的是典型的lowshelf 過(guò)濾器。這是為了提供一個(gè)基本的低音増幅效果:
biquadFilter.type = "lowshelf"; biquadFilter.frequency.value = 1000; biquadFilter.gain.value = 25;
在這個(gè)例子中可以設(shè)定過(guò)濾器的種類,周波數(shù),甚至gain的值。如果是lowshelf過(guò)濾器的話,可以提供一個(gè)比指定周波數(shù)低25dB的低音増幅。
關(guān)于其他的Web Audio API的內(nèi)容使用Web Audio API的話,可以做到音頻的可視化與立體化(例如音頻平移等)。關(guān)于這些,我們?cè)谄渌奈臋n中說(shuō)明。
后記終于完了。
翻譯技術(shù)文章遠(yuǎn)比想象的要困難,特別是遇到很多陌生的某個(gè)領(lǐng)域下的專有詞匯。
日語(yǔ)真是神奇,很多硬是用片假名套英文的情況,呵呵呵,讓我想起了,特律風(fēng)。
文中不免有錯(cuò)的地方,希望大家能指出來(lái),幫助文章更好,謝謝。
感謝,@說(shuō)說(shuō)說(shuō)說(shuō)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/79643.html
摘要:你知道在瀏覽器環(huán)境下能夠利用到的提交請(qǐng)求數(shù)據(jù)的方式有哪些嗎這些方式各自有什么特點(diǎn)呢在什么情況下使用呢讓我們一起來(lái)整理一下。其實(shí)這也是能夠利用到的提交請(qǐng)求數(shù)據(jù)的方式之一。 你知道在瀏覽器環(huán)境下JavaScript能夠利用到的提交/請(qǐng)求數(shù)據(jù)的方式有哪些嗎?這些方式各自有什么特點(diǎn)呢?在什么情況下使用呢?讓我們一起來(lái)整理一下。 基礎(chǔ)知識(shí) 建議大家先看完這幾篇文章,了解一下基礎(chǔ)知識(shí) HTTP訪...
摘要:做一個(gè)搬運(yùn)工,希望自己能努力學(xué)習(xí),也希望大神們的東西能讓更多的人看到不斷更新更新日志新增了網(wǎng)絡(luò)安全分類,整理了排版布局新增了的鏈接,將一些雜七雜八的東西弄到了一篇新文章上了,叫做積累與雜貨鋪一以及相關(guān)教程的規(guī)范與相關(guān)中文學(xué)習(xí)大本營(yíng)中文文檔簡(jiǎn) 做一個(gè)搬運(yùn)工,希望自己能努力學(xué)習(xí),也希望大神們的東西能讓更多的人看到 不斷更新 更新日志:2017.10.13 新增了網(wǎng)絡(luò)安全分類,整理了排版布局...
摘要:做一個(gè)搬運(yùn)工,希望自己能努力學(xué)習(xí),也希望大神們的東西能讓更多的人看到不斷更新更新日志新增了網(wǎng)絡(luò)安全分類,整理了排版布局新增了的鏈接,將一些雜七雜八的東西弄到了一篇新文章上了,叫做積累與雜貨鋪一以及相關(guān)教程的規(guī)范與相關(guān)中文學(xué)習(xí)大本營(yíng)中文文檔簡(jiǎn) 做一個(gè)搬運(yùn)工,希望自己能努力學(xué)習(xí),也希望大神們的東西能讓更多的人看到 不斷更新 更新日志:2017.10.13 新增了網(wǎng)絡(luò)安全分類,整理了排版布局...
閱讀 573·2021-11-18 10:02
閱讀 1052·2021-11-02 14:41
閱讀 679·2021-09-03 10:29
閱讀 1896·2021-08-23 09:42
閱讀 2735·2021-08-12 13:31
閱讀 1203·2019-08-30 15:54
閱讀 1958·2019-08-30 13:09
閱讀 1430·2019-08-30 10:55