npm.io
0.70.0 • Published 1 week ago

supersonic-scsynth

Licence
MIT
Version
0.70.0
Deps
1
Size
467 kB
Vulns
0
Weekly
0
Stars
206

SuperSonic 0.70.0

SuperCollider's scsynth in the browser as an AudioWorklet.

Auto-generated from project docs — see GitHub for full documentation.

Table of Contents


Quick Start

You've installed SuperSonic - now let's make some sound.

We'll create a simple page with two buttons: one to boot the audio engine, and one to trigger a synth.

<button id="boot-btn">boot</button>
<button id="trig-btn">trigger</button>
import { SuperSonic } from "https://unpkg.com/supersonic-scsynth@latest";

const supersonic = new SuperSonic({
  baseURL: "https://unpkg.com/supersonic-scsynth@latest/dist/",
  synthdefBaseURL: "https://unpkg.com/supersonic-scsynth-synthdefs@latest/synthdefs/",
});

const bootBtn = document.getElementById("boot-btn");
const trigBtn = document.getElementById("trig-btn");

bootBtn.onclick = async () => {
  await supersonic.init();
  await supersonic.loadSynthDef("sonic-pi-prophet");
};

trigBtn.onclick = () => {
  supersonic.send("/s_new", "sonic-pi-prophet", -1, 0, 0, "note", 28, "release", 8, "cutoff", 70);
};

Let's break down what's happening here.

User Interaction

Web browsers have an autoplay policy that prevents websites from making sound without user consent. Audio can only start after a user interaction like a click, tap, or keypress.

This is why we use a boot button - calling init() from a button handler satisfies the browser's autoplay policy and allows audio to begin.

Creating a SuperSonic Instance

const supersonic = new SuperSonic({
  baseURL: "https://unpkg.com/supersonic-scsynth@latest/dist/",
  synthdefBaseURL: "https://unpkg.com/supersonic-scsynth-synthdefs@latest/synthdefs/",
});

This creates a new SuperSonic instance configured to load assets from CDN. The baseURL tells SuperSonic where to find the WASM engine and workers. The synthdefBaseURL tells it where to find synthdef files when you call loadSynthDef(). The instance doesn't start the audio engine yet - it just sets up the configuration. You can pass additional options to configure transport mode, debug output, and scsynth engine settings (see API Reference).

Booting the Engine

await supersonic.init();

Calling init() boots the scsynth audio engine. Behind the scenes this:

  1. Creates an AudioContext and AudioWorklet
  2. Loads the WebAssembly module containing scsynth
  3. Starts scsynth running in a dedicated high-priority audio thread

This is an async operation - the await ensures we don't proceed until the engine is ready.

Loading a Synth Definition

await supersonic.loadSynthDef("sonic-pi-prophet");

Before you can play a synth, you need to send its design to scsynth. This design is called a synth definition (or "synthdef") and is a recipe that describes a synth's audio graph - what oscillators, filters, and effects it uses and how they're connected.

SuperSonic comes with 127 ready-to-use synthdefs from Sonic Pi. Here we're loading sonic-pi-prophet, a warm polyphonic synth inspired by the Prophet-5.

Note: you can also use SuperCollider's Desktop app to design your own synthdefs and directly import them live at runtime into your SuperSonic session.

Triggering a Synth

supersonic.send("/s_new", "sonic-pi-prophet", -1, 0, 0, "note", 28, "release", 8, "cutoff", 70);

Now for the fun part - making sound! The send() method sends OSC (Open Sound Control) messages to scsynth. The /s_new command creates a new synth instance.

The arguments are:

synthdef name "sonic-pi-prophet" Which synth to create
node ID -1 Let scsynth assign an ID automatically
add action 0 Add to the head of the target group
target 0 The root group
params... "note", 28, ... Name/value pairs for synth parameters

The synth parameters control the sound. Here we set note to 28 (a low E), release to 8 seconds, and cutoff to 70 (filter brightness). Each synthdef has its own parameters - see the synthdef documentation for available options.

We used -1 for the node ID here to let scsynth pick one for us. That's fine for fire-and-forget sounds, but if you need to control a synth after creating it - change its parameters, stop it, query it - you need to know its ID. That's where nextNodeId() comes in:

const id = supersonic.nextNodeId();
supersonic.send("/s_new", "sonic-pi-prophet", id, 0, 0, "note", 28, "release", 8, "cutoff", 70);

// Later — change the cutoff while it's playing
supersonic.send("/n_set", id, "cutoff", 100);

nextNodeId() is thread-safe - if you have multiple Web Workers sending OSC (see the Workers Guide), each one can allocate IDs independently, guaranteed unique with no clashes.

Working Example

See example/simple.html for a complete working example you can run locally, or example/simple_metrics.html for the same example with a live metrics dashboard.

Adding a Metrics Dashboard

SuperSonic includes a web component that renders a full metrics dashboard from the schema:

<link rel="stylesheet" href="https://unpkg.com/supersonic-scsynth@latest/dist/metrics-dark.css" />
<script type="module" src="https://unpkg.com/supersonic-scsynth@latest/dist/metrics_component.js"></script>

<supersonic-metrics id="metrics"></supersonic-metrics>

Connect it after boot to start live updates:

bootBtn.onclick = async () => {
  await supersonic.init();
  await supersonic.loadSynthDef("sonic-pi-prophet");
  document.getElementById("metrics").connect(supersonic, { refreshRate: 10 });
};

See Metrics Component for theming, layout control, and customisation.


API Overview

Coordinates WASM, AudioWorklet, SharedArrayBuffer, and IO Workers to run scsynth with low latency inside a web page.

Core

Member Description
init() Initialise the engine.
shutdown() Shut down the engine.
destroy() Destroy the engine completely.
recover() Smart recovery — tries a quick resume first, falls back to full reload.
suspend() Suspend the AudioContext and stop the drift timer.
resume() Quick resume — calls purge to flush stale messages, resumes AudioContext, and resyncs timing.
reload() Full reload — destroys and recreates the worklet and WASM, then restores all previously loaded synthdefs and audio buffers.
reset() Shutdown and immediately re-initialise.
send() Send any OSC message.
sendOSC() Send pre-encoded OSC bytes to scsynth.
sync() Wait for scsynth to process all pending commands.
purge() Flush all pending scheduled OSC: clears the WASM BundleScheduler and the IN ring so nothing already in-flight will fire.

Asset Loading

Member Description
loadSynthDef() Load a SynthDef into scsynth.
loadSynthDefs() Load multiple SynthDefs by name in parallel.
loadSample() Load an audio sample into a scsynth buffer slot.
sampleInfo() Get sample metadata (including content hash) without allocating a buffer.

Events

Member Description
on() Subscribe to an event.
off() Unsubscribe from an event.
once() Subscribe to an event once.
removeAllListeners() Remove all listeners for an event, or all listeners entirely.

Node Tree

Member Description
getTree() Get the node tree in hierarchical format.
getRawTree() Get the node tree in flat format with linkage pointers.
getSnapshot() Get a diagnostic snapshot with metrics, node tree, and memory info.

Metrics

Member Description
getMetrics() Get current metrics as a named object.
getMetricsArray() Get metrics as a flat Uint32Array for zero-allocation reading.
getMetricsSchema() Get the metrics schema describing all available metrics.

Properties

Member Description
initialized Whether the engine has completed initialisation.
initializing Whether init is currently in progress.
audioContext The underlying AudioContext.
node AudioWorkletNode wrapper for custom audio routing.

Advanced

Member Description
getInfo() Get engine info: sample rate, memory layout, capabilities, and version.
createOscChannel() Create an OscChannel for direct worker-to-worklet communication.
startCapture() Start capturing audio output to a buffer.
stopCapture() Stop capturing and return the captured audio data.
getCaptureFrames() Get number of audio frames captured so far.
isCaptureEnabled() Check if audio capture is currently enabled.
getMaxCaptureDuration() Get maximum capture duration in seconds.
setClockOffset() Set clock offset for multi-system sync (e.g. Ableton Link, NTP server).

Advanced

Member Description
bufferConstants Buffer layout constants from the WASM build.
initTime NTP time (seconds since 1900) when the AudioContext started.
mode Active transport mode ('sab' or 'postMessage').
ringBufferBase Ring buffer base offset in SharedArrayBuffer.
sharedBuffer The SharedArrayBuffer (SAB mode) or null (postMessage mode).
superClock Session-timeline service: tempo, beat origin, transport, NTP "now." See SuperClock for the full API surface.
getEngineState() Returns the current engine lifecycle state.
getLoadedBuffers() Get info about all loaded audio buffers.
getSystemReport() Get a comprehensive system performance report.
isRunning() Returns true if the engine has finished booting and is ready to send and receive messages.
nextNodeId() Get the next unique node ID.
getRawTreeSchema() Get schema describing the raw flat node tree structure.
getTreeSchema() Get schema describing the hierarchical node tree structure.
OscChannel

OscChannel — unified dispatch for sending OSC to the AudioWorklet.

