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

Kuba Sienkiewicz
Chris Wilson

Chrome stale i cicho ulepsza obsługę interfejsu Web Audio API. W Chrome 49 (od lutego 2016 r.) w wersji beta, która powinna być stabilna w marcu 2016 r., zaktualizowaliśmy kilka funkcji, żeby śledzić to specyfikację, i dodaliśmy też 1 nowy węzeł.

DecodeAudioData() zwraca teraz obietnicę

Metoda decodeAudioData() w obiekcie AudioContext zwraca teraz wartość Promise, co umożliwia asynchroniczną obsługę wzorców na podstawie obietnicy. Metoda decodeAudioData() zawsze przyjmowała funkcje wywołania zwrotnego sukcesu i błędu jako parametry:

context.decodeAudioData( arraybufferData, onSuccess, onError);

Jednak teraz możesz korzystać ze standardowej metody Promise do obsługi asynchronicznej natury dekodowania danych audio:

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

Choć jeden przykład wygląda bardziej szczegółowy, z obietnictwem obiecane podejście ułatwia programowanie asynchroniczne i spójniejsze. Aby zapewnić zgodność, funkcje wywołań zwrotnych „Sukces” i „Error” są nadal obsługiwane zgodnie ze specyfikacją.

Tryb offlineAudioContext obsługuje teraz funkcje zawiesza() i wznawianie()

Na pierwszy rzut oka może wydawać się dziwne, że wspomniany tryb zawieszenia() w obszarze OfflineAudioContext może się wydawać dziwny. Ostatecznie suspend() został dodany do AudioContext, aby umożliwić włączenie sprzętu audio w tryb gotowości, co w sytuacjach, gdy renderujesz dane do bufora (oczywiście do tego służy OfflineAudioContext). Celem tej funkcji jest jednak możliwość generowania jednocześnie tylko części „wyniku”, co pozwala zminimalizować wykorzystanie pamięci. Możesz utworzyć więcej węzłów w trakcie renderowania w trybie zawieszenia.

Na przykład sonata księżycowa Beethovena zawiera około 6500 nut. Każda „notatka” prawdopodobnie dekonstruuje co najmniej kilka węzłów wykresu audio (np. bufor dźwięku i węzeł wzmocnienia). Jeśli zamierzasz wyrenderować całe 7 i pół minuty w buforze za pomocą funkcji OfflineAudioContext, prawdopodobnie nie chcesz tworzyć wszystkich tych węzłów naraz. Zamiast tego możesz je tworzyć według fragmentów czasu:

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();
}

Pomaga to zminimalizować liczbę węzłów, które trzeba utworzyć na początku renderowania, i zmniejszyć zapotrzebowanie na pamięć.

IIRFilterNode

Do specyfikacji dodano węzeł dla audiofilów, którzy chcą utworzyć własną dokładnie określoną odpowiedź na nieskończoną impuls: IIRFilterNode. Ten filtr uzupełnia element BiquadFilterNode, ale umożliwia określenie parametrów odpowiedzi filtra (zamiast łatwego w użyciu AudioParams obiektu BiquadFilterNode typu, częstotliwości, Q itp.). Element IIRFilterNode umożliwia dokładne określanie filtrów, których nie udało się utworzyć wcześniej, takich jak filtry jednoporządkowe. Jednak korzystanie z IIRFilterNode wymaga dogłębnej wiedzy o sposobie działania filtrów IIR. Poza tym nie można go planować, tak jak w przypadku obiektów BiquadFilterNodes.

Poprzednie zmiany

Chcę też wspomnieć o kilku ulepszeniach, które pojawiły się wcześniej: w Chrome 48 automatyzacja węzłów BiquadFilter zaczęła działać z szybkością dźwięku. Interfejs API w ogóle się nie zmienił, ale dzięki temu filtrowanie filtrów będzie brzmieć jeszcze płynniej. Ponadto w Chrome 48 dodaliśmy łańcuch do metody AudioNode.connect() przez zwrócenie węzła, z którym się łączysz. Ułatwia to tworzenie łańcuchów węzłów, jak w tym przykładzie:

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

Na razie to wszystko.