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
- API Overview
- Patterns
- Constructor Options
- Server Options
- scsynth Command Quick Reference
- Full Method Reference
- Support + License
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:
- Creates an AudioContext and AudioWorklet
- Loads the WebAssembly module containing scsynth
- 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
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
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
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
getMetrics()
getMetrics():
OscChannelMetrics
Get current metrics snapshot.
Returns
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()
staticfromTransferable(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
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
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
-1to have the server auto-generate a unique node ID - Node ID
0is 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:
floatorint- 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
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'— beforeinit()or aftershutdown()/destroy().'booting'— whileinit()is in progress.'running'— afterinit()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
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
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
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
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
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
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
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
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)string→sboolean→T/FUint8Array/ArrayBuffer→b(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()
staticgetMetricsSchema():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
getRawTreeSchema()
staticgetRawTreeSchema():Record<string,unknown>
Get schema describing the raw flat node tree structure.
Returns
Record<string, unknown>
getTreeSchema()
staticgetTreeSchema():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
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
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
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
getMetrics()
getMetrics():
OscChannelMetrics
Get current metrics snapshot.
Returns
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()
staticfromTransferable(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
Example
// In a Web Worker:
self.onmessage = (e) => {
const channel = OscChannel.fromTransferable(e.data.ch);
channel.send(oscBytes);
};