Chrome 64 では、待望の Web Audio API の新機能が実装されます。 AudioWorklet。ここでは、Terraform ワークフローの カスタムオーディオプロセッサを 開発しています詳しくは、 ライブデモ シリーズの次の記事「オーディオ ワークレットのデザイン パターン」では、 高度なオーディオ アプリを作成するうえで興味深いドキュメントです。
バックグラウンド: ScriptProcessorNode
Web Audio API の音声処理はメインスレッドとは別のスレッドで実行される スムーズに動作します。カスタム音声処理を有効にするには、 JavaScript、Web Audio API は ScriptProcessorNode を提案しました。 イベント ハンドラを使用して、メイン UI スレッドでユーザー スクリプトを呼び出す。
この設計には 2 つの問題があります。イベント処理が非同期であることです。
メインスレッドで実行されます。前者
レイテンシを引き起こします。後者では、メインスレッドに
さまざまな UI や DOM 関連のタスクで混雑していると、
「ジャンク」に「グリッチ」にできます。こうした根本的な設計上の欠陥により、
ScriptProcessorNode
は仕様で非推奨となり、
AudioWorklet に置き換えられました。
コンセプト
オーディオ ワークレットは、ユーザーが指定した JavaScript コードをすべて
やり取りできます。つまり、モジュールを使わずに、
やり取りできます。つまり、ユーザーが入力したスクリプト コードが実際に
オーディオ レンダリング スレッド(AudioWorkletGlobalScope
)で、
組み込みの AudioNodes
。これにより、レイテンシの増加と同期を
説明します。
登録とインスタンス化
オーディオ ワークレットの使用は、AudioWorkletProcessor
と
AudioWorkletNode
。これは、ScriptProcessorNode を使用するよりも
カスタム オーディオの低レベルの機能をデベロッパーに提供するために
あります。AudioWorkletProcessor
は実際のオーディオ プロセッサを表します。
記述され、AudioWorkletGlobalScope
にあります。
AudioWorkletNode
は AudioWorkletProcessor
と同等で、
メインスレッド内の他の AudioNodes
との接続を管理します。これは、
メインのグローバル スコープで公開され、通常の AudioNode
のように機能します。
こちらは 2 つのコード スニペットで、登録と インスタンス化できます。
// 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);
});
AudioWorkletNode
を作成するには、AudioContext を追加する必要があります。
プロセッサ名を文字列として格納します。プロセッサ定義は
新しいオーディオ ワークレット オブジェクトの addModule()
呼び出しによって読み込まれて登録されます。
音声ワークレットなどの Worklet API は、
安全なコンテキストを提供できるため、
それらを使用するページは HTTPS で配信する必要がありますが、http://localhost
は
安全とみなされます。
AudioWorkletNode
をサブクラス化して、
ワークレットで実行されているプロセッサを基盤とするカスタム ノードを作成します。
// 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);
AudioWorkletGlobalScope
の registerProcessor()
メソッドは、
登録するプロセッサの名前とクラス定義の文字列。
グローバル スコープでスクリプト コードの評価が完了すると、
AudioWorklet.addModule()
からの Promise が解決され、ユーザーに通知されます。
クラス定義がメインのグローバル スコープで使用できる状態であることを確認します。
カスタム音声パラメータ
AudioNode の便利な点の一つは schedulable パラメータです。
AudioParam
による自動化。AudioWorkletNode はこれらを使用して、
オーディオ レートで自動的に制御できる公開パラメータ。
ユーザー定義のオーディオ パラメータは AudioWorkletProcessor
で宣言できる
AudioParamDescriptor
のセットをセットアップしてクラス定義を行います。「
基になる WebAudio エンジンが、この情報を
AudioWorkletNode を作成してから、そのノードを
AudioParam
オブジェクトを適切にノードに追加します。
/* 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()
メソッド
実際の音声処理は、process()
コールバック メソッドで行われます。
AudioWorkletProcessor
。これはクラスのユーザーが実装する必要があります。
定義します。WebAudio エンジンはこの関数をアイソクロナス レイヤで呼び出し、
入力とパラメータをフィードし、出力をフェッチします。
/* 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;
}
さらに、process()
メソッドの戻り値を使用して、
AudioWorkletNode
の存続期間を制御して、デベロッパーが管理できるようにする
削減できますprocess()
メソッドマークから false
を返す
プロセッサが非アクティブになり、WebAudio
エンジンが
メソッドを呼び出します。プロセッサを存続させるため、メソッドは true
を返す必要があります。
それ以外の場合、ノードとプロセッサのペアがシステムによってガベージ コレクションされます
あります。
MessagePort による双方向通信
カスタムの AudioWorkletNode
が、そうでないコントロールを公開しようとすることがあります。
AudioParam
にマッピング(文字列ベースの type
属性など)
カスタムフィルタの制御に使用できますこの目的とその後のために
AudioWorkletNode
と AudioWorkletProcessor
は以下を搭載しています:
MessagePort
: 双方向通信に使用します。あらゆる種類のカスタムデータ
このチャネルで交換できます
MessagePort には、ノードと Pod の両方で .port
属性を使用してアクセスできます
提供します。ノードの port.postMessage()
メソッドは、メッセージを
関連付けられているプロセッサの port.onmessage
ハンドラで、逆にその逆になります。
/* 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
は Transferable に対応しているため、次のことを行えます。
WASM モジュールです開く
Audio Worklet システムの使い方は無限に広がっています。
チュートリアル: ゲインノードを作成する
このスライドは、Google Cloud 上に構築された
AudioWorkletNode
と AudioWorkletProcessor
。
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>
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);
オーディオ ワークレット システムの基本について説明します。ライブデモを利用できます Chrome WebAudio チームの GitHub リポジトリで確認できます。
機能の移行: 試験運用版から安定版へ
Chrome 66 以降では、オーディオ ワークレットがデフォルトで有効になっています。Chrome 64 と 65 では、この機能は試験運用版のフラグを使用していました。