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.

Source: docs/js/ym2612synth.js | docs/js/ym2612-worklet.js | docs/js/ym2612.js docs/info/ym2612synth_audioworklet.html

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