Obtain a channel via SuperSonic.createOscChannel on the main thread, then transfer it to a Web Worker for direct communication with the AudioWorklet.

Member Description
getCurrentNTP Set the NTP time source for classification (used in AudioWorklet context).
mode Transport mode this channel is using.
transferable Serializable config for transferring this channel to a worker via postMessage.
transferList Array of transferable objects (MessagePorts) for the postMessage transfer list.
close() Close the channel and release its ports.
getAndResetMetrics() Get and reset local metrics (for periodic reporting).
getMetrics() Get current metrics snapshot.
nextNodeId() Get the next unique node ID.
send() Send an OSC message: frames it onto the IN ring (SAB) or postMessages it to the worklet (PM).
sendDirect() Alias of send — kept for callers that used the explicit direct path.
fromTransferable() Reconstruct an OscChannel from data received via postMessage in a worker.
Example
// Main thread: create and transfer to worker
const channel = sonic.createOscChannel();
myWorker.postMessage(
  { channel: channel.transferable },
  channel.transferList,
);

// Inside worker: reconstruct and send
import { OscChannel } from 'supersonic-scsynth/osc-channel';
const channel = OscChannel.fromTransferable(event.data.channel);
channel.send(oscBytes);

Constructors
Constructor

new OscChannel(): OscChannel

Returns

OscChannel


Accessors
getCurrentNTP
Set Signature

set getCurrentNTP(fn): void

Set the NTP time source for classification (used in AudioWorklet context).

Parameters
Parameter Type
fn () => number
Returns

void

mode
Get Signature

get mode(): TransportMode

Transport mode this channel is using.

Returns

TransportMode

transferable
Get Signature

get transferable(): OscChannelTransferable

Serializable config for transferring this channel to a worker via postMessage.

Example
worker.postMessage({ ch: channel.transferable }, channel.transferList);
Returns

OscChannelTransferable

transferList
Get Signature

get transferList(): Transferable[]

Array of transferable objects (MessagePorts) for the postMessage transfer list.

Example
worker.postMessage({ ch: channel.transferable }, channel.transferList);
Returns

Transferable[]


Methods
close()

close(): void

Close the channel and release its ports.

Returns

void

getAndResetMetrics()

getAndResetMetrics(): OscChannelMetrics

Get and reset local metrics (for periodic reporting).

Returns

OscChannelMetrics

getMetrics()

getMetrics(): OscChannelMetrics

Get current metrics snapshot.

Returns

OscChannelMetrics

nextNodeId()

nextNodeId(): number

Get the next unique node ID.

Thread-safe — can be called concurrently from multiple workers and no two callers will ever receive the same ID. IDs start at 1000 (0 is the root group, 1 is the default group, 2–999 are reserved for manual use).

Returns

number

A unique node ID (>= 1000)

send()

send(oscData): boolean

