YM2612Synth AudioWorklet Demo
This example uses YM2612Synth with
YM2612WorkletTransport.
YM2612 register writes are sent to an AudioWorklet, where the
YM2612 WASM instance generates PCM continuously.
Minimal Usage
const audioContext = new AudioContext();
await audioContext.audioWorklet.addModule(
"../js/ym2612-worklet.js"
);
const wasmResponse = await fetch(
"../generated/ym2612_wasm.wasm"
);
const wasmBinary =
await wasmResponse.arrayBuffer();
const node = new AudioWorkletNode(
audioContext,
"ym2612-processor",
{
numberOfInputs: 0,
numberOfOutputs: 1,
outputChannelCount: [2],
}
);
node.connect(audioContext.destination);
const ready = waitForWorkletReady(node);
node.port.postMessage(
{
type: "initialize",
wasmBinary,
},
[wasmBinary]
);
await ready;
const transport =
new YM2612WorkletTransport(node);
const synth =
new YM2612Synth({ transport });
synth.setOperator(0, 3, {
dt: 0,
multi: 1,
tl: 8,
ar: 22,
d1r: 6,
d2r: 3,
sl: 3,
rr: 8,
});
synth.setAlgo(0, 7, 0);
synth.setPan(0, true, true);
synth.noteOn(0, 4, 553);
synth.noteOff(0);
Ready.
Data Flow
Main Thread
YM2612Synth
|
v
YM2612WorkletTransport
|
v
postMessage(register write)
-------------------------------
Main Thread / AudioWorklet
-------------------------------
AudioWorklet
|
v
YM2612Processor
|
v
Ym2612
|
v
YM2612 / ymfm WASM
|
v
generateStereo()
|
v
AudioWorklet output
|
v
AudioContext.destination
Why Transfer the WASM Binary?
The Emscripten-generated module cannot load the
.wasm file normally from the AudioWorklet environment.
The main thread therefore loads the binary with fetch()
and transfers its ArrayBuffer to the AudioWorklet.
fetch("ym2612_wasm.wasm")
|
v
ArrayBuffer
|
v
postMessage(..., [wasmBinary])
|
v
AudioWorklet
|
v
createYm2612(
ym2612ModuleFactory,
{ wasmBinary }
)
Direct vs AudioWorklet
Direct
YM2612Synth
|
v
YM2612DirectTransport
|
v
Ym2612
|
v
generateStereo() on Main Thread
AudioWorklet
YM2612Synth
|
v
YM2612WorkletTransport
|
v
postMessage()
|
v
Ym2612 inside AudioWorklet
|
v
generateStereo() in process()