Chrome 64 ma długo oczekiwaną nową funkcję w interfejsie Web Audio API: AudioWorklet Poznaj pojęcia i sposoby korzystania z tych narzędzi, aby tworzyć za pomocą niestandardowego procesora audio z kodem JavaScript. Zwróć uwagę na: prezentacji na żywo. Następny artykuł z serii Audio Worklet Design Pattern (wzorzec projektowania elementów audio) może być interesującą lekcją na temat tworzenia zaawansowanej aplikacji audio.
Tło: ScriptProcessorNode
Przetwarzanie dźwięku w Web Audio API działa w osobnym wątku niż główny UI, więc wszystko działa płynnie. Aby włączyć niestandardowe przetwarzanie dźwięku w: JavaScript, interfejs Web Audio API zaproponował skrypt ScriptProcessorNode, moduły obsługi zdarzeń wywołujące skrypt użytkownika w głównym wątku UI.
Na tym etapie występują 2 problemy: asynchroniczna obsługa zdarzeń.
a wykonanie kodu odbywa się w wątku głównym. Poprzedni
wywołuje opóźnienie, które z kolei wpływa na główny wątek, który
często zatłoczony różnymi zadaniami
związanymi z UI i DOM,
do „zacinania” lub dźwięku,
żeby coś się zacięło. Z powodu tego zasadniczego błędu projektowego
Interfejs ScriptProcessorNode
został wycofany ze specyfikacji i
zastąpiono komponentem AudioWorklet.
Pojęcia
Audio Worklet przechowuje kod JavaScript dostarczony przez użytkownika w
wątku przetwarzania dźwięku. Oznacza to, że nie musi przechodzić do elementu głównego
w wątku na potrzeby przetwarzania dźwięku. Oznacza to, że kod skryptu dostarczonego przez użytkownika musi zostać uruchomiony
w wątku renderowania dźwięku (AudioWorkletGlobalScope
) wraz z innymi
wbudowanej funkcji AudioNodes
, która zapewnia zerowe opóźnienia i synchronizację synchroniczną
jak renderowanie.
Rejestracja i tworzenie instancji
Korzystanie z Worklet audio składa się z 2 części: AudioWorkletProcessor
oraz
AudioWorkletNode
Wymaga to więcej pracy niż w przypadku ScriptProcessorNode.
ale konieczne jest zapewnienie programistom niskopoziomowych możliwości
o przetwarzaniu danych. AudioWorkletProcessor
oznacza faktyczny procesor audio
napisanych w kodzie JavaScriptu, a elementy te znajdują się w elemencie AudioWorkletGlobalScope
.
AudioWorkletNode
to odpowiednik AudioWorkletProcessor
i przyjmuje
dba o połączenie z i od innych użytkowników AudioNodes
w wątku głównym. it
jest widoczny w głównym zakresie globalnym i działa jak zwykły AudioNode
.
Oto 2 fragmenty kodu ilustrujące rejestrację oraz tworzenia instancji.
// The code in the main global scope.
class MyWorkletNode extends AudioWorkletNode {
constructor(context) {
super(context, 'my-worklet-processor');
}
}
let context = new AudioContext();
context.audioWorklet.addModule('processors.js').then(() => {
let node = new MyWorkletNode(context);
});
Aby utworzyć AudioWorkletNode
, musisz dodać kontekst AudioContext
a nazwa procesora w formie ciągu znaków. Definicja procesora może być
został wczytany i zarejestrowany przez wywołanie addModule()
nowego obiektu Worklet Audio.
Interfejsy API Worklet, w tym Worklet Audio, są dostępne tylko
bezpieczny kontekst,
strony używające ich muszą być wyświetlane przez HTTPS, podczas gdy http://localhost
to
uważanych za bezpieczne
pod kątem testów lokalnych.
Możesz użyć podklasy AudioWorkletNode
, aby zdefiniować
w węźle niestandardowym
obsługiwanym przez procesor działający w danym obszarze roboczym.
// This is the "processors.js" file, evaluated in AudioWorkletGlobalScope
// upon audioWorklet.addModule() call in the main global scope.
class MyWorkletProcessor extends AudioWorkletProcessor {
constructor() {
super();
}
process(inputs, outputs, parameters) {
// audio processing code here.
}
}
registerProcessor('my-worklet-processor', MyWorkletProcessor);
Metoda registerProcessor()
w AudioWorkletGlobalScope
pobiera
ciąg tekstowy zawierający nazwę procesora, który ma zostać zarejestrowany, oraz definicję klasy.
Po zakończeniu oceny kodu skryptu w zakresie globalnym
obietnica produktu AudioWorklet.addModule()
zostanie rozwiązana powiadamianiem użytkowników
że definicja klasy jest gotowa do użycia w głównym zakresie globalnym.
Niestandardowe parametry audio
Jedną z przydatnych funkcji AudioNodes jest parametr podlegający planowaniu.
automatyzację za pomocą funkcji AudioParam
. AudioWorkletNodes może ich użyć, aby uzyskać
parametrów z grupy eksperymentalnej, które można automatycznie kontrolować, określając szybkość transmisji dźwięku.
Zdefiniowane przez użytkownika parametry audio można zadeklarować w polu AudioWorkletProcessor
.
definicji klasy przez skonfigurowanie zbioru AudioParamDescriptor
.
bazowy mechanizm WebAudio rejestruje te informacje podczas
tworzenia węzła AudioWorkletNode, a następnie tworzy i łączy
AudioParam
obiektów do węzła.
/* A separate script file, like "my-worklet-processor.js" */
class MyWorkletProcessor extends AudioWorkletProcessor {
// Static getter to define AudioParam objects in this custom processor.
static get parameterDescriptors() {
return [{
name: 'myParam',
defaultValue: 0.707
}];
}
constructor() { super(); }
process(inputs, outputs, parameters) {
// |myParamValues| is a Float32Array of either 1 or 128 audio samples
// calculated by WebAudio engine from regular AudioParam operations.
// (automation methods, setter) Without any AudioParam change, this array
// would be a single value of 0.707.
const myParamValues = parameters.myParam;
if (myParamValues.length === 1) {
// |myParam| has been a constant value for the current render quantum,
// which can be accessed by |myParamValues[0]|.
} else {
// |myParam| has been changed and |myParamValues| has 128 values.
}
}
}
AudioWorkletProcessor.process()
metoda
Rzeczywiste przetwarzanie dźwięku ma miejsce w metodzie wywołania zwrotnego process()
w funkcji
AudioWorkletProcessor
Musi zostać wdrożony przez użytkownika w klasie
definicji. Mechanizm WebAudio wywołuje tę funkcję w trybie izochronologicznym
do przesyłania danych wejściowych i parametrów oraz pobierania danych wyjściowych.
/* AudioWorkletProcessor.process() method */
process(inputs, outputs, parameters) {
// The processor may have multiple inputs and outputs. Get the first input and
// output.
const input = inputs[0];
const output = outputs[0];
// Each input or output may have multiple channels. Get the first channel.
const inputChannel0 = input[0];
const outputChannel0 = output[0];
// Get the parameter value array.
const myParamValues = parameters.myParam;
// if |myParam| has been a constant value during this render quantum, the
// length of the array would be 1.
if (myParamValues.length === 1) {
// Simple gain (multiplication) processing over a render quantum
// (128 samples). This processor only supports the mono channel.
for (let i = 0; i < inputChannel0.length; ++i) {
outputChannel0[i] = inputChannel0[i] * myParamValues[0];
}
} else {
for (let i = 0; i < inputChannel0.length; ++i) {
outputChannel0[i] = inputChannel0[i] * myParamValues[i];
}
}
// To keep this processor alive.
return true;
}
Dodatkowo wartości zwracanej przez metodę process()
można używać do
kontrolować okres ważności AudioWorkletNode
, aby deweloperzy mogli zarządzać
wykorzystanie pamięci masowej. Zwracanie false
ze znacznika process()
metody
procesor jest nieaktywny, a mechanizm WebAudio
nie wywołuje już
. Aby procesor był aktywny, metoda musi zwracać wartość true
.
W przeciwnym razie para węzła i procesora stanowi czyszczenie pamięci przez system
w końcu.
Dwukierunkowa komunikacja z MessagePort
Czasami niestandardowy AudioWorkletNode
chce udostępnić ustawienia, które nie są
mapować na AudioParam
, na przykład jako atrybut type
oparty na ciągach znaków
służy do sterowania filtrem niestandardowym. W tym celu i nie tylko,
AudioWorkletNode
i AudioWorkletProcessor
mają:
MessagePort
dla komunikacji dwukierunkowej. Dowolne dane niestandardowe
można wymieniać na tym kanale.
Dostęp do MessagePort można uzyskać za pomocą atrybutu .port
zarówno w węźle,
z procesorem. Metoda port.postMessage()
węzła wysyła komunikat do
w funkcji port.onmessage
powiązanego procesora i odwrotnie.
/* The code in the main global scope. */
context.audioWorklet.addModule('processors.js').then(() => {
let node = new AudioWorkletNode(context, 'port-processor');
node.port.onmessage = (event) => {
// Handling data from the processor.
console.log(event.data);
};
node.port.postMessage('Hello!');
});
/* "processors.js" file. */
class PortProcessor extends AudioWorkletProcessor {
constructor() {
super();
this.port.onmessage = (event) => {
// Handling data from the node.
console.log(event.data);
};
this.port.postMessage('Hi!');
}
process(inputs, outputs, parameters) {
// Do nothing, producing silent output.
return true;
}
}
registerProcessor('port-processor', PortProcessor);
MessagePort
obsługuje przenoszenie, co pozwala
pamięci masowej do przesyłania danych lub modułu WASM ponad granicę wątku. Spowoduje to otwarcie
daje niezliczone możliwości wykorzystania systemu Audio Worklet.
Przewodnik: tworzenie węzła GainNode
Oto kompletny przykładowy interfejs GainNode oparty na
AudioWorkletNode
i AudioWorkletProcessor
.
Plik index.html
:
<!doctype html>
<html>
<script>
const context = new AudioContext();
// Loads module script with AudioWorklet.
context.audioWorklet.addModule('gain-processor.js').then(() => {
let oscillator = new OscillatorNode(context);
// After the resolution of module loading, an AudioWorkletNode can be
// constructed.
let gainWorkletNode = new AudioWorkletNode(context, 'gain-processor');
// AudioWorkletNode can be interoperable with other native AudioNodes.
oscillator.connect(gainWorkletNode).connect(context.destination);
oscillator.start();
});
</script>
</html>
Plik gain-processor.js
:
class GainProcessor extends AudioWorkletProcessor {
// Custom AudioParams can be defined with this static getter.
static get parameterDescriptors() {
return [{ name: 'gain', defaultValue: 1 }];
}
constructor() {
// The super constructor call is required.
super();
}
process(inputs, outputs, parameters) {
const input = inputs[0];
const output = outputs[0];
const gain = parameters.gain;
for (let channel = 0; channel < input.length; ++channel) {
const inputChannel = input[channel];
const outputChannel = output[channel];
if (gain.length === 1) {
for (let i = 0; i < inputChannel.length; ++i)
outputChannel[i] = inputChannel[i] * gain[0];
} else {
for (let i = 0; i < inputChannel.length; ++i)
outputChannel[i] = inputChannel[i] * gain[i];
}
}
return true;
}
}
registerProcessor('gain-processor', GainProcessor);
Omawiamy podstawy systemu Audio Worklet. Dostępne są prezentacje na żywo w repozytorium zespołu Chrome WebAudio na GitHubie.
Przejście funkcji: wersja eksperymentalna na stabilną
Worklet audio jest domyślnie włączony w Chrome 66 i nowszych wersjach. W Chrome 64 i 65 ta funkcja była dostępna za flagą eksperymentalnej.