Send an OSC message: frames it onto the IN ring (SAB) or postMessages it to the worklet (PM). Classification and scheduling happen on the audio thread (the engine's OscIngress + BundleScheduler) — the producer never classifies.

Parameters
Parameter Type Description
oscData Uint8Array Encoded OSC bytes
Returns

boolean

true if sent successfully

sendDirect()

sendDirect(oscData): boolean

Alias of send — kept for callers that used the explicit direct path.

Parameters
Parameter Type Description
oscData Uint8Array Encoded OSC bytes
Returns

boolean

true if sent successfully

fromTransferable()

static fromTransferable(data): OscChannel

Reconstruct an OscChannel from data received via postMessage in a worker.

Parameters
Parameter Type Description
data OscChannelTransferable The transferable config from channel.transferable
Returns

OscChannel

Example
// In a Web Worker:
self.onmessage = (e) => {
  const channel = OscChannel.fromTransferable(e.data.ch);
  channel.send(oscBytes);
};

Variables


Patterns

Scheduling with OSC Bundles
Full-Precision NTP Timestamps

When scheduling bundles, a plain JavaScript number loses sub-microsecond precision because IEEE 754 float64 only has 52 mantissa bits — not enough for NTP's full 64-bit range. Use a [seconds, fraction] uint32 pair for lossless timestamps:

// Float — easy but loses precision at large NTP values
const ntpTime = SuperSonic.osc.ntpNow();
SuperSonic.osc.encodeBundle(ntpTime + 0.5, [
  ["/s_new", "sonic-pi-beep", 1001, 0, 0],
]);

// Uint32 pair — full 64-bit precision, no float loss
SuperSonic.osc.encodeBundle([3913056000, 2147483648], [
  ["/s_new", "sonic-pi-beep", 1001, 0, 0],
  ["/n_set", 1001, "amp", 0.5],
]);

TimeTag formats accepted by encodeBundle():

Value Meaning
1, null, undefined Execute immediately
[seconds, fraction] NTP uint32 pair — preserves full 64-bit precision
Number (e.g. 3913056000.5) NTP float — seconds since 1900 (fractional part encoded)
Sending OSC from Workers

Avoiding the Main Thread

When you send OSC from the main thread, it has to compete with everything else happening there - DOM updates, event handlers, animations, your application logic. For simple cases this is fine, but if you're running a sequencer, processing MIDI input, or doing other timing-sensitive work, you can end up with jitter or UI stuttering.

Web Workers let you move work off the main thread. The challenge is getting OSC from a worker to the AudioWorklet efficiently. You could send messages back to the main thread and have it forward them - but that adds latency and defeats the purpose of using a worker in the first place.

SuperSonic solves this with OscChannel - a transferable object that gives workers a direct line to the AudioWorklet.

OscChannel

Normally you'd just call supersonic.send() - but workers are separate threads with no access to your main thread's objects. The supersonic instance doesn't exist in the worker's world.

You could have the worker send messages back to the main thread via postMessage, and have the main thread forward them to scsynth. But that puts the main thread back in the middle of every message - defeating the purpose of using a worker.

The solution is to create a direct channel from the worker to scsynth running in the AudioWorklet. SuperSonic gives you an OscChannel for exactly this.

You create an OscChannel with createOscChannel and then you need to transfer it to the worker.

Note: Transferring is critical because the core internal comms mechanisms cannot be copied to the worker with a standard postMessage, they must be explicitly transferred. This enables the worker to have full and unique ownership of the newly created OscChannel.

Here's how you create an OscChannel and transfer it to a worker:

// Main thread - create and transfer
const channel = supersonic.createOscChannel();
worker.postMessage(
  { type: "init", channel: channel.transferable },
  channel.transferList
);

The second argument to postMessage is optional - when provided, it lists which objects to transfer rather than copy.

In your worker, handle this as an init message and reconstruct the channel:

// Worker thread
import { OscChannel } from "supersonic-scsynth";

let channel = null;

self.onmessage = (event) => {
  if (event.data.type === "init") {
    channel = OscChannel.fromTransferable(event.data.channel);
  }
};

// Now you can send OSC directly to the AudioWorklet
channel.send(oscBytes);

Using a type field lets you handle different message types cleanly - for example init, start, stop (see the sequencer example below).

Multiple Workers

Each call to createOscChannel() returns a new channel with a unique source ID. An optional blocking parameter (SAB mode only) controls whether Atomics.wait() is used for guaranteed ring buffer delivery (default: true for workers where sourceId !== 0, false for main thread). Set to false for AudioWorklet use. This means you can have multiple workers all sending OSC independently - they don't need to coordinate with each other, and their messages can be traced back to their source in metrics and logs.

const sequencerChannel = supersonic.createOscChannel(); // sourceId: 1
const lfoChannel = supersonic.createOscChannel(); // sourceId: 2
const midiChannel = supersonic.createOscChannel(); // sourceId: 3

sequencerWorker.postMessage({ channel: sequencerChannel.transferable }, sequencerChannel.transferList);
lfoWorker.postMessage({ channel: lfoChannel.transferable }, lfoChannel.transferList);
midiWorker.postMessage({ channel: midiChannel.transferable }, midiChannel.transferList);

SAB vs PM Mode

OscChannel works identically in both modes - it detects the active mode and uses the appropriate communication method automatically. Your worker code doesn't need to know or care which mode is active.

See Communication Modes for details on choosing between SAB and postMessage modes.

Message Routing

OscChannel.send() automatically classifies messages and routes them appropriately:

Message Type Where It Goes Why
Regular messages (not bundles) Direct to AudioWorklet No timing requirements
Immediate bundles (timetag 0 or 1) Direct to AudioWorklet Execute now
Near-future bundles (within 500ms) Direct to AudioWorklet Close enough to buffer
Late bundles (in the past) Direct to AudioWorklet Execute immediately
Far-future bundles (>500ms ahead) Prescheduler Hold until closer to execution time

The 500ms threshold is configurable via bypassLookaheadMs in the SuperSonic constructor.

OscChannel API

Methods
Method Description
send(oscBytes) Send with automatic routing
sendDirect(oscBytes) Force direct send (bypass prescheduler)
classify(oscBytes) Get routing classification without sending
close() Release resources
Properties
Property Description
mode 'sab' or 'postMessage'
transferable Data for postMessage transfer
transferList Transferable objects array
getCurrentNTP (setter) Set NTP time source function for timestamp classification
Static Methods
Method Description
OscChannel.fromTransferable(data) Reconstruct channel in worker

Example: Sequencer Worker

Here's a worker that runs a simple step sequencer:

// sequencer-worker.js
import { OscChannel, osc } from "supersonic-scsynth";

let channel = null;
let running = false;
let step = 0;
let bpm = 120;

const pattern = [60, 62, 64, 65, 67, 65, 64, 62]; // Notes to play

self.onmessage = (event) => {
  const { type, data } = event.data;

  if (type === "init") {
    channel = OscChannel.fromTransferable(data.channel);
  } else if (type === "start") {
    running = true;
    step = 0;
    tick();
  } else if (type === "stop") {
    running = false;
  } else if (type === "bpm") {
    bpm = data.bpm;
  }
};

function tick() {
  if (!running || !channel) return;

  const note = pattern[step % pattern.length];
  const msg = osc.encodeMessage("/s_new", [
    "sonic-pi-beep", -1, 0, 0,
    "note", note,
    "amp", 0.5
  ]);
  channel.send(msg);

  step++;
  const msPerBeat = 60000 / bpm;
  setTimeout(tick, msPerBeat / 4); // 16th notes
}
Lifecycle & Recovery
Setup vs Ready

The setup event fires after init/recover completes, before ready. Async handlers are awaited. Use it for any persistent audio infrastructure that needs to exist on both initial boot and after recovery:

  • Groups — node tree organization
  • FX chains — reverb, filters, compressors
  • Bus routing — synths that read/write to audio buses
  • Persistent synths — always-on nodes like analyzers or mixers
supersonic.on("setup", async () => {
  // Create group structure
  supersonic.send("/g_new", 100, 0, 0); // synths group
  supersonic.send("/g_new", 101, 1, 0); // fx group (after synths)

  // Create FX chain
  supersonic.send("/s_new", "sonic-pi-fx_reverb", 2000, 0, 101,
    "in_bus", 20, "out_bus", 0, "mix", 0.3);

  await supersonic.sync();
});

Why setup instead of ready? When recover() falls through to a full reload(), WASM memory is destroyed and recreated, so all nodes are lost. The setup event lets you rebuild consistently on both initial boot and after recovery, regardless of transport mode. See Communication Modes for more on SAB vs postMessage.

Tab Visibility & Recovery

Use visibilitychange to recover when the user switches back to your tab:

document.addEventListener("visibilitychange", async () => {
  if (!document.hidden) {
    await supersonic.recover();
  }
});
Resume vs Reload

resume() is fast but only works if the worklet is still alive — it calls purge() to flush stale scheduled messages, resumes the AudioContext, and resyncs timing. reload() is a full restart. When you don't know which is needed, use recover() — or handle it manually:

if (await supersonic.resume()) {
  console.log("Quick resume worked, nodes preserved");
} else {
  console.log("Worklet was killed, need full reload");
  await supersonic.reload();
}

Audio Routing
Connecting Microphone Input
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const micSource = audioContext.createMediaStreamSource(stream);

// Connect mic to SuperSonic input
micSource.connect(supersonic.node.input);

// Audio flows through scsynth's input buses (bus 2+ by default)
// Use In.ar(2) in a synthdef to read the mic signal
Connecting to an Analyser
const analyser = supersonic.audioContext.createAnalyser();

// Connect SuperSonic output to analyser (in addition to speakers)
supersonic.node.connect(analyser);

// Read frequency data
const data = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(data);

Samples
Loading from Different Sources
// By name (uses sampleBaseURL)
await supersonic.loadSample(0, "loop_amen.flac");

// By full path/URL
await supersonic.loadSample(0, "./custom/my-sample.wav");

// From user-selected file
const file = document.querySelector('input[type="file"]').files[0];
await supersonic.loadSample(0, file);

// From ArrayBuffer (e.g., fetched manually)
const response = await fetch("./audio/sample.wav");
const arrayBuffer = await response.arrayBuffer();
await supersonic.loadSample(0, arrayBuffer);

// Load partial sample (frames 1000-2000)
await supersonic.loadSample(0, "long-sample.flac", 1000, 1000);
Deduplication with sampleInfo()

Use sampleInfo() to get a SHA-256 content hash without allocating a buffer, then check before loading:

const info = await supersonic.sampleInfo("kick.wav");
console.log(info.duration, info.numChannels, info.sampleRate);

// Check for duplicates
const loaded = supersonic.getLoadedBuffers();
if (loaded.some(b => b.hash === info.hash)) {
  console.log("Already loaded, skipping");
} else {
  await supersonic.loadSample(nextBufnum, "kick.wav");
}


Constructor Options

Property Type Description Required
activityEvent? ActivityLineConfig Line length limits for activity events emitted to listeners.
audioContext? AudioContext Provide your own AudioContext instead of letting SuperSonic create one.
audioContextOptions? AudioContextOptions Options passed to new AudioContext(). Ignored if audioContext is provided.
autoConnect? boolean Auto-connect the AudioWorkletNode to the AudioContext destination. Default: true.
baseURL? string Convenience shorthand when all assets (WASM, workers, synthdefs, samples) are co-located. Yes*
bufferGrowIncrement? number Bytes to grow the buffer pool per growth event. Default: 32MB.
coreBaseURL? string Base URL for GPL assets: WASM and AudioWorklet (supersonic-scsynth-core package). Defaults to baseURL.
debug? boolean Enable all debug console logging. Default: false.
debugOscIn? boolean Log incoming OSC messages to console. Default: false.
debugOscOut? boolean Log outgoing OSC messages to console. Default: false.
debugScsynth? boolean Log scsynth debug output to console. Default: false.
fetchMaxRetries? number Max fetch retries when loading assets. Default: 3.
fetchRetryDelay? number Base delay between retries in ms (exponential backoff). Default: 1000.
maxBufferMemory? number Maximum buffer pool capacity in bytes. Pool grows on demand up to this limit. Default: 256MB.
mode? TransportMode Transport mode. - 'postMessage' (default) — works everywhere, no special headers needed - 'sab' — lowest latency, requires Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers See docs/MODES.md for a full comparison of communication modes.
sampleBaseURL? string Base URL for audio sample files (used by SuperSonic.loadSample).
scsynthOptions? ScsynthOptions Engine options passed to scsynth World_New().
snapshotIntervalMs? number How often to snapshot metrics/tree in postMessage mode (ms).
synthdefBaseURL? string Base URL for synthdef files (used by SuperSonic.loadSynthDef).
wasmBaseURL? string Base URL for WASM files. Defaults to coreBaseURL + 'wasm/'.
wasmUrl? string Full URL to the WASM binary. Overrides wasmBaseURL.
workerBaseURL? string Base URL for MIT worker scripts. Defaults to baseURL + 'workers/'.
workletUrl? string Full URL to the AudioWorklet script. Overrides coreBaseURL.

Required unless both coreBaseURL/workerBaseURL and wasmBaseURL are provided.


Server Options

Property Type Description Default Range
bufLength? 128 Audio buffer length — must be 128 (WebAudio API constraint). 128 128 (fixed)
loadGraphDefs? 0 | 1 Auto-load synthdefs from disk: 0 or 1. Default: 0. 0 0–1
maxGraphDefs? number Max synth definitions. Default: 1024. 1024 1+
maxNodes? number Max synthesis nodes — synths + groups. Default: 1024. 1024 1+
maxWireBufs? number Max wire buffers for internal UGen routing. Default: 64. 64 1+
memoryLocking? boolean Memory locking — not applicable in browser. Default: false. false
numAudioBusChannels? number Audio bus channels for routing between synths. Default: 128. 128 1+
numBuffers? number Max audio buffers (1–65535). Default: 1024. 1024 1–65535
numControlBusChannels? number Control bus channels for control-rate data. Default: 4096. 4096 1+
numInputBusChannels? number Hardware input channels. Default: 2 (stereo). 2 0+
numOutputBusChannels? number Hardware output channels (1–128). Default: 2 (stereo). 2 1–128
numRGens? number Random number generators per synth. Default: 64. 64 1+
preferredSampleRate? number Preferred sample rate. 0 = use AudioContext default (typically 48000). 0 0, 8000–384000
realTime? boolean Clock source. Always false in SuperSonic (externally clocked by AudioWorklet). false
realTimeMemorySize? number Real-time memory pool in KB for synthesis allocations. Default: 8192 (8MB). 8192 1+
verbosity? number Debug verbosity: 0 = quiet, 1 = errors, 2 = warnings, 3 = info, 4 = debug. 0 0–4

scsynth Command Quick Reference

Send commands using send() which auto-detects types:

supersonic.send("/s_new", "sonic-pi-beep", 1000, 0, 0, "note", 60);

Or directly send OSC bytes that you have already pre-encoded via sendOSC():

supersonic.sendOSC(oscBytes);
Command Description
Top-Level
/notify Register for node event notifications
/status Query server status (UGens, synths, CPU)
/sync Wait for async commands to complete
/version Query server version info
/rtMemoryStatus Query realtime memory usage
Synth Definitions
/d_recv Load a synthdef from binary data
/d_free Free loaded synthdefs by name
Nodes
/n_free Delete nodes
/n_run Turn nodes on or off
/n_set Set node control values
/n_setn Set sequential control values
/n_fill Fill controls with a single value
/n_map Map controls to control buses
/n_mapn Map sequential controls to control buses
/n_mapa Map controls to audio buses
/n_mapan Map sequential controls to audio buses
/n_before Move node before another
/n_after Move node after another
/n_query Query node info
/n_trace Debug trace node execution
/n_order Reorder nodes within a group
Synths
/s_new Create a new synth
/s_get Get synth control values
/s_getn Get sequential synth control values
/s_noid Remove synth ID tracking
Groups
/g_new Create a new group
/p_new Create a parallel group
/g_head Move node to head of group
/g_tail Move node to tail of group
/g_freeAll Free all nodes in group
/g_deepFree Recursively free all synths in group
/g_dumpTree Print group tree (debug)
/g_queryTree Query group tree structure
Buffers
/b_alloc Allocate an empty buffer
/b_allocRead Allocate buffer and load audio file
/b_allocReadChannel Allocate buffer and load specific channels
/b_free Free a buffer
/b_zero Zero buffer contents
/b_set Set individual samples
/b_setn Set sequential samples
/b_fill Fill samples with a value
/b_gen Generate buffer contents (sine, cheby, etc.)
/b_query Query buffer info
/b_get Get sample values
/b_getn Get sequential sample values
Control Buses
/c_set Set control bus values
/c_setn Set sequential bus values
/c_fill Fill buses with a value
/c_get Get bus values
/c_getn Get sequential bus values
SuperSonic Extensions
/b_allocFile Load audio from inline file data (SuperSonic only)

Parameter Types
Notation Type Description
int Integer 32-bit signed integer
float Float 32-bit floating point
double Double 64-bit floating point
string String Null-terminated string
bytes Blob Binary data (byte array)
Repetition

N × indicates the parameter can be repeated N times. For example:

// /n_free takes N node IDs
supersonic.send("/n_free", 1000, 1001, 1002);
Node IDs
  • Use -1 to have the server auto-generate a unique node ID
  • Node ID 0 is the root group (always exists)
  • Positive integers are user-assigned IDs
Add Actions

Used when creating or moving nodes:

Value Action Description
0 head Add to head of target group
1 tail Add to tail of target group
2 before Add before target node
3 after Add after target node
4 replace Replace target node
Control Values

Controls can be set by index (integer) or name (string). Values can be:

  • float or int - Direct value
  • "cN" - Map to control bus N (e.g., "c0")
  • "aN" - Map to audio bus N (e.g., "a0")
Asynchronous Commands

Commands marked Async execute on a background thread. They reply with /done on success or /fail on error. Use /sync to wait for all async commands to complete.


These commands don't work in SuperSonic due to browser/AudioWorklet constraints.

For a complete guide to all differences between SuperSonic and scsynth—including unsupported UGens, architectural differences, and error handling—see SCSYNTH_DIFFERENCES.md.

Scheduling and Debug Commands
Command Reason
/clearSched Use cancelAll() or the fine-grained cancelTag(), cancelSession(), cancelSessionTag() methods instead
/error SuperSonic always enables error notifications so you never miss a /fail message
/quit Use destroy() to shut down the SuperSonic instance
Plugin Commands
Command Status
/cmd No commands currently registered
/u_cmd No UGens currently define commands

These commands allow plugins to register custom functionality beyond the standard OSC API. None of the built-in UGens use them, but the mechanism exists if compelling use cases emerge. If you have a need for custom plugin commands, open an issue describing your use case.

Filesystem Commands

No filesystem in browser/WASM, so file-based commands aren't available:

Command Alternative
/d_load loadSynthDef() or /d_recv with bytes
/d_loadDir loadSynthDefs()
/b_read loadSample()
/b_readChannel loadSample()
/b_write Not available
/b_close Not available
Buffer Commands
Command Reason
/b_setSampleRate Not implemented - WebAudio automatically resamples buffers to context sample rate

Use the JavaScript API to load assets - it fetches via HTTP and sends the data to scsynth:

await supersonic.loadSynthDef("sonic-pi-beep");
await supersonic.loadSample(0, "loop_amen.flac");

For full details on every command (parameters, replies, examples), see the scsynth Command Reference.


Full Method Reference

Methods
createOscChannel()

createOscChannel(options?): OscChannel

Create an OscChannel for direct worker-to-worklet communication.

The returned channel can be transferred to a Web Worker, allowing that worker to send OSC directly to the AudioWorklet without going through the main thread. Works in both SAB and postMessage modes.

The blocking option defaults to true for worker channels (sourceId !== 0) and false for main thread. Set to false for AudioWorkletProcessor use. In postMessage mode this has no effect.

For AudioWorkletProcessor use, import from 'supersonic-scsynth/osc-channel' which avoids DOM APIs unavailable in the worklet scope.

See docs/WORKERS.md for the full workers guide.

Parameters
Parameter Type Description
options? { blocking?: boolean; sourceId?: number; } Channel options
options.blocking? boolean Whether sends block until the worklet reads the message
options.sourceId? number Numeric source ID (0 = main thread, 1+ = workers)
Returns

OscChannel

Example
const channel = sonic.createOscChannel();
myWorker.postMessage(
  { channel: channel.transferable },
  channel.transferList,
);
destroy()

destroy(): Promise<void>

Destroy the engine completely. The instance cannot be re-used.

Calls shutdown then clears the WASM cache and all event listeners. Emits 'destroy'.

Returns

Promise<void>

getCaptureFrames()

getCaptureFrames(): number

Get number of audio frames captured so far.

Returns

number

getEngineState()

getEngineState(): "running" | "stopped" | "booting"

Returns the current engine lifecycle state.

One of:

  • 'stopped' — before init() or after shutdown()/destroy().
  • 'booting' — while init() is in progress.
  • 'running' — after init() resolves and before any teardown.

Mirrors the C++ SupersonicEngine::engineState() accessor. The C++ enum also has 'restarting' and 'error' states that the web runtime does not currently distinguish — recover() and resume() do not surface a 'restarting' state from JS.

Returns

"running" | "stopped" | "booting"

getInfo()

getInfo(): SuperSonicInfo

Get engine info: sample rate, memory layout, capabilities, and version.

Returns

SuperSonicInfo

Example
const info = sonic.getInfo();
console.log(`Sample rate: ${info.sampleRate}Hz`);
console.log(`Boot time: ${info.bootTimeMs}ms`);
console.log(`Version: ${info.version}`);
getLoadedBuffers()

getLoadedBuffers(): LoadedBufferInfo[]

Get info about all loaded audio buffers.

Returns

LoadedBufferInfo[]

Example
const buffers = sonic.getLoadedBuffers();
for (const buf of buffers) {
  console.log(`Buffer ${buf.bufnum}: ${buf.duration.toFixed(1)}s, ${buf.source}`);
}
getMaxCaptureDuration()

getMaxCaptureDuration(): number

Get maximum capture duration in seconds.

Returns

number

getMetrics()

getMetrics(): SuperSonicMetrics

Get current metrics as a named object.

This is a cheap local memory read in both SAB and postMessage modes — no IPC or copying. Safe to call from requestAnimationFrame.

See docs/METRICS.md for the full metrics guide.

Returns

SuperSonicMetrics

Example
const m = sonic.getMetrics();
console.log(`Messages sent: ${m.oscOutMessagesSent}`);
console.log(`Scheduler depth: ${m.scsynthSchedulerDepth}`);
getMetricsArray()

getMetricsArray(): Uint32Array

Get metrics as a flat Uint32Array for zero-allocation reading.

Returns the same array reference every call — values are updated in-place. Use SuperSonic.getMetricsSchema for offset mappings.

Returns

Uint32Array

Example
const schema = SuperSonic.getMetricsSchema();
const arr = sonic.getMetricsArray();
const sent = arr[schema.metrics.oscOutMessagesSent.offset];
getRawTree()

getRawTree(): RawTree

Get the node tree in flat format with linkage pointers.

More efficient than getTree for serialization or custom rendering.

Returns

RawTree

getSnapshot()

getSnapshot(): Snapshot

Get a diagnostic snapshot with metrics, node tree, and memory info.

Useful for capturing state for bug reports or debugging timing issues.

Returns

Snapshot

getSystemReport()

getSystemReport(): SystemReport

Get a comprehensive system performance report.

Includes hardware info, audio configuration, Chrome playbackStats (if available), a cross-browser audio health percentage, and a human-readable health assessment. Useful for diagnosing audio crackling on constrained hardware.

Returns

SystemReport

Example
const report = sonic.getSystemReport();
console.log(report.health.summary);
if (report.health.audioHealthPct < 95) {
  console.warn('Audio thread struggling:', report.health.issues);
}
getTree()

getTree(): Tree

Get the node tree in hierarchical format.

The mirror has a default capacity of 1024 nodes. If exceeded, droppedCount will be non-zero and the tree may be incomplete, but audio continues normally.

Returns

Tree

Example
const tree = sonic.getTree();
function printTree(node, indent = 0) {
  const prefix = '  '.repeat(indent);
  const label = node.type === 'synth' ? node.defName : 'group';
  console.log(`${prefix}[${node.id}] ${label}`);
  for (const child of node.children) printTree(child, indent + 1);
}
printTree(tree.root);
init()

init(): Promise<void>

Initialise the engine.

Loads the WASM binary, creates the AudioContext and AudioWorklet, starts IO workers, and syncs timing. Emits 'setup' then 'ready' when complete.

Safe to call multiple times — subsequent calls are no-ops. Must be called from a user gesture (click/tap) due to browser autoplay policies.

Returns

Promise<void>

Throws

If required browser features are missing or WASM fails to load.

Example
await sonic.init();
// Engine is now ready to send/receive OSC
isCaptureEnabled()

isCaptureEnabled(): boolean

Check if audio capture is currently enabled.

Returns

boolean

isRunning()

isRunning(): boolean

Returns true if the engine has finished booting and is ready to send and receive messages.

Mirrors the C++ SupersonicEngine::isRunning() accessor; returns the same value as the existing initialized getter, exposed as a method to match the C++ API shape.

Returns

boolean

loadSample()

loadSample(bufnum, source, startFrame?, numFrames?): Promise<LoadSampleResult>

Load an audio sample into a scsynth buffer slot.

Decodes the audio file (WAV, AIFF, etc.) and copies the samples into the WASM buffer pool. The buffer is then available for use with PlayBuf, BufRd, etc.

Parameters
Parameter Type Description
bufnum number Buffer slot number (0 to numBuffers-1)
source string | ArrayBuffer | ArrayBufferView<ArrayBufferLike> | Blob Sample path/URL, raw bytes, or File/Blob
startFrame? number First frame to read (default: 0)
numFrames? number Number of frames to read (default: 0 = all)
Returns

Promise<LoadSampleResult>

Buffer info including frame count, channels, and sample rate

Example
// Load from URL:
await sonic.loadSample(0, '/samples/kick.wav');

// Use in a synth:
await sonic.send('/s_new', 'sampler', 1001, 0, 1, 'bufnum', 0);
loadSynthDef()

loadSynthDef(source): Promise<LoadSynthDefResult>

Load a SynthDef into scsynth.

Accepts multiple source types:

  • Name string — fetched from synthdefBaseURL (e.g. 'beep'synthdefBaseURL/beep.scsyndef)
  • Path/URL string — fetched directly (must contain / or ://)
  • ArrayBuffer / Uint8Array — raw synthdef bytes
  • File / Blob — e.g. from a file input
Parameters
Parameter Type Description
source string | ArrayBuffer | ArrayBufferView<ArrayBufferLike> | Blob SynthDef name, path/URL, raw bytes, or File/Blob
Returns

Promise<LoadSynthDefResult>

The extracted name and byte size

Throws

If the source type is invalid or the synthdef can't be parsed

Example
// By name (uses synthdefBaseURL):
await sonic.loadSynthDef('beep');

// By URL:
await sonic.loadSynthDef('/assets/synthdefs/pad.scsyndef');

// From raw bytes:
const bytes = await fetch('/my-synth.scsyndef').then(r => r.arrayBuffer());
await sonic.loadSynthDef(bytes);

// From file input:
fileInput.onchange = async (e) => {
  await sonic.loadSynthDef(e.target.files[0]);
};
loadSynthDefs()

loadSynthDefs(names): Promise<Record<string, { error?: string; success: boolean; }>>

Load multiple SynthDefs by name in parallel.

Parameters
Parameter Type Description
names string[] Array of synthdef names
Returns

Promise<Record<string, { error?: string; success: boolean; }>>

Object mapping each name to { success: true } or { success: false, error: string }

Example
const results = await sonic.loadSynthDefs(['beep', 'pad', 'kick']);
if (!results.kick.success) console.error(results.kick.error);
nextNodeId()

nextNodeId(): number

Get the next unique node ID.

Thread-safe — can be called concurrently from multiple workers and no two callers will ever receive the same ID. IDs start at 1000 (0 is the root group, 1 is the default group, 2–999 are reserved for manual use).

Also available on OscChannel for use in Web Workers.

Returns

number

A unique node ID (>= 1000)

Example
const id = sonic.nextNodeId();
sonic.send('/s_new', 'beep', id, 0, 1, 'freq', 440);
off()

off<E>(event, callback): this

Unsubscribe from an event.

Type Parameters
Type Parameter
E extends keyof SuperSonicEventMap
Parameters
Parameter Type Description
event E Event name
callback SuperSonicEventMap[E] The same function reference passed to on
Returns

this

on()

on<E>(event, callback): () => void

Subscribe to an event.

Type Parameters
Type Parameter
E extends keyof SuperSonicEventMap
Parameters
Parameter Type Description
event E Event name
callback SuperSonicEventMap[E] Handler function (type-checked per event)
Returns

Unsubscribe function — call it to remove the listener

() => void

Example
const unsub = sonic.on('in', (msg) => {
  console.log(msg[0], msg.slice(1));
});

// Later:
unsub();
once()

once<E>(event, callback): () => void

Subscribe to an event once. The handler is automatically removed after the first call. Returns an unsubscribe function (matching on).

Type Parameters
Type Parameter
E extends keyof SuperSonicEventMap
Parameters
Parameter Type Description
event E Event name
callback SuperSonicEventMap[E] Handler function
Returns

Unsubscribe function — call it to remove the listener before it fires

() => void

purge()

purge(): Promise<void>

Flush all pending scheduled OSC: clears the WASM BundleScheduler and the IN ring so nothing already in-flight will fire. Resolves when confirmed.

Returns

Promise<void>

recover()

recover(): Promise<boolean>

Smart recovery — tries a quick resume first, falls back to full reload.

Use when you're not sure if the worklet is still alive (e.g. returning from a long background period).

Returns

Promise<boolean>

true if audio is running after recovery

Example
document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'visible') sonic.recover();
});
reload()

