postMessage を使用して 1 つの AudioWorkletProcessor から入力を抽出し、その入力を別の AudioWorkletProcessor に挿入しようとしています。
Float32Array を 2 番目の AudioWorkletProcessor プロセス メソッドに入れることはできましたが、RingBuffer が機能していないようです。
process メソッド内のエラーまたは RingBuffer に関連するエラーを検出する方法がわかりません。
無音出力が表示され、コンソールにエラーはありません。
抽出された Float32Array を ring-buffer-worklet-processor 出力に渡す方法を知る必要があります。
前もって感謝します。
編集: ( outputChannelCount: [2] ) を ringBufferWorkletNode オプションに追加した後、出力でオーディオを取得し始めましたが、まったくクリアされませんでした。
const ringBufferWorkletNode = new AudioWorkletNode(
audioCtx,
"ring-buffer-worklet-processor",
{
outputChannelCount: [2],
processorOptions: {
kernelBufferSize: audioCtx.sampleRate,
channelCount: 2,
},
}
);
メインスレッド:
navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(async (stream) => {
const source = audioCtx.createMediaStreamSource(stream);
await audioCtx.audioWorklet.addModule("http://localhost:3003/lib/audio-processor.js");
await audioCtx.audioWorklet.addModule("http://localhost:3003/lib/ring-buffer-worklet-
processor.js");
const voiceNode = new AudioWorkletNode(audioCtx, "audio-processor");
const ringBufferWorkletNode = new AudioWorkletNode(audioCtx, "ring-buffer-worklet-processor",{
// EDIT: added outputChannelCount
outputChannelCount: [2],
processorOptions: {
kernelBufferSize: audioCtx.sampleRate / 2, // 48000/2
channelCount: 2,
},
}
);
voiceNode.port.onmessage = (e) => {
ringBufferWorkletNode.port.postMessage(e.data);
};
ringBufferWorkletNode.port.onmessage = (e) => {
console.log(e.data);
};
source.connect(voiceNode);
ringBufferWorkletNode.connect(audioCtx.destination);
}
audio-processor.js
class AudioProcessor extends AudioWorkletProcessor {
constructor(...args) {
super(...args);
}
process(inputList, outputList, parameters) {
this.port.postMessage(inputList[0]);
return true;
}
}
registerProcessor("audio-processor", AudioProcessor);
ring-buffer-worklet-processor.js
import Module from "./variable-buffer-kernel.wasmmodule.js";
import { HeapAudioBuffer, RingBuffer } from "./wasm-audio-helper.js";
class RingBufferWorkletProcessor extends AudioWorkletProcessor {
static get parameterDescriptors() {
return [
{
name: "input",
defaultValue: null,
},
];
}
constructor(options) {
super();
this._kernelBufferSize = options.processorOptions.kernelBufferSize;
this._channelCount = options.processorOptions.channelCount;
// RingBuffers for input and output.
this._inputRingBuffer = new RingBuffer(
this._kernelBufferSize,
this._channelCount
);
this._outputRingBuffer = new RingBuffer(
this._kernelBufferSize,
this._channelCount
);
// For WASM memory, also for input and output.
this._heapInputBuffer = new HeapAudioBuffer(
Module,
this._kernelBufferSize,
this._channelCount
);
this._heapOutputBuffer = new HeapAudioBuffer(
Module,
this._kernelBufferSize,
this._channelCount
);
// WASM audio processing kernel.
this._kernel = new Module.VariableBufferKernel(this._kernelBufferSize);
this.inputData = null;
this.port.onmessage = this.onmessage.bind(this);
}
onmessage = (e) => {
const { data } = e;
if (data) {
this.inputData = data;
} else {
this.inputData = null;
}
};
process(inputs, outputs, parameters) {
let output = outputs[0];
let input = this.inputData;
// AudioWorkletProcessor always gets 128 frames in and 128 frames out. Here
// we push 128 frames into the ring buffer.
if (input) {
this.port.postMessage(input);
// I get : (2) [Float32Array(128), Float32Array(128)] in console full with numbers not 0s
this._inputRingBuffer.push(input);
// Process only if we have enough frames for the kernel.
if (this._inputRingBuffer.framesAvailable >= this._kernelBufferSize) {
// Get the queued data from the input ring buffer.
this._inputRingBuffer.pull(this._heapInputBuffer.getChannelData());
// This WASM process function can be replaced with ScriptProcessor's
// |onaudioprocess| callback funciton. However, if the event handler
// touches DOM in the main scope, it needs to be translated with the
// async messaging via MessagePort.
this._kernel.process(
this._heapInputBuffer.getHeapAddress(),
this._heapOutputBuffer.getHeapAddress(),
this._channelCount
);
// Fill the output ring buffer with the processed data.
this._outputRingBuffer.push(this._heapOutputBuffer.getChannelData());
}
// Always pull 128 frames out. If the ring buffer does not have enough
// frames, the output will be silent.
this._outputRingBuffer.pull(output);
}
return true;
}
}
registerProcessor("ring-buffer-worklet-processor", RingBufferWorkletProcessor);
メインスレッドからの console.log サンプル:
ringBufferWorkletNode.port.onmessage = (e) => {
console.log(e.data);
};
(2) [Float32Array(128), Float32Array(128)]
0: Float32Array(128)
[0 … 99]
0: -0.00013565909466706216
1: -0.00004953467214363627
2: -0.00008576592517783865
3: -0.00005288537431624718
4: -0.000025271740014431998
5: -0.000051156635890947655
6: -0.00003429186836001463
7: -0.000021470399587997235
8: -0.000034319222322665155
9: -0.0000439783361798618
10: -0.000009586839041730855
11: -0.00003202698644599877
12: 0.000033984630135819316
13: -0.00002201009374402929
14: -0.00007097060733940452
15: 0.000004624932444130536
16: -0.00009633887384552509
17: 0.00000770429596741451
18: -0.00004159680975135416
19: -0.00012190178676974028
20: -0.00001845001861511264
21: -0.00008007502037798986
22: -0.00004237010216456838
23: -0.00001076792977983132
24: -0.00006972716801101342
25: -0.0000477194698760286
26: -0.000021934287360636517
27: -0.00009244760440196842
28: -0.000007403687050100416
29: 0.000007816993274900597
30: -0.00008117098332149908
31: -0.00003129038304905407
32: 0.00009489256626693532
33: 0.000023729033273411915
34: -0.000009693003448774107
35: -0.00003678350549307652
36: -0.00011439441732363775
37: -0.00003462867607595399
38: 0.000029057020583422855
39: -0.00003098553133895621
40: -0.00004036649261252023
41: -0.00001566937135066837
42: -0.00003948688390664756
43: -0.000021292273231665604
44: -0.000031062725611263886
45: -0.00006067131835152395
46: -0.00008801861258689314
47: -0.0000940829049795866
48: -0.000027806054276879877
49: 0.000005677926765201846
50: -0.00004410342808114365
51: -0.00005494384822668508
52: -0.00012077790597686544
53: -0.00005381474693422206
54: -0.00004889833144261502
55: -0.00006171152199385688
56: -0.00007169923628680408
57: -0.000027956590201938525
58: -0.0000925964122870937
59: -0.00008822995005175471
60: -0.00011014055053237826
61: -0.00009332459740107879
62: -0.00007393134728772566
63: -0.00009183597285300493
64: -0.000051114031521137804
65: -0.00009899734141072258
66: -0.00001619849535927642
67: -0.00006849400961073115
68: -0.00007494576129829511
69: -0.00004512929081101902
70: -0.00007846889639040455
71: -0.0000887925925781019
72: -0.00011394681496312842
73: -0.0000661616213619709
74: -0.00006388152542058378
75: -0.000028652870241785422
76: -0.000049569716793484986
77: -0.000008633718607597984
78: -0.00003698172440635972
79: -0.00007338733121287078
80: -0.00004050061761518009
81: -0.00011863364488817751
82: -0.00005003352271160111
83: 0.00009503970795776695
84: -0.000020715609934995882
85: -0.000040291022742167115
86: -0.00006244835822144523
87: -0.00013285929162520915
88: -0.00009266978304367512
89: -0.00015499485016334802
90: 0.000009959074304788373
91: -0.00002722918361541815
92: -0.000045168246288085356
93: 0.00005641198004013859
94: -6.97990401477e-7
95: -0.00008256734145106748
96: -0.00011380571231711656
97: -0.00010966734407702461
98: -0.00010636053775670007
99: -0.00009042541933013126
[100 … 127]
buffer:
ArrayBuffer(512)
byteLength: 512
byteOffset: 0
length: 128
Symbol(Symbol.toStringTag): (...)
[[Prototype]]: TypedArray
1: Float32Array(128)
[0 … 99]
[100 … 127]
buffer:
ArrayBuffer(512)
byteLength: 512
byteOffset: 0
length: 128
Symbol(Symbol.toStringTag): (...)
[[Prototype]]: TypedArray
length: 2
[[Prototype]]: Array(0)
これは私がフォローしていた GitHub です: https://github.com/GoogleChromeLabs/web-audio-samples/tree/main/audio-worklet/design-pattern/wasm-ring-buffer