個案研究 - 使用 Chrome 的 JAM

我們如何製作這聲樂聲

Oskar Eriksson
Oskar Eriksson

簡介

JAM 版 Chrome 是由 Google 建立的網路音樂專案。Chrome 版 Chrome 可讓世界各地的使用者組成樂團,透過瀏覽器即時享受他們的音樂。DinahMoe 很高興能參與這項專案。我們的角色是為應用程式製作音樂,以及設計和開發音樂元素。這個開發過程主要分為三個領域:一個「音樂工作站」(包括片中廣告、軟體取樣器、音效、轉送和混音);該音樂邏輯引擎可讓您以互動方式即時控制音樂;以及確保工作階段中的所有玩家都能同時聽到音樂的同步元件,這都是可以一起演奏的先決條件。

我們選擇使用 Web Audio API,盡可能確保真實程度、準確性和音質。本個案研究將探討我們面臨的部分挑戰,以及我們如何解決這些問題。HTML5Rocks 提供許多實用的入門文章,協助您開始使用網路音訊,因此我們直接深入研究資料。

撰寫自訂音效

Web Audio API 的規格中有許多實用的效果,但我們需要為 JAM 使用 Chrome 中的樂器提供更多更精細的效果。舉例來說,網路音訊中只有一個原生延遲節點,但「延遲」有多種類型,例如立體聲延遲、連線偵測 (ping) 延遲、回溯延遲和清單啟用。幸好,這些全都可以使用原生效果節點和想像力在 Web Audio 中建立。

既然我們想盡可能使用原生節點和我們自訂的效果,以便達到這樣公開透明的效果,因此決定建立包裝函式格式來達成這個目的。Web Audio 中的原生節點會使用其連線方法將節點相互連結,因此我們需要模擬這個行為。基本概念如下所示:

var MyCustomNode = function(){
    this.input = audioContext.createGain();
    var output = audioContext.createGain();

    this.connect = function(target){
       output.connect(target);
    };
};

透過這個模式,我們非常接近原生節點。讓我們看看該怎麼使用。

//create a couple of native nodes and our custom node
var gain = audioContext.createGain(),
    customNode = new MyCustomNode(),
    anotherGain = audioContext.createGain();

//connect our custom node to the native nodes and send to the output
gain.connect(customNode.input);
customNode.connect(anotherGain);
anotherGain.connect(audioContext.destination);
轉送自訂節點

自訂節點和原生節點的唯一差異,就是必須連線至自訂節點輸入屬性。我相信有些方法可以規避這個,但距離目標遠遠足以達成我們的目的。您可以進一步開發這個模式,藉此模擬原生 AudioNodes 的中斷連線方法,以及在連線時配合使用者定義的輸入/輸出作業。查看規格,瞭解原生節點的功能。

既然我們已經擁有建立自訂效果的基本模式,下一步就是為自訂節點設定一些自訂行為。我們來看看一個備用延遲節點

吸收他人的自拍照

回響延遲有時也稱為「回響回響」,是融入 50 風格的人聲與衝浪吉他等多種樂器的經典效果。這個效果會接收傳入音效,然後播放音訊副本,但稍微延遲約 75 到 250 毫秒。感覺到只是因為把聲音滑回去,所以知道它的名字。我們可以建立如下的效果:

var SlapbackDelayNode = function(){
    //create the nodes we'll use
    this.input = audioContext.createGain();
    var output = audioContext.createGain(),
        delay = audioContext.createDelay(),
        feedback = audioContext.createGain(),
        wetLevel = audioContext.createGain();

    //set some decent values
    delay.delayTime.value = 0.15; //150 ms delay
    feedback.gain.value = 0.25;
    wetLevel.gain.value = 0.25;

    //set up the routing
    this.input.connect(delay);
    this.input.connect(output);
    delay.connect(feedback);
    delay.connect(wetLevel);
    feedback.connect(delay);
    wetLevel.connect(output);

    this.connect = function(target){
       output.connect(target);
    };
};
備用節點的內部路由

在一些您可能已經知道,這個延遲情況也可以延長延遲時間,因此提供意見回饋將變成常態的單聲道。以下舉例說明使用這項延遲時間,讓您聽到聲音。

轉送音訊

在專業音訊應用程式中使用不同樂器和音樂零件時,請務必提供靈活的路由系統,以便有效混音及調整聲音。在 JAM Chrome 版中,我們開發了音訊匯流排系統,這與實體混音板的類似。如此一來,我們就能連結所有需回電公車或水道的樂器,然後在該公車中加入回音,而不必為每個獨立樂器加上回音。這屬於重大最佳化作業,當您開始執行較複雜的應用程式時,建議您立即執行類似的作業。

AudioBus 轉送方式

幸好,在網路音訊中就可以輕鬆達成此目的。基本上,我們可以運用為特效定義的骨架,以相同的方式加以使用。

var AudioBus = function(){
    this.input = audioContext.createGain();
    var output = audioContext.createGain();

    //create effect nodes (Convolver and Equalizer are other custom effects from the library presented at the end of the article)
    var delay = new SlapbackDelayNode(),
        convolver = new tuna.Convolver(),
        equalizer = new tuna.Equalizer();

    //route 'em
    //equalizer -> delay -> convolver
    this.input.connect(equalizer);
    equalizer.connect(delay.input);
    delay.connect(convolver);
    convolver.connect(output);

    this.connect = function(target){
       output.connect(target);
    };
};

方式如下:

//create some native oscillators and our custom audio bus
var bus = new AudioBus(),
    instrument1 = audioContext.createOscillator(),
    instrument2 = audioContext.createOscillator(),
    instrument3 = audioContext.createOscillator();

//connect our instruments to the same bus
instrument1.connect(bus.input);
instrument2.connect(bus.input);
instrument3.connect(bus.input);
bus.connect(audioContext.destination);

反之,我們將延遲、均等化和回響 (對效能的影響而言) 是大幅增加的成本,就好比將效果套用到每種樂器的一半。如果我們想要為匯流排增添一些添加效果,可以加入兩個新的增益節點 ( preGet 和 postGain),以便我們透過兩種不同方式關閉或淡出公車中的聲音。預先增益應置於影響前,而後增益會置於鏈結的末端。若我們淡出 2 來淡出,讓效果在獲得增益後仍會產生共鳴,但如果我們漸漸淡化 postGain 音效,所有聲音就會同時設為靜音。

從這裡出發的目的地?

我在這裡說明的這些方法,可能需要進一步發展。如要實作 (例如自訂節點的輸入和輸出內容,以及連線方法),則應使用原型繼承進行實作。公車應能藉由傳遞效果清單,以動態方式產生特效。

為慶祝 JAM Chrome 版推出,我們決定採用開放原始碼效果架構。如果這份簡短說明您引人注目,不妨放手一番,並視情況做出貢獻。相關主題請參閱這裡的討論,瞭解如何將自訂網路音訊內容格式標準化。與觀眾同樂!