reload(): Promise<boolean>

Full reload — destroys and recreates the worklet and WASM, then restores all previously loaded synthdefs and audio buffers.

Emits 'setup' so you can rebuild groups, FX chains, and bus routing. Use when the worklet was killed (e.g. long background, browser reclaimed memory).

Returns

Promise<boolean>

true if reload succeeded

removeAllListeners()

removeAllListeners(event?): this

Remove all listeners for an event, or all listeners entirely.

Parameters
Parameter Type Description
event? keyof SuperSonicEventMap Event name, or omit to remove everything
Returns

this


Event Types
Event Description
audiocontext:interrupted AudioContext was interrupted (iOS-specific). Another app or system event took audio focus. Similar to suspended but triggered externally.
audiocontext:resumed AudioContext resumed to 'running' state.
audiocontext:statechange AudioContext state changed. State is one of: 'running', 'suspended', 'closed', or 'interrupted'.
audiocontext:suspended AudioContext was suspended (e.g. tab backgrounded, autoplay policy, iOS audio interruption). Show a restart UI and call recover() when the user interacts.
buffer:pool:grown Buffer pool grew on demand. Fired when the initial pool was exhausted and a new segment was added.
debug Debug text output from scsynth (e.g. synthdef compilation messages). Includes NTP timestamp and sequence number.
destroy Engine has been destroyed. Only fired by destroy(), not by shutdown() or reset(). Last chance to clean up before all listeners are cleared.
error Error from any component (worklet, transport, workers).
in Decoded OSC message received from scsynth. Messages are plain arrays: [address, ...args].
in:html Pre-formatted HTML representation of an incoming OSC message with CSS classes for colorization. Only emitted when listeners are attached.
in:osc Raw OSC bytes received from scsynth (before decoding). Includes NTP timestamps for timing analysis.
in:text Pre-formatted text representation of an incoming OSC message. Only emitted when listeners are attached or debug logging is enabled.
loading:complete An asset finished loading. Size is in bytes.
loading:start An asset started loading. Type is 'wasm', 'synthdef', or 'sample'.
out Decoded OSC message sent to scsynth. Messages are plain arrays: [address, ...args]. Mirrors the 'in' event for outgoing messages.
out:html Pre-formatted HTML representation of an outgoing OSC message with CSS classes for colorization. Only emitted when listeners are attached.
out:osc Raw OSC bytes sent to scsynth. Includes source worker ID, sequence number, and NTP timestamps.
out:text Pre-formatted text representation of an outgoing OSC message. Only emitted when listeners are attached or debug logging is enabled.
ready Fired when the engine is fully booted and ready to receive messages. Payload includes browser capabilities and boot timing.
reload:complete Full reload completed.
reload:start Full reload started (worklet and WASM will be recreated).
resumed Audio resumed after a suspend (AudioContext was re-started). Emitted after resume() succeeds.
setup Fired after init completes, before 'ready'. Use for setting up groups, FX chains, and bus routing. Can be async — init waits for all setup handlers to resolve. Also fires after recover() triggers a reload().
shutdown Engine is shutting down. Fired by shutdown(), reset(), and destroy().
reset()

