Aktualizacje dźwięku w przeglądarce w Chrome 49

Chris Wilson
Chris Wilson

W Chrome stale i bezgłośnie ulepszamy obsługę interfejsu Web Audio API. W Chrome 49 (w wersji beta od lutego 2016 r., a w wersji stabilnej w marcu 2016 r.) zaktualizowaliśmy kilka funkcji, aby były zgodne ze specyfikacją, oraz dodaliśmy nowy węzeł.

Metoda decodeAudioData() zwraca teraz obietnicę.

Metoda decodeAudioData() w obiekcie AudioContext zwraca teraz obiekt Promise, co umożliwia obsługę asynchronicznych wzorów na podstawie obietnic. Metoda decodeAudioData() zawsze przyjmowała jako parametry funkcje wywołania zwrotnego dla powodzenia i błędu:

context.decodeAudioData( arraybufferData, onSuccess, onError);

Teraz możesz jednak użyć standardowej metody Promise, aby obsłużyć asynchroniczną naturę dekodowania danych audio:

context.decodeAudioData( arraybufferData ).then(
        (buffer) => { /* store the buffer */ },
        (reason) => { console.log("decode failed! " + reason) });

Chociaż w pojedynczym przykładzie wygląda to na bardziej skomplikowane, obietnice ułatwiają programowanie asynchroniczne i czynią je bardziej spójnymi. Ze względu na zgodność nadal obsługiwane są funkcje wywołania zwrotnego Success i Error zgodnie ze specyfikacją.

OfflineAudioContext obsługuje teraz suspend() i resume()

Na pierwszy rzut oka może się wydawać dziwne, że wywołanie suspend() występuje w obiekcie OfflineAudioContext. W końcu suspend() zostało dodane do AudioContext, aby umożliwić przełączenie sprzętu audio w tryb gotowości, co wydaje się bezcelowe w sytuacjach, gdy renderujesz do bufora (do czego oczywiście służy OfflineAudioContext). Jednak sens tej funkcji polega na tym, aby móc tworzyć tylko część „wyników” naraz, aby zminimalizować wykorzystanie pamięci. Możesz utworzyć więcej węzłów, gdy zawiesisz renderowanie w trakcie jego wykonywania.

Na przykład Sonata księżycowa Beethovena zawiera około 6500 nut. Każda „nuta” prawdopodobnie składa się z co najmniej kilku węzłów w grafie audio (np. węzła AudioBuffer i węzła Gain). Jeśli chcesz wyrenderować cały 7,5-minutowy bufor za pomocą OfflineAudioContext, prawdopodobnie nie chcesz tworzyć wszystkich tych węzłów naraz. Zamiast tego możesz je tworzyć w okresie:

var context = new OfflineAudioContext(2, length, sampleRate);
scheduleNextBlock();
context.startRendering().then( (buffer) => { /* store the buffer */ } );

function scheduleNextBlock() {
    // create any notes for the next blockSize number of seconds here
    // ...

    // make sure to tell the context to suspend again after this block;
    context.suspend(context.currentTime + blockSize).then( scheduleNextBlock );

    context.resume();
}

Pozwoli to zminimalizować liczbę węzłów, które należy utworzyć na początku renderowania, i zmniejszy zapotrzebowanie na pamięć.

IIRFilterNode

Specyfikacja została rozszerzona o węzeł dla audiofilów, którzy chcą tworzyć własne dokładnie określone obwody stałoimpedancyjne: IIRFilterNode. Ten filtr uzupełnia węzeł BiquadFilterNode, ale umożliwia pełną specyfikację parametrów odpowiedzi filtra (zamiast łatwych w użyciu parametrów BiquadFilterNode AudioParams typu, częstotliwości, Q i podobnych). IIRFilterNode umożliwia dokładne określenie filtrów, których nie można było utworzyć wcześniej, np. filtrów jednorzędowych. Jednak korzystanie z IIRFilterNode wymaga pewnej wiedzy na temat działania filtrów IIR. Nie można też zaplanować działania takich węzłów, tak jak w przypadku węzłów BiquadFilterNode.

Poprzednie zmiany

Chcę też wspomnieć o kilku ulepszeniach, które zostały wprowadzone wcześniej: w Chrome 48 automatyzacja węzła BiquadFilter zaczęła działać z częstotliwością dźwięku. Interfejs API nie zmienił się w żaden sposób, ale dzięki temu Twoje filtry będą brzmieć jeszcze płynniej. W Chrome 48 dodaliśmy łańcuch do metody AudioNode.connect(), zwracając węzeł, z którym się łączymy. Dzięki temu łatwiej jest tworzyć łańcuchy węzłów, jak w tym przykładzie:

sourceNode.connect(gainNode).connect(filterNode).connect(context.destination);

To wszystko na razie.