reset(): Promise<void>

Shutdown and immediately re-initialise.

Equivalent to await sonic.shutdown(); await sonic.init();

Returns

Promise<void>

resume()

resume(): Promise<boolean>

Quick resume — calls purge to flush stale messages, resumes AudioContext, and resyncs timing.

Memory, node tree, and loaded synthdefs are preserved. Does not emit 'setup'. Use when you know the worklet is still running (e.g. tab was briefly backgrounded).

Returns

Promise<boolean>

true if the worklet is running after resume

sampleInfo()

sampleInfo(source, startFrame?, numFrames?): Promise<SampleInfo>

Get sample metadata (including content hash) without allocating a buffer.

Fetches, decodes, and hashes the audio, returning the same info that would appear in the loadSample result if the content were loaded. No buffer slot is consumed and no OSC is sent to scsynth.

Use this to inspect content or check for duplicates before loading.

Parameters
Parameter Type Description
source string | ArrayBuffer | ArrayBufferView<ArrayBufferLike> | Blob Sample path/URL, raw bytes, or File/Blob
startFrame? number First frame to read (default: 0)
numFrames? number Number of frames to read (default: 0 = all)
Returns

Promise<SampleInfo>

Sample metadata including hash, frame count, channels, sample rate, and duration

Example
const info = await sonic.sampleInfo('kick.wav');
console.log(info.hash, info.duration, info.numChannels);

const loaded = sonic.getLoadedBuffers();
if (loaded.some(b => b.hash === info.hash)) {
  console.log('Already loaded');
}
send()
Call Signature

send(address, ...args): never

Parameters
Parameter Type
address "/d_load"
...args OscArg[]
Returns

never

Deprecated

Use loadSynthDef() or send('/d_recv', bytes) instead. Filesystem access is not available in the browser.

Call Signature

send(address, ...args): never

Parameters
Parameter Type
address "/d_loadDir"
...args OscArg[]
Returns

never

Deprecated

Use loadSynthDef() or send('/d_recv', bytes) instead. Filesystem access is not available in the browser.

Call Signature

send(address, ...args): never

Parameters
Parameter Type
address "/b_read"
...args OscArg[]
Returns

never

Deprecated

Use loadSample() instead. Filesystem access is not available in the browser.

Call Signature

send(address, ...args): never

Parameters
Parameter Type
address "/b_readChannel"
...args OscArg[]
Returns

never

Deprecated

Use loadSample() instead. Filesystem access is not available in the browser.

Call Signature

send(address, ...args): never

Parameters
Parameter Type
address "/b_write"
...args OscArg[]
Returns

never

Deprecated

File writing is not available in the browser.

Call Signature

send(address, ...args): never

Parameters
Parameter Type
address "/b_close"
...args OscArg[]
Returns

never

Deprecated

File writing is not available in the browser.

Call Signature

send(address, ...args): never

Parameters
Parameter Type
address "/clearSched"
...args OscArg[]
Returns

never

Deprecated

Use purge() to clear the WASM BundleScheduler + IN ring.

Call Signature

send(address, ...args): never

Parameters
Parameter Type
address "/error"
...args OscArg[]
Returns

never

Deprecated

SuperSonic always enables error notifications so you never miss a /fail reply.

Call Signature

send(address, ...args): never

Parameters
Parameter Type
address "/quit"
...args OscArg[]
Returns

never

Deprecated

Use destroy() to shut down SuperSonic.

Call Signature

send(address): void

Query server status. Replies with /status.reply: unused, numUGens, numSynths, numGroups, numSynthDefs, avgCPU%, peakCPU%, nominalSampleRate, actualSampleRate.

Parameters
Parameter Type
address "/status"
Returns

void

Call Signature

send(address): void

Query server version. Replies with /version.reply: programName, majorVersion, minorVersion, patchVersion, gitBranch, commitHash.

Parameters
Parameter Type
address "/version"
Returns

void

Call Signature

send(address, flag, clientID?): void

Register (1) or unregister (0) for server notifications (/n_go, /n_end, /n_on, /n_off, /n_move). Replies with /done /notify clientID [maxLogins].

Parameters
Parameter Type
address "/notify"
flag 0 | 1
clientID? number
Returns

void

Call Signature

send(address, flag): void

Enable/disable OSC message dumping to debug output. 0=off, 1=parsed, 2=hex, 3=both.

Parameters
Parameter Type
address "/dumpOSC"
flag 0 | 1 | 2 | 3
Returns

void

Call Signature

send(address, syncID): void

Async. Wait for all prior async commands to complete. Replies with /synced syncID.

Parameters
Parameter Type
address "/sync"
syncID number
Returns

void

Call Signature

send(address): void

Query realtime memory usage. Replies with /rtMemoryStatus.reply: freeBytes, largestFreeBlockBytes.

Parameters
Parameter Type
address "/rtMemoryStatus"
Returns

void

Call Signature

send(address, bytes, completionMessage?): void

Async. Load a compiled synthdef from bytes. Optional completionMessage is an encoded OSC message executed after loading. Replies with /done /d_recv.

Parameters
Parameter Type
address "/d_recv"
bytes ArrayBuffer | Uint8Array<ArrayBufferLike>
completionMessage? ArrayBuffer | Uint8Array<ArrayBufferLike>
Returns

void

Call Signature

send(address, ...names): void

Free one or more loaded synthdefs by name.

Parameters
Parameter Type
address "/d_free"
...names [string, ...string[]]
Returns

void

Call Signature

send(address): void

Free all loaded synthdefs. Not in the official SC reference but supported by scsynth.

Parameters
Parameter Type
address "/d_freeAll"
Returns

void

Call Signature

send(address, defName, nodeID, addAction, targetID, ...controls): void

Create a new synth from a loaded synthdef. addAction: 0=head, 1=tail, 2=before, 3=after, 4=replace. Controls are alternating name/index and value pairs. Values can be numbers or bus mapping strings like "c0" (control bus 0) or "a0" (audio bus 0). Use nodeID=-1 for auto-assign.

Parameters
Parameter Type
address "/s_new"
defName string
nodeID number
addAction AddAction
targetID number
...controls (string | number)[]
Returns

void

Call Signature

send(address, nodeID, ...controls): void

Get synth control values. Controls can be indices or names. Replies with /n_set nodeID control value ....

Parameters
Parameter Type
address "/s_get"
nodeID number
...controls (string | number)[]
Returns

void

Call Signature

send(address, nodeID, control, count): void

Get sequential synth control values. Control can be an index or name. Replies with /n_setn nodeID control count values.... For multiple ranges, use the catch-all overload.

Parameters
Parameter Type
address "/s_getn"
nodeID number
control string | number
count number
Returns

void

Call Signature

send(address, ...nodeIDs): void

Release client-side synth ID tracking. Synths continue running but are reassigned to reserved negative IDs. Use when you no longer need to communicate with the synth and want to reuse the ID.

Parameters
Parameter Type
address "/s_noid"
...nodeIDs [number, ...number[]]
Returns

void

Call Signature

send(address, ...nodeIDs): void

Free (delete) one or more nodes.

Parameters
Parameter Type
address "/n_free"
...nodeIDs [number, ...number[]]
Returns

void

Call Signature

send(address, nodeID, ...controls): void

Set node control values. Controls are alternating name/index and value pairs. If the node is a group, sets the control on all nodes in the group.

Parameters
Parameter Type
address "/n_set"
nodeID number
...controls (string | number)[]
Returns

void

Call Signature

send(address, nodeID, control, count, ...values): void

Set sequential control values starting at the given control index/name. For multiple ranges, use the catch-all overload.

Parameters
Parameter Type
address "/n_setn"
nodeID number
control string | number
count number
...values number[]
Returns

void

Call Signature

send(address, nodeID, control, count, value): void

Fill sequential controls with a single value. For multiple ranges, use the catch-all overload.

Parameters
Parameter Type
address "/n_fill"
nodeID number
control string | number
count number
value number
Returns

void

Call Signature

send(address, ...pairs): void

Turn nodes on (1) or off (0). Args are repeating [nodeID, flag] pairs.

Parameters
Parameter Type
address "/n_run"
...pairs [number, 0 | 1, ...number[]]
Returns

void

Call Signature

send(address, ...pairs): void

Move nodeA to execute immediately before nodeB. Args are repeating [nodeA, nodeB] pairs.

Parameters
Parameter Type
address "/n_before"
...pairs [number, number, ...number[]]
Returns

void

Call Signature

send(address, ...pairs): void

Move nodeA to execute immediately after nodeB. Args are repeating [nodeA, nodeB] pairs.

Parameters
Parameter Type
address "/n_after"
...pairs [number, number, ...number[]]
Returns

void

Call Signature

send(address, addAction, targetID, ...nodeIDs): void

Reorder nodes within a group. addAction: 0=head, 1=tail, 2=before target, 3=after target. Does not support 4 (replace).

Parameters
Parameter Type
address "/n_order"
addAction 0 | 1 | 2 | 3
targetID number
...nodeIDs [number, ...number[]]
Returns

void

Call Signature

send(address, ...nodeIDs): void

Query node info. Replies with /n_info for each node: nodeID, parentGroupID, prevNodeID, nextNodeID, isGroup, [headNodeID, tailNodeID].

Parameters
Parameter Type
address "/n_query"
...nodeIDs [number, ...number[]]
Returns

void

Call Signature

send(address, ...nodeIDs): void

Print control values and calculation rates for each node to debug output. No reply message.

Parameters
Parameter Type
address "/n_trace"
...nodeIDs [number, ...number[]]
Returns

void

Call Signature

send(address, nodeID, ...mappings): void

Map controls to read from control buses. Mappings are repeating [control, busIndex] pairs. Set busIndex to -1 to unmap.

Parameters
Parameter Type
address "/n_map"
nodeID number
...mappings (string | number)[]
Returns

void

Call Signature

send(address, nodeID, ...mappings): void

Map a range of sequential controls to sequential control buses. Mappings are repeating [control, busIndex, count] triplets.

Parameters
Parameter Type
address "/n_mapn"
nodeID number
...mappings (string | number)[]
Returns

void

Call Signature

send(address, nodeID, ...mappings): void

Map controls to read from audio buses. Mappings are repeating [control, busIndex] pairs. Set busIndex to -1 to unmap.

Parameters
Parameter Type
address "/n_mapa"
nodeID number
...mappings (string | number)[]
Returns

void

Call Signature

send(address, nodeID, ...mappings): void

Map a range of sequential controls to sequential audio buses. Mappings are repeating [control, busIndex, count] triplets.

Parameters
Parameter Type
address "/n_mapan"
nodeID number
...mappings (string | number)[]
Returns

void

Call Signature

send(address, ...args): void

Create new groups. Args are repeating [groupID, addAction, targetID] triplets. addAction: 0=head, 1=tail, 2=before, 3=after, 4=replace.

Parameters
Parameter Type
address "/g_new"
...args [number, AddAction, number, ...number[]]
Returns

void

Call Signature

send(address, ...args): void

Create new parallel groups (children evaluated in unspecified order). Same signature as /g_new.

Parameters
Parameter Type
address "/p_new"
...args [number, AddAction, number, ...number[]]
Returns

void

Call Signature

send(address, ...groupIDs): void

Free all immediate children of one or more groups (groups themselves remain).

Parameters
Parameter Type
address "/g_freeAll"
...groupIDs [number, ...number[]]
Returns

void

Call Signature

send(address, ...groupIDs): void

Recursively free all synths inside one or more groups and their nested sub-groups.

Parameters
Parameter Type
address "/g_deepFree"
...groupIDs [number, ...number[]]
Returns

void

Call Signature

send(address, ...pairs): void

Move node to head of group. Args are repeating [groupID, nodeID] pairs.

Parameters
Parameter Type
address "/g_head"
...pairs [number, number, ...number[]]
Returns

void

Call Signature

send(address, ...pairs): void

Move node to tail of group. Args are repeating [groupID, nodeID] pairs.

Parameters
Parameter Type
address "/g_tail"
...pairs [number, number, ...number[]]
Returns

void

Call Signature

send(address, ...groupFlagPairs): void

Print group's node tree to debug output. Args are repeating [groupID, flag] pairs. flag: 0=structure only, non-zero=include control values. No reply message.

Parameters
Parameter Type
address "/g_dumpTree"
...groupFlagPairs [number, number, ...number[]]
Returns

void

Call Signature

send(address, ...groupFlagPairs): void

Query group tree structure. Args are repeating [groupID, flag] pairs. flag: 0=structure only, non-zero=include control values. Replies with /g_queryTree.reply.

Parameters
Parameter Type
address "/g_queryTree"
...groupFlagPairs [number, number, ...number[]]
Returns

void

Call Signature

send(address, nodeID, ugenIndex, command, ...args): void

Send a command to a specific UGen instance within a synth. The command name and args are UGen-specific.

Parameters
Parameter Type
address "/u_cmd"
nodeID number
ugenIndex number
command string
...args OscArg[]
Returns

void

Call Signature

send(address, bufnum, numFrames, numChannels?, sampleRate?): void

Async. Allocate an empty buffer. Queued and rewritten to /b_allocPtr internally. Use sync() after to ensure completion. Replies with /done /b_allocPtr bufnum. Note: completion messages are not supported (dropped during rewrite).

Parameters
Parameter Type
address "/b_alloc"
bufnum number
numFrames number
numChannels? number
sampleRate? number
Returns

void

Call Signature

send(address, bufnum, path, startFrame?, numFrames?): void

Async. Allocate a buffer and read an audio file into it. The path is fetched via the configured sampleBaseURL. Queued and rewritten internally. Replies with /done /b_allocPtr bufnum.

Parameters
Parameter Type
address "/b_allocRead"
bufnum number
path string
startFrame? number
numFrames? number
Returns

void

Call Signature

send(address, bufnum, path, startFrame, numFrames, ...channels): void

Async. Allocate a buffer and read specific channels from an audio file. Queued and rewritten internally. Replies with /done /b_allocPtr bufnum.

Parameters
Parameter Type
address "/b_allocReadChannel"
bufnum number
path string
startFrame number
numFrames number
...channels number[]
Returns

void

Call Signature

send(address, bufnum, data): void

Async. SuperSonic extension: allocate a buffer from inline audio file bytes (WAV, FLAC, OGG, etc.) without URL fetch. Queued and rewritten internally. Replies with /done /b_allocPtr bufnum.

Parameters
Parameter Type
address "/b_allocFile"
bufnum number
data ArrayBuffer | Uint8Array<ArrayBufferLike>
Returns

void

Call Signature

send(address, bufnum, completionMessage?): void

Async. Free a buffer. Optional completionMessage is an encoded OSC message executed after freeing. Replies with /done /b_free bufnum.

Parameters
Parameter Type
address "/b_free"
bufnum number
completionMessage? ArrayBuffer | Uint8Array<ArrayBufferLike>
Returns

void

Call Signature

send(address, bufnum, completionMessage?): void

Async. Zero a buffer's sample data. Optional completionMessage is an encoded OSC message executed after zeroing. Replies with /done /b_zero bufnum.

Parameters
Parameter Type
address "/b_zero"
bufnum number
completionMessage? ArrayBuffer | Uint8Array<ArrayBufferLike>
Returns

void

Call Signature

send(address, ...bufnums): void

Query buffer info. Replies with /b_info for each buffer: bufnum, numFrames, numChannels, sampleRate.

Parameters
Parameter Type
address "/b_query"
...bufnums [number, ...number[]]
Returns

void

Call Signature

send(address, bufnum, ...sampleIndices): void

Get individual sample values. Replies with /b_set bufnum index value ....

Parameters
Parameter Type
address "/b_get"
bufnum number
...sampleIndices [number, ...number[]]
Returns

void

Call Signature

send(address, bufnum, ...indexValuePairs): void

Set individual buffer samples. Args are repeating [index, value] pairs after bufnum.

Parameters
Parameter Type
address "/b_set"
bufnum number
...indexValuePairs number[]
Returns

void

Call Signature

send(address, bufnum, startIndex, count, ...values): void

Set sequential buffer samples starting at startIndex. For multiple ranges, use the catch-all overload.

Parameters
Parameter Type
address "/b_setn"
bufnum number
startIndex number
count number
...values number[]
Returns

void

Call Signature

send(address, bufnum, startIndex, count): void

Get sequential sample values. Replies with /b_setn bufnum startIndex count values.... For multiple ranges, use the catch-all overload.

Parameters
Parameter Type
address "/b_getn"
bufnum number
startIndex number
count number
Returns

void

Call Signature

send(address, bufnum, startIndex, count, value): void

Fill sequential buffer samples with a single value. For multiple ranges, use the catch-all overload.

Parameters
Parameter Type
address "/b_fill"
bufnum number
startIndex number
count number
value number
Returns

void

Call Signature

send(address, bufnum, command, ...args): void

Async. Generate buffer contents. Commands: "sine1", "sine2", "sine3", "cheby", "copy". Flags (for sine/cheby): 1=normalize, 2=wavetable, 4=clear (OR together, e.g. 7=all). Replies with /done /b_gen bufnum.

Parameters
Parameter Type
address "/b_gen"
bufnum number
command string
...args OscArg[]
Returns

void

Call Signature

send(address, ...busIndexValuePairs): void

Set control bus values. Args are repeating [busIndex, value] pairs.

Parameters
Parameter Type
address "/c_set"
...busIndexValuePairs number[]
Returns

void

Call Signature

send(address, ...busIndices): void

Get control bus values. Replies with /c_set index value ....

Parameters
Parameter Type
address "/c_get"
...busIndices [number, ...number[]]
Returns

void

Call Signature

send(address, startIndex, count, ...values): void

Set sequential control bus values starting at startIndex. For multiple ranges, use the catch-all overload.

Parameters
Parameter Type
address "/c_setn"
startIndex number
count number
...values number[]
Returns

void

Call Signature

send(address, startIndex, count): void

Get sequential control bus values. Replies with /c_setn startIndex count values.... For multiple ranges, use the catch-all overload.

Parameters
Parameter Type
address "/c_getn"
startIndex number
count number
Returns

void

Call Signature

send(address, startIndex, count, value): void

Fill sequential control buses with a single value. For multiple ranges, use the catch-all overload.

Parameters
Parameter Type
address "/c_fill"
startIndex number
count number
value number
Returns

void

Call Signature

send(address, ...args): void

Send any OSC message. Use this for commands not covered by typed overloads, or for multi-range variants of commands like /n_setn, /b_fill, /c_getn.

Parameters
Parameter Type
address string
...args OscArg[]
Returns

void


OSC Argument Types

OSC argument types that can be sent in a message.

Plain JS values are mapped to OSC types automatically:

  • number (integer) → i (int32)
  • number (float) → f (float32)
  • strings
  • booleanT / F
  • Uint8Array / ArrayBufferb (blob)

For 64-bit or timetag types, use the tagged object form:

{ type: 'int', value: 42 }
{ type: 'float', value: 440 }     // force float32 for whole numbers
{ type: 'string', value: 'hello' }
{ type: 'blob', value: new Uint8Array([1,2,3]) }
{ type: 'bool', value: true }
{ type: 'int64', value: 9007199254740992n }
{ type: 'double', value: 3.141592653589793 }
{ type: 'timetag', value: ntpTimestamp }
sendOSC()

sendOSC(oscData): void

Send pre-encoded OSC bytes to scsynth.

Use this when you've already encoded the message (e.g. via SuperSonic.osc.encodeMessage) or when sending from a worker that produces raw OSC. Sends bytes as-is without rewriting — buffer allocation commands (/b_alloc*) are not transformed. Use send for buffer commands so they are handled correctly.

Parameters
Parameter Type Description
oscData ArrayBuffer | Uint8Array<ArrayBufferLike> Encoded OSC message or bundle bytes
Returns

void

Throws

If the message exceeds the IN ring size

Example
const msg = SuperSonic.osc.encodeMessage('/n_set', [1001, 'freq', 880]);
sonic.sendOSC(msg);
setClockOffset()

setClockOffset(offsetS): void

Set clock offset for multi-system sync (e.g. Ableton Link, NTP server).

Shifts all scheduled bundle execution times by the specified offset. Positive values mean the shared/server clock is ahead of local time.

Parameters
Parameter Type Description
offsetS number Offset in seconds
Returns

void

shutdown()

shutdown(): Promise<void>

Shut down the engine. The instance can be re-initialised with init.

Closes the AudioContext, terminates workers, and releases memory. Emits 'shutdown'.

Returns

Promise<void>

startCapture()

startCapture(): void

Start capturing audio output to a buffer. SAB mode only.

Returns

void

stopCapture()

stopCapture(): object

Stop capturing and return the captured audio data.

Returns

object

Name Type
channels number
frames number
left Float32Array
right Float32Array<ArrayBufferLike>
sampleRate number
suspend()

suspend(): Promise<void>

Suspend the AudioContext and stop the drift timer.

The worklet remains loaded but audio processing stops. Use resume or recover to restart.

Returns

Promise<void>

sync()

sync(syncId?): Promise<void>

Wait for scsynth to process all pending commands.

Sends a /sync message and waits for the /synced reply. Use after loading synthdefs or buffers to ensure they're ready before creating synths.

Parameters
Parameter Type Description
syncId? number Optional custom sync ID (random if omitted)
Returns

Promise<void>

Throws

Rejects after 10 seconds if scsynth doesn't respond.

Example
await sonic.loadSynthDef('beep');
await sonic.sync();
// SynthDef is now guaranteed to be loaded
await sonic.send('/s_new', 'beep', 1001, 0, 1);
getMetricsSchema()

static getMetricsSchema(): MetricsSchema

Get the metrics schema describing all available metrics.

Includes array offsets for zero-allocation reading via getMetricsArray, metric types/units/descriptions, and a declarative UI layout used by the <supersonic-metrics> web component.

See docs/METRICS_COMPONENT.md for the metrics component guide.

Returns

MetricsSchema

getRawTreeSchema()

static getRawTreeSchema(): Record<string, unknown>

Get schema describing the raw flat node tree structure.

Returns

Record<string, unknown>

getTreeSchema()

static getTreeSchema(): Record<string, unknown>

Get schema describing the hierarchical node tree structure.

Returns

Record<string, unknown>


OscChannel

OscChannel — unified dispatch for sending OSC to the AudioWorklet.

Obtain a channel via SuperSonic.createOscChannel on the main thread, then transfer it to a Web Worker for direct communication with the AudioWorklet.

Member Description
getCurrentNTP Set the NTP time source for classification (used in AudioWorklet context).
mode Transport mode this channel is using.
transferable Serializable config for transferring this channel to a worker via postMessage.
transferList Array of transferable objects (MessagePorts) for the postMessage transfer list.
close() Close the channel and release its ports.
getAndResetMetrics() Get and reset local metrics (for periodic reporting).
getMetrics() Get current metrics snapshot.
nextNodeId() Get the next unique node ID.
send() Send an OSC message: frames it onto the IN ring (SAB) or postMessages it to the worklet (PM).
sendDirect() Alias of send — kept for callers that used the explicit direct path.
fromTransferable() Reconstruct an OscChannel from data received via postMessage in a worker.
Example
// Main thread: create and transfer to worker
const channel = sonic.createOscChannel();
myWorker.postMessage(
  { channel: channel.transferable },
  channel.transferList,
);

// Inside worker: reconstruct and send
import { OscChannel } from 'supersonic-scsynth/osc-channel';
const channel = OscChannel.fromTransferable(event.data.channel);
channel.send(oscBytes);

Constructors
Constructor

new OscChannel(): OscChannel

Returns

OscChannel


Accessors
getCurrentNTP
Set Signature

set getCurrentNTP(fn): void

Set the NTP time source for classification (used in AudioWorklet context).

Parameters
Parameter Type
fn () => number
Returns

void

mode
Get Signature

get mode(): TransportMode

Transport mode this channel is using.

Returns

TransportMode

transferable
Get Signature

get transferable(): OscChannelTransferable

Serializable config for transferring this channel to a worker via postMessage.

Example
worker.postMessage({ ch: channel.transferable }, channel.transferList);
Returns

OscChannelTransferable

transferList
Get Signature

get transferList(): Transferable[]

Array of transferable objects (MessagePorts) for the postMessage transfer list.

Example
worker.postMessage({ ch: channel.transferable }, channel.transferList);
Returns

Transferable[]


Methods
close()

close(): void

Close the channel and release its ports.

Returns

void

getAndResetMetrics()

getAndResetMetrics(): OscChannelMetrics

Get and reset local metrics (for periodic reporting).

Returns

OscChannelMetrics

getMetrics()

getMetrics(): OscChannelMetrics

Get current metrics snapshot.

Returns

OscChannelMetrics

nextNodeId()

nextNodeId(): number

Get the next unique node ID.

Thread-safe — can be called concurrently from multiple workers and no two callers will ever receive the same ID. IDs start at 1000 (0 is the root group, 1 is the default group, 2–999 are reserved for manual use).

Returns

number

A unique node ID (>= 1000)

send()

send(oscData): boolean

Send an OSC message: frames it onto the IN ring (SAB) or postMessages it to the worklet (PM). Classification and scheduling happen on the audio thread (the engine's OscIngress + BundleScheduler) — the producer never classifies.

Parameters
Parameter Type Description
oscData Uint8Array Encoded OSC bytes
Returns

boolean

true if sent successfully

sendDirect()

sendDirect(oscData): boolean

Alias of send — kept for callers that used the explicit direct path.

Parameters
Parameter Type Description
oscData Uint8Array Encoded OSC bytes
Returns

boolean

true if sent successfully

fromTransferable()

static fromTransferable(data): OscChannel

Reconstruct an OscChannel from data received via postMessage in a worker.

Parameters
Parameter Type Description
data OscChannelTransferable The transferable config from channel.transferable
Returns

OscChannel

Example
// In a Web Worker:
self.onmessage = (e) => {
  const channel = OscChannel.fromTransferable(e.data.ch);
  channel.send(oscBytes);
};

Support + License

  • GitHub — source, issues, discussions
  • npm — package registry
  • License: MIT (main library) / GPL-3.0 (WASM/AudioWorklet core)