supersonic-scsynth 0.66.0 → 0.67.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.npm.md CHANGED
@@ -1,4 +1,4 @@
1
- # SuperSonic 0.66.0
1
+ # SuperSonic 0.67.2
2
2
 
3
3
  > SuperCollider's scsynth in the browser as an AudioWorklet.
4
4
  >
@@ -124,6 +124,18 @@ The arguments are:
124
124
 
125
125
  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.
126
126
 
127
+ 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:
128
+
129
+ ```javascript
130
+ const id = supersonic.nextNodeId();
131
+ supersonic.send("/s_new", "sonic-pi-prophet", id, 0, 0, "note", 28, "release", 8, "cutoff", 70);
132
+
133
+ // Later — change the cutoff while it's playing
134
+ supersonic.send("/n_set", id, "cutoff", 100);
135
+ ```
136
+
137
+ `nextNodeId()` is thread-safe - if you have multiple Web Workers sending OSC (see the [Workers Guide](https://github.com/samaaron/supersonic/blob/main/docs/WORKERS.md)), each one can allocate IDs independently, guaranteed unique with no clashes.
138
+
127
139
 
128
140
  ## Working Example
129
141
 
@@ -239,18 +251,20 @@ scsynth with low latency inside a web page.
239
251
 
240
252
  **Advanced**
241
253
 
242
- | Member | Description |
243
- | ----------------------------------------- | ------------------------------------------------------------ |
244
- | [`bufferConstants`](#bufferconstants) | Buffer layout constants from the WASM build. |
245
- | [`initTime`](#inittime) | NTP time (seconds since 1900) when the AudioContext started. |
246
- | [`mode`](#mode) | Active transport mode ('sab' or 'postMessage'). |
247
- | [`ringBufferBase`](#ringbufferbase) | Ring buffer base offset in SharedArrayBuffer. |
248
- | [`sharedBuffer`](#sharedbuffer) | The SharedArrayBuffer (SAB mode) or null (postMessage mode). |
249
- | [`getLoadedBuffers()`](#getloadedbuffers) | Get info about all loaded audio buffers. |
250
- | [`getSystemReport()`](#getsystemreport) | Get a comprehensive system performance report. |
251
- | [`nextNodeId()`](#nextnodeid) | Get the next unique node ID. |
252
- | [`getRawTreeSchema()`](#getrawtreeschema) | Get schema describing the raw flat node tree structure. |
253
- | [`getTreeSchema()`](#gettreeschema) | Get schema describing the hierarchical node tree structure. |
254
+ | Member | Description |
255
+ | ----------------------------------------- | ------------------------------------------------------------------------------------------ |
256
+ | [`bufferConstants`](#bufferconstants) | Buffer layout constants from the WASM build. |
257
+ | [`initTime`](#inittime) | NTP time (seconds since 1900) when the AudioContext started. |
258
+ | [`mode`](#mode) | Active transport mode ('sab' or 'postMessage'). |
259
+ | [`ringBufferBase`](#ringbufferbase) | Ring buffer base offset in SharedArrayBuffer. |
260
+ | [`sharedBuffer`](#sharedbuffer) | The SharedArrayBuffer (SAB mode) or null (postMessage mode). |
261
+ | [`getEngineState()`](#getenginestate) | Returns the current engine lifecycle state. |
262
+ | [`getLoadedBuffers()`](#getloadedbuffers) | Get info about all loaded audio buffers. |
263
+ | [`getSystemReport()`](#getsystemreport) | Get a comprehensive system performance report. |
264
+ | [`isRunning()`](#isrunning) | Returns true if the engine has finished booting and is ready to send and receive messages. |
265
+ | [`nextNodeId()`](#nextnodeid) | Get the next unique node ID. |
266
+ | [`getRawTreeSchema()`](#getrawtreeschema) | Get schema describing the raw flat node tree structure. |
267
+ | [`getTreeSchema()`](#gettreeschema) | Get schema describing the hierarchical node tree structure. |
254
268
 
255
269
  ### OscChannel
256
270
 
@@ -259,21 +273,27 @@ OscChannel — unified dispatch for sending OSC to the AudioWorklet.
259
273
  Obtain a channel via [SuperSonic.createOscChannel](#createoscchannel) on the main thread,
260
274
  then transfer it to a Web Worker for direct communication with the AudioWorklet.
261
275
 
262
- | Member | Description |
263
- | --------------------------------------------- | ------------------------------------------------------------------------------- |
264
- | [`getCurrentNTP`](#getcurrentntp) | Set the NTP time source for classification (used in AudioWorklet context). |
265
- | [`mode`](#mode) | Transport mode this channel is using. |
266
- | [`transferable`](#transferable) | Serializable config for transferring this channel to a worker via postMessage. |
267
- | [`transferList`](#transferlist) | Array of transferable objects (MessagePorts) for the postMessage transfer list. |
268
- | [`classify()`](#classify) | Classify an OSC message to determine its routing. |
269
- | [`close()`](#close) | Close the channel and release its ports. |
270
- | [`getAndResetMetrics()`](#getandresetmetrics) | Get and reset local metrics (for periodic reporting). |
271
- | [`getMetrics()`](#getmetrics) | Get current metrics snapshot. |
272
- | [`nextNodeId()`](#nextnodeid) | Get the next unique node ID. |
273
- | [`send()`](#send) | Send an OSC message with automatic routing. |
274
- | [`sendDirect()`](#senddirect) | Send directly to worklet without classification or metrics tracking. |
275
- | [`sendToPrescheduler()`](#sendtoprescheduler) | Send to prescheduler without classification. |
276
- | [`fromTransferable()`](#fromtransferable) | Reconstruct an OscChannel from data received via postMessage in a worker. |
276
+ | Member | Description |
277
+ | --------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
278
+ | [`getCurrentNTP`](#getcurrentntp) | Set the NTP time source for classification (used in AudioWorklet context). |
279
+ | [`mode`](#mode) | Transport mode this channel is using. |
280
+ | [`replyDrops`](#replydrops) | Number of reply messages dropped because the reply buffer was full. |
281
+ | [`transferable`](#transferable) | Serializable config for transferring this channel to a worker via postMessage. |
282
+ | [`transferList`](#transferlist) | Array of transferable objects (MessagePorts) for the postMessage transfer list. |
283
+ | [`activateReplies()`](#activatereplies) | Activate the reply slot without registering a handler. |
284
+ | [`classify()`](#classify) | Classify an OSC message to determine its routing. |
285
+ | [`clearReplyHandler()`](#clearreplyhandler) | Clear the reply handler and release the reply channel. |
286
+ | [`close()`](#close) | Close the channel and release its ports. |
287
+ | [`deactivateReplies()`](#deactivatereplies) | Release the reply slot. |
288
+ | [`getAndResetMetrics()`](#getandresetmetrics) | Get and reset local metrics (for periodic reporting). |
289
+ | [`getMetrics()`](#getmetrics) | Get current metrics snapshot. |
290
+ | [`nextNodeId()`](#nextnodeid) | Get the next unique node ID. |
291
+ | [`pollReplies()`](#pollreplies) | Drain pending replies, calling the registered handler (or handler argument, if given) once per message. |
292
+ | [`send()`](#send) | Send an OSC message with automatic routing. |
293
+ | [`sendDirect()`](#senddirect) | Send directly to worklet without classification or metrics tracking. |
294
+ | [`sendToPrescheduler()`](#sendtoprescheduler) | Send to prescheduler without classification. |
295
+ | [`setReplyHandler()`](#setreplyhandler) | Register a handler for OSC replies from scsynth. |
296
+ | [`fromTransferable()`](#fromtransferable) | Reconstruct an OscChannel from data received via postMessage in a worker. |
277
297
 
278
298
  #### Example
279
299
 
@@ -337,6 +357,20 @@ Transport mode this channel is using.
337
357
 
338
358
  [`TransportMode`](#transportmode)
339
359
 
360
+ ##### replyDrops
361
+
362
+ ###### Get Signature
363
+
364
+ > **get** **replyDrops**(): `number`
365
+
366
+ Number of reply messages dropped because the reply buffer was full.
367
+ SAB mode only — undefined in PM mode or before [activateReplies](#activatereplies).
368
+ Counter resets each time the slot is (re)claimed.
369
+
370
+ ###### Returns
371
+
372
+ `number`
373
+
340
374
  ##### transferable
341
375
 
342
376
  ###### Get Signature
@@ -377,6 +411,19 @@ worker.postMessage({ ch: channel.transferable }, channel.transferList);
377
411
 
378
412
  #### Methods
379
413
 
414
+ ##### activateReplies()
415
+
416
+ > **activateReplies**(): `void`
417
+
418
+ Activate the reply slot without registering a handler. Usually called
419
+ for you by [setReplyHandler](#setreplyhandler); only call directly if you want to
420
+ claim the slot before installing a handler (or to use the optional
421
+ one-shot handler argument of [pollReplies](#pollreplies)).
422
+
423
+ ###### Returns
424
+
425
+ `void`
426
+
380
427
  ##### classify()
381
428
 
382
429
  > **classify**(`oscData`): [`OscCategory`](#osccategory)
@@ -393,6 +440,16 @@ Classify an OSC message to determine its routing.
393
440
 
394
441
  [`OscCategory`](#osccategory)
395
442
 
443
+ ##### clearReplyHandler()
444
+
445
+ > **clearReplyHandler**(): `void`
446
+
447
+ Clear the reply handler and release the reply channel. Idempotent.
448
+
449
+ ###### Returns
450
+
451
+ `void`
452
+
396
453
  ##### close()
397
454
 
398
455
  > **close**(): `void`
@@ -403,6 +460,16 @@ Close the channel and release its ports.
403
460
 
404
461
  `void`
405
462
 
463
+ ##### deactivateReplies()
464
+
465
+ > **deactivateReplies**(): `void`
466
+
467
+ Release the reply slot. Usually called for you by [clearReplyHandler](#clearreplyhandler).
468
+
469
+ ###### Returns
470
+
471
+ `void`
472
+
406
473
  ##### getAndResetMetrics()
407
474
 
408
475
  > **getAndResetMetrics**(): [`OscChannelMetrics`](#oscchannelmetrics)
@@ -439,6 +506,30 @@ the root group, 1 is the default group, 2–999 are reserved for manual use).
439
506
 
440
507
  A unique node ID (>= 1000)
441
508
 
509
+ ##### pollReplies()
510
+
511
+ > **pollReplies**(`handler?`): `number`
512
+
513
+ Drain pending replies, calling the registered handler (or `handler`
514
+ argument, if given) once per message. Returns the number of messages
515
+ processed. Zero-allocation on the hot path.
516
+
517
+ Call from an AudioWorklet's `process()` method to receive replies on
518
+ the audio thread. In other contexts automatic delivery already calls
519
+ this for you.
520
+
521
+ ###### Parameters
522
+
523
+ | Parameter | Type | Description |
524
+ | ---------- | ------------------------------------------------------------------------------------------- | ------------------------------------ |
525
+ | `handler?` | ((`view`, `offset`, `length`, `sequence`) => `void`) \| ((`oscData`, `sequence`) => `void`) | Optional override for this call only |
526
+
527
+ ###### Returns
528
+
529
+ `number`
530
+
531
+ Number of messages drained
532
+
442
533
  ##### send()
443
534
 
444
535
  > **send**(`oscData`): `boolean`
@@ -498,6 +589,40 @@ Send to prescheduler without classification.
498
589
 
499
590
  true if sent successfully
500
591
 
592
+ ##### setReplyHandler()
593
+
594
+ > **setReplyHandler**(`handler`): `void`
595
+
596
+ Register a handler for OSC replies from scsynth. Idempotent — replaces
597
+ any previously-registered handler. In AudioWorklet contexts the worklet
598
+ must call [pollReplies](#pollreplies) from `process()` to drain; in all other
599
+ contexts delivery is automatic. All registered channels receive all
600
+ replies (broadcast); filter locally if you only need specific addresses.
601
+
602
+ SAB mode: handler receives `(view, offset, length, sequence)` — zero-copy
603
+ into the shared buffer. Read bytes from `view[offset..offset+length]`.
604
+ Data is valid only for the duration of the handler call.
605
+
606
+ PM mode: handler receives `(oscData, sequence)` where `oscData` is a copy.
607
+
608
+ ###### Parameters
609
+
610
+ | Parameter | Type |
611
+ | --------- | ------------------------------------------------------------------------------------------- |
612
+ | `handler` | ((`view`, `offset`, `length`, `sequence`) => `void`) \| ((`oscData`, `sequence`) => `void`) |
613
+
614
+ ###### Returns
615
+
616
+ `void`
617
+
618
+ ###### Example
619
+
620
+ ```ts
621
+ channel.setReplyHandler((view, offset, length, sequence) => {
622
+ // SAB: read raw OSC bytes from view[offset..offset+length]
623
+ });
624
+ ```
625
+
501
626
  ##### fromTransferable()
502
627
 
503
628
  > `static` **fromTransferable**(`data`): [`OscChannel`](#oscchannel)
@@ -1216,6 +1341,27 @@ Get number of audio frames captured so far.
1216
1341
 
1217
1342
  `number`
1218
1343
 
1344
+ ##### getEngineState()
1345
+
1346
+ > **getEngineState**(): `"running"` | `"stopped"` | `"booting"`
1347
+
1348
+ Returns the current engine lifecycle state.
1349
+
1350
+ One of:
1351
+
1352
+ * `'stopped'` — before `init()` or after `shutdown()`/`destroy()`.
1353
+ * `'booting'` — while `init()` is in progress.
1354
+ * `'running'` — after `init()` resolves and before any teardown.
1355
+
1356
+ Mirrors the C++ `SupersonicEngine::engineState()` accessor. The C++
1357
+ enum also has `'restarting'` and `'error'` states that the web runtime
1358
+ does not currently distinguish — `recover()` and `resume()` do not
1359
+ surface a `'restarting'` state from JS.
1360
+
1361
+ ###### Returns
1362
+
1363
+ `"running"` | `"stopped"` | `"booting"`
1364
+
1219
1365
  ##### getInfo()
1220
1366
 
1221
1367
  > **getInfo**(): [`SuperSonicInfo`](#supersonicinfo)
@@ -1421,6 +1567,21 @@ Check if audio capture is currently enabled.
1421
1567
 
1422
1568
  `boolean`
1423
1569
 
1570
+ ##### isRunning()
1571
+
1572
+ > **isRunning**(): `boolean`
1573
+
1574
+ Returns true if the engine has finished booting and is ready to send
1575
+ and receive messages.
1576
+
1577
+ Mirrors the C++ `SupersonicEngine::isRunning()` accessor; returns the
1578
+ same value as the existing `initialized` getter, exposed as a method
1579
+ to match the C++ API shape.
1580
+
1581
+ ###### Returns
1582
+
1583
+ `boolean`
1584
+
1424
1585
  ##### loadSample()
1425
1586
 
1426
1587
  > **loadSample**(`bufnum`, `source`, `startFrame?`, `numFrames?`): `Promise`<[`LoadSampleResult`](#loadsampleresult)>
@@ -2141,9 +2302,9 @@ Create a new synth from a loaded synthdef. addAction: 0=head, 1=tail, 2=before,
2141
2302
  | ------------- | ------------------------- |
2142
2303
  | `address` | `"/s_new"` |
2143
2304
  | `defName` | `string` |
2144
- | `nodeID` | [`NodeID`](#nodeid) |
2305
+ | `nodeID` | `number` |
2145
2306
  | `addAction` | [`AddAction`](#addaction) |
2146
- | `targetID` | [`NodeID`](#nodeid) |
2307
+ | `targetID` | `number` |
2147
2308
  | ...`controls` | (`string` \| `number`)\[] |
2148
2309
 
2149
2310
  ###### Returns
@@ -2161,7 +2322,7 @@ Get synth control values. Controls can be indices or names. Replies with `/n_set
2161
2322
  | Parameter | Type |
2162
2323
  | ------------- | ------------------------- |
2163
2324
  | `address` | `"/s_get"` |
2164
- | `nodeID` | [`NodeID`](#nodeid) |
2325
+ | `nodeID` | `number` |
2165
2326
  | ...`controls` | (`string` \| `number`)\[] |
2166
2327
 
2167
2328
  ###### Returns
@@ -2179,7 +2340,7 @@ Get sequential synth control values. Control can be an index or name. Replies wi
2179
2340
  | Parameter | Type |
2180
2341
  | --------- | -------------------- |
2181
2342
  | `address` | `"/s_getn"` |
2182
- | `nodeID` | [`NodeID`](#nodeid) |
2343
+ | `nodeID` | `number` |
2183
2344
  | `control` | `string` \| `number` |
2184
2345
  | `count` | `number` |
2185
2346
 
@@ -2195,10 +2356,10 @@ Release client-side synth ID tracking. Synths continue running but are reassigne
2195
2356
 
2196
2357
  ###### Parameters
2197
2358
 
2198
- | Parameter | Type |
2199
- | ------------ | ------------------------------------- |
2200
- | `address` | `"/s_noid"` |
2201
- | ...`nodeIDs` | \[[`NodeID`](#nodeid), `...NodeID[]`] |
2359
+ | Parameter | Type |
2360
+ | ------------ | -------------------------- |
2361
+ | `address` | `"/s_noid"` |
2362
+ | ...`nodeIDs` | \[`number`, `...number[]`] |
2202
2363
 
2203
2364
  ###### Returns
2204
2365
 
@@ -2212,10 +2373,10 @@ Free (delete) one or more nodes.
2212
2373
 
2213
2374
  ###### Parameters
2214
2375
 
2215
- | Parameter | Type |
2216
- | ------------ | ------------------------------------- |
2217
- | `address` | `"/n_free"` |
2218
- | ...`nodeIDs` | \[[`NodeID`](#nodeid), `...NodeID[]`] |
2376
+ | Parameter | Type |
2377
+ | ------------ | -------------------------- |
2378
+ | `address` | `"/n_free"` |
2379
+ | ...`nodeIDs` | \[`number`, `...number[]`] |
2219
2380
 
2220
2381
  ###### Returns
2221
2382
 
@@ -2232,7 +2393,7 @@ Set node control values. Controls are alternating name/index and value pairs. If
2232
2393
  | Parameter | Type |
2233
2394
  | ------------- | ------------------------- |
2234
2395
  | `address` | `"/n_set"` |
2235
- | `nodeID` | [`NodeID`](#nodeid) |
2396
+ | `nodeID` | `number` |
2236
2397
  | ...`controls` | (`string` \| `number`)\[] |
2237
2398
 
2238
2399
  ###### Returns
@@ -2250,7 +2411,7 @@ Set sequential control values starting at the given control index/name. For mult
2250
2411
  | Parameter | Type |
2251
2412
  | ----------- | -------------------- |
2252
2413
  | `address` | `"/n_setn"` |
2253
- | `nodeID` | [`NodeID`](#nodeid) |
2414
+ | `nodeID` | `number` |
2254
2415
  | `control` | `string` \| `number` |
2255
2416
  | `count` | `number` |
2256
2417
  | ...`values` | `number`\[] |
@@ -2270,7 +2431,7 @@ Fill sequential controls with a single value. For multiple ranges, use the catch
2270
2431
  | Parameter | Type |
2271
2432
  | --------- | -------------------- |
2272
2433
  | `address` | `"/n_fill"` |
2273
- | `nodeID` | [`NodeID`](#nodeid) |
2434
+ | `nodeID` | `number` |
2274
2435
  | `control` | `string` \| `number` |
2275
2436
  | `count` | `number` |
2276
2437
  | `value` | `number` |
@@ -2287,10 +2448,10 @@ Turn nodes on (1) or off (0). Args are repeating \[nodeID, flag] pairs.
2287
2448
 
2288
2449
  ###### Parameters
2289
2450
 
2290
- | Parameter | Type |
2291
- | ---------- | ------------------------------------------------- |
2292
- | `address` | `"/n_run"` |
2293
- | ...`pairs` | \[[`NodeID`](#nodeid), `0` \| `1`, `...NodeID[]`] |
2451
+ | Parameter | Type |
2452
+ | ---------- | -------------------------------------- |
2453
+ | `address` | `"/n_run"` |
2454
+ | ...`pairs` | \[`number`, `0` \| `1`, `...number[]`] |
2294
2455
 
2295
2456
  ###### Returns
2296
2457
 
@@ -2304,10 +2465,10 @@ Move nodeA to execute immediately before nodeB. Args are repeating \[nodeA, node
2304
2465
 
2305
2466
  ###### Parameters
2306
2467
 
2307
- | Parameter | Type |
2308
- | ---------- | ---------------------------------------------------------- |
2309
- | `address` | `"/n_before"` |
2310
- | ...`pairs` | \[[`NodeID`](#nodeid), [`NodeID`](#nodeid), `...NodeID[]`] |
2468
+ | Parameter | Type |
2469
+ | ---------- | ------------------------------------ |
2470
+ | `address` | `"/n_before"` |
2471
+ | ...`pairs` | \[`number`, `number`, `...number[]`] |
2311
2472
 
2312
2473
  ###### Returns
2313
2474
 
@@ -2321,10 +2482,10 @@ Move nodeA to execute immediately after nodeB. Args are repeating \[nodeA, nodeB
2321
2482
 
2322
2483
  ###### Parameters
2323
2484
 
2324
- | Parameter | Type |
2325
- | ---------- | ---------------------------------------------------------- |
2326
- | `address` | `"/n_after"` |
2327
- | ...`pairs` | \[[`NodeID`](#nodeid), [`NodeID`](#nodeid), `...NodeID[]`] |
2485
+ | Parameter | Type |
2486
+ | ---------- | ------------------------------------ |
2487
+ | `address` | `"/n_after"` |
2488
+ | ...`pairs` | \[`number`, `number`, `...number[]`] |
2328
2489
 
2329
2490
  ###### Returns
2330
2491
 
@@ -2338,12 +2499,12 @@ Reorder nodes within a group. addAction: 0=head, 1=tail, 2=before target, 3=afte
2338
2499
 
2339
2500
  ###### Parameters
2340
2501
 
2341
- | Parameter | Type |
2342
- | ------------ | ------------------------------------- |
2343
- | `address` | `"/n_order"` |
2344
- | `addAction` | `0` \| `1` \| `2` \| `3` |
2345
- | `targetID` | [`NodeID`](#nodeid) |
2346
- | ...`nodeIDs` | \[[`NodeID`](#nodeid), `...NodeID[]`] |
2502
+ | Parameter | Type |
2503
+ | ------------ | -------------------------- |
2504
+ | `address` | `"/n_order"` |
2505
+ | `addAction` | `0` \| `1` \| `2` \| `3` |
2506
+ | `targetID` | `number` |
2507
+ | ...`nodeIDs` | \[`number`, `...number[]`] |
2347
2508
 
2348
2509
  ###### Returns
2349
2510
 
@@ -2357,10 +2518,10 @@ Query node info. Replies with `/n_info` for each node: nodeID, parentGroupID, pr
2357
2518
 
2358
2519
  ###### Parameters
2359
2520
 
2360
- | Parameter | Type |
2361
- | ------------ | ------------------------------------- |
2362
- | `address` | `"/n_query"` |
2363
- | ...`nodeIDs` | \[[`NodeID`](#nodeid), `...NodeID[]`] |
2521
+ | Parameter | Type |
2522
+ | ------------ | -------------------------- |
2523
+ | `address` | `"/n_query"` |
2524
+ | ...`nodeIDs` | \[`number`, `...number[]`] |
2364
2525
 
2365
2526
  ###### Returns
2366
2527
 
@@ -2374,10 +2535,10 @@ Print control values and calculation rates for each node to debug output. No rep
2374
2535
 
2375
2536
  ###### Parameters
2376
2537
 
2377
- | Parameter | Type |
2378
- | ------------ | ------------------------------------- |
2379
- | `address` | `"/n_trace"` |
2380
- | ...`nodeIDs` | \[[`NodeID`](#nodeid), `...NodeID[]`] |
2538
+ | Parameter | Type |
2539
+ | ------------ | -------------------------- |
2540
+ | `address` | `"/n_trace"` |
2541
+ | ...`nodeIDs` | \[`number`, `...number[]`] |
2381
2542
 
2382
2543
  ###### Returns
2383
2544
 
@@ -2394,7 +2555,7 @@ Map controls to read from control buses. Mappings are repeating \[control, busIn
2394
2555
  | Parameter | Type |
2395
2556
  | ------------- | ------------------------- |
2396
2557
  | `address` | `"/n_map"` |
2397
- | `nodeID` | [`NodeID`](#nodeid) |
2558
+ | `nodeID` | `number` |
2398
2559
  | ...`mappings` | (`string` \| `number`)\[] |
2399
2560
 
2400
2561
  ###### Returns
@@ -2412,7 +2573,7 @@ Map a range of sequential controls to sequential control buses. Mappings are rep
2412
2573
  | Parameter | Type |
2413
2574
  | ------------- | ------------------------- |
2414
2575
  | `address` | `"/n_mapn"` |
2415
- | `nodeID` | [`NodeID`](#nodeid) |
2576
+ | `nodeID` | `number` |
2416
2577
  | ...`mappings` | (`string` \| `number`)\[] |
2417
2578
 
2418
2579
  ###### Returns
@@ -2430,7 +2591,7 @@ Map controls to read from audio buses. Mappings are repeating \[control, busInde
2430
2591
  | Parameter | Type |
2431
2592
  | ------------- | ------------------------- |
2432
2593
  | `address` | `"/n_mapa"` |
2433
- | `nodeID` | [`NodeID`](#nodeid) |
2594
+ | `nodeID` | `number` |
2434
2595
  | ...`mappings` | (`string` \| `number`)\[] |
2435
2596
 
2436
2597
  ###### Returns
@@ -2448,7 +2609,7 @@ Map a range of sequential controls to sequential audio buses. Mappings are repea
2448
2609
  | Parameter | Type |
2449
2610
  | ------------- | ------------------------- |
2450
2611
  | `address` | `"/n_mapan"` |
2451
- | `nodeID` | [`NodeID`](#nodeid) |
2612
+ | `nodeID` | `number` |
2452
2613
  | ...`mappings` | (`string` \| `number`)\[] |
2453
2614
 
2454
2615
  ###### Returns
@@ -2463,10 +2624,10 @@ Create new groups. Args are repeating \[groupID, addAction, targetID] triplets.
2463
2624
 
2464
2625
  ###### Parameters
2465
2626
 
2466
- | Parameter | Type |
2467
- | --------- | ---------------------------------------------------------------------------------------------- |
2468
- | `address` | `"/g_new"` |
2469
- | ...`args` | \[[`NodeID`](#nodeid), [`AddAction`](#addaction), [`NodeID`](#nodeid), ...(number \| UUID)\[]] |
2627
+ | Parameter | Type |
2628
+ | --------- | --------------------------------------------------------------- |
2629
+ | `address` | `"/g_new"` |
2630
+ | ...`args` | \[`number`, [`AddAction`](#addaction), `number`, `...number[]`] |
2470
2631
 
2471
2632
  ###### Returns
2472
2633
 
@@ -2480,10 +2641,10 @@ Create new parallel groups (children evaluated in unspecified order). Same signa
2480
2641
 
2481
2642
  ###### Parameters
2482
2643
 
2483
- | Parameter | Type |
2484
- | --------- | ---------------------------------------------------------------------------------------------- |
2485
- | `address` | `"/p_new"` |
2486
- | ...`args` | \[[`NodeID`](#nodeid), [`AddAction`](#addaction), [`NodeID`](#nodeid), ...(number \| UUID)\[]] |
2644
+ | Parameter | Type |
2645
+ | --------- | --------------------------------------------------------------- |
2646
+ | `address` | `"/p_new"` |
2647
+ | ...`args` | \[`number`, [`AddAction`](#addaction), `number`, `...number[]`] |
2487
2648
 
2488
2649
  ###### Returns
2489
2650
 
@@ -2497,10 +2658,10 @@ Free all immediate children of one or more groups (groups themselves remain).
2497
2658
 
2498
2659
  ###### Parameters
2499
2660
 
2500
- | Parameter | Type |
2501
- | ------------- | ------------------------------------- |
2502
- | `address` | `"/g_freeAll"` |
2503
- | ...`groupIDs` | \[[`NodeID`](#nodeid), `...NodeID[]`] |
2661
+ | Parameter | Type |
2662
+ | ------------- | -------------------------- |
2663
+ | `address` | `"/g_freeAll"` |
2664
+ | ...`groupIDs` | \[`number`, `...number[]`] |
2504
2665
 
2505
2666
  ###### Returns
2506
2667
 
@@ -2514,10 +2675,10 @@ Recursively free all synths inside one or more groups and their nested sub-group
2514
2675
 
2515
2676
  ###### Parameters
2516
2677
 
2517
- | Parameter | Type |
2518
- | ------------- | ------------------------------------- |
2519
- | `address` | `"/g_deepFree"` |
2520
- | ...`groupIDs` | \[[`NodeID`](#nodeid), `...NodeID[]`] |
2678
+ | Parameter | Type |
2679
+ | ------------- | -------------------------- |
2680
+ | `address` | `"/g_deepFree"` |
2681
+ | ...`groupIDs` | \[`number`, `...number[]`] |
2521
2682
 
2522
2683
  ###### Returns
2523
2684
 
@@ -2531,10 +2692,10 @@ Move node to head of group. Args are repeating \[groupID, nodeID] pairs.
2531
2692
 
2532
2693
  ###### Parameters
2533
2694
 
2534
- | Parameter | Type |
2535
- | ---------- | ---------------------------------------------------------- |
2536
- | `address` | `"/g_head"` |
2537
- | ...`pairs` | \[[`NodeID`](#nodeid), [`NodeID`](#nodeid), `...NodeID[]`] |
2695
+ | Parameter | Type |
2696
+ | ---------- | ------------------------------------ |
2697
+ | `address` | `"/g_head"` |
2698
+ | ...`pairs` | \[`number`, `number`, `...number[]`] |
2538
2699
 
2539
2700
  ###### Returns
2540
2701
 
@@ -2548,10 +2709,10 @@ Move node to tail of group. Args are repeating \[groupID, nodeID] pairs.
2548
2709
 
2549
2710
  ###### Parameters
2550
2711
 
2551
- | Parameter | Type |
2552
- | ---------- | ---------------------------------------------------------- |
2553
- | `address` | `"/g_tail"` |
2554
- | ...`pairs` | \[[`NodeID`](#nodeid), [`NodeID`](#nodeid), `...NodeID[]`] |
2712
+ | Parameter | Type |
2713
+ | ---------- | ------------------------------------ |
2714
+ | `address` | `"/g_tail"` |
2715
+ | ...`pairs` | \[`number`, `number`, `...number[]`] |
2555
2716
 
2556
2717
  ###### Returns
2557
2718
 
@@ -2565,10 +2726,10 @@ Print group's node tree to debug output. Args are repeating \[groupID, flag] pai
2565
2726
 
2566
2727
  ###### Parameters
2567
2728
 
2568
- | Parameter | Type |
2569
- | ------------------- | ----------------------------------------------- |
2570
- | `address` | `"/g_dumpTree"` |
2571
- | ...`groupFlagPairs` | \[[`NodeID`](#nodeid), `number`, `...NodeID[]`] |
2729
+ | Parameter | Type |
2730
+ | ------------------- | ------------------------------------ |
2731
+ | `address` | `"/g_dumpTree"` |
2732
+ | ...`groupFlagPairs` | \[`number`, `number`, `...number[]`] |
2572
2733
 
2573
2734
  ###### Returns
2574
2735
 
@@ -2582,10 +2743,10 @@ Query group tree structure. Args are repeating \[groupID, flag] pairs. flag: 0=s
2582
2743
 
2583
2744
  ###### Parameters
2584
2745
 
2585
- | Parameter | Type |
2586
- | ------------------- | ----------------------------------------------- |
2587
- | `address` | `"/g_queryTree"` |
2588
- | ...`groupFlagPairs` | \[[`NodeID`](#nodeid), `number`, `...NodeID[]`] |
2746
+ | Parameter | Type |
2747
+ | ------------------- | ------------------------------------ |
2748
+ | `address` | `"/g_queryTree"` |
2749
+ | ...`groupFlagPairs` | \[`number`, `number`, `...number[]`] |
2589
2750
 
2590
2751
  ###### Returns
2591
2752
 
@@ -2602,7 +2763,7 @@ Send a command to a specific UGen instance within a synth. The command name and
2602
2763
  | Parameter | Type |
2603
2764
  | ----------- | ---------------------- |
2604
2765
  | `address` | `"/u_cmd"` |
2605
- | `nodeID` | [`NodeID`](#nodeid) |
2766
+ | `nodeID` | `number` |
2606
2767
  | `ugenIndex` | `number` |
2607
2768
  | `command` | `string` |
2608
2769
  | ...`args` | [`OscArg`](#oscarg)\[] |
@@ -2978,7 +3139,7 @@ Plain JS values are mapped to OSC types automatically:
2978
3139
  * `boolean` → `T` / `F`
2979
3140
  * `Uint8Array` / `ArrayBuffer` → `b` (blob)
2980
3141
 
2981
- For 64-bit, timetag, or UUID types, use the tagged object form:
3142
+ For 64-bit or timetag types, use the tagged object form:
2982
3143
 
2983
3144
  ```ts
2984
3145
  { type: 'int', value: 42 }
@@ -2989,7 +3150,6 @@ For 64-bit, timetag, or UUID types, use the tagged object form:
2989
3150
  { type: 'int64', value: 9007199254740992n }
2990
3151
  { type: 'double', value: 3.141592653589793 }
2991
3152
  { type: 'timetag', value: ntpTimestamp }
2992
- { type: 'uuid', value: new Uint8Array(16) }
2993
3153
  ```
2994
3154
 
2995
3155
  ##### sendOSC()
@@ -3179,21 +3339,27 @@ OscChannel — unified dispatch for sending OSC to the AudioWorklet.
3179
3339
  Obtain a channel via [SuperSonic.createOscChannel](#createoscchannel) on the main thread,
3180
3340
  then transfer it to a Web Worker for direct communication with the AudioWorklet.
3181
3341
 
3182
- | Member | Description |
3183
- | --------------------------------------------- | ------------------------------------------------------------------------------- |
3184
- | [`getCurrentNTP`](#getcurrentntp) | Set the NTP time source for classification (used in AudioWorklet context). |
3185
- | [`mode`](#mode) | Transport mode this channel is using. |
3186
- | [`transferable`](#transferable) | Serializable config for transferring this channel to a worker via postMessage. |
3187
- | [`transferList`](#transferlist) | Array of transferable objects (MessagePorts) for the postMessage transfer list. |
3188
- | [`classify()`](#classify) | Classify an OSC message to determine its routing. |
3189
- | [`close()`](#close) | Close the channel and release its ports. |
3190
- | [`getAndResetMetrics()`](#getandresetmetrics) | Get and reset local metrics (for periodic reporting). |
3191
- | [`getMetrics()`](#getmetrics) | Get current metrics snapshot. |
3192
- | [`nextNodeId()`](#nextnodeid) | Get the next unique node ID. |
3193
- | [`send()`](#send) | Send an OSC message with automatic routing. |
3194
- | [`sendDirect()`](#senddirect) | Send directly to worklet without classification or metrics tracking. |
3195
- | [`sendToPrescheduler()`](#sendtoprescheduler) | Send to prescheduler without classification. |
3196
- | [`fromTransferable()`](#fromtransferable) | Reconstruct an OscChannel from data received via postMessage in a worker. |
3342
+ | Member | Description |
3343
+ | --------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
3344
+ | [`getCurrentNTP`](#getcurrentntp) | Set the NTP time source for classification (used in AudioWorklet context). |
3345
+ | [`mode`](#mode) | Transport mode this channel is using. |
3346
+ | [`replyDrops`](#replydrops) | Number of reply messages dropped because the reply buffer was full. |
3347
+ | [`transferable`](#transferable) | Serializable config for transferring this channel to a worker via postMessage. |
3348
+ | [`transferList`](#transferlist) | Array of transferable objects (MessagePorts) for the postMessage transfer list. |
3349
+ | [`activateReplies()`](#activatereplies) | Activate the reply slot without registering a handler. |
3350
+ | [`classify()`](#classify) | Classify an OSC message to determine its routing. |
3351
+ | [`clearReplyHandler()`](#clearreplyhandler) | Clear the reply handler and release the reply channel. |
3352
+ | [`close()`](#close) | Close the channel and release its ports. |
3353
+ | [`deactivateReplies()`](#deactivatereplies) | Release the reply slot. |
3354
+ | [`getAndResetMetrics()`](#getandresetmetrics) | Get and reset local metrics (for periodic reporting). |
3355
+ | [`getMetrics()`](#getmetrics) | Get current metrics snapshot. |
3356
+ | [`nextNodeId()`](#nextnodeid) | Get the next unique node ID. |
3357
+ | [`pollReplies()`](#pollreplies) | Drain pending replies, calling the registered handler (or handler argument, if given) once per message. |
3358
+ | [`send()`](#send) | Send an OSC message with automatic routing. |
3359
+ | [`sendDirect()`](#senddirect) | Send directly to worklet without classification or metrics tracking. |
3360
+ | [`sendToPrescheduler()`](#sendtoprescheduler) | Send to prescheduler without classification. |
3361
+ | [`setReplyHandler()`](#setreplyhandler) | Register a handler for OSC replies from scsynth. |
3362
+ | [`fromTransferable()`](#fromtransferable) | Reconstruct an OscChannel from data received via postMessage in a worker. |
3197
3363
 
3198
3364
  #### Example
3199
3365
 
@@ -3257,6 +3423,20 @@ Transport mode this channel is using.
3257
3423
 
3258
3424
  [`TransportMode`](#transportmode)
3259
3425
 
3426
+ ##### replyDrops
3427
+
3428
+ ###### Get Signature
3429
+
3430
+ > **get** **replyDrops**(): `number`
3431
+
3432
+ Number of reply messages dropped because the reply buffer was full.
3433
+ SAB mode only — undefined in PM mode or before [activateReplies](#activatereplies).
3434
+ Counter resets each time the slot is (re)claimed.
3435
+
3436
+ ###### Returns
3437
+
3438
+ `number`
3439
+
3260
3440
  ##### transferable
3261
3441
 
3262
3442
  ###### Get Signature
@@ -3297,6 +3477,19 @@ worker.postMessage({ ch: channel.transferable }, channel.transferList);
3297
3477
 
3298
3478
  #### Methods
3299
3479
 
3480
+ ##### activateReplies()
3481
+
3482
+ > **activateReplies**(): `void`
3483
+
3484
+ Activate the reply slot without registering a handler. Usually called
3485
+ for you by [setReplyHandler](#setreplyhandler); only call directly if you want to
3486
+ claim the slot before installing a handler (or to use the optional
3487
+ one-shot handler argument of [pollReplies](#pollreplies)).
3488
+
3489
+ ###### Returns
3490
+
3491
+ `void`
3492
+
3300
3493
  ##### classify()
3301
3494
 
3302
3495
  > **classify**(`oscData`): [`OscCategory`](#osccategory)
@@ -3313,6 +3506,16 @@ Classify an OSC message to determine its routing.
3313
3506
 
3314
3507
  [`OscCategory`](#osccategory)
3315
3508
 
3509
+ ##### clearReplyHandler()
3510
+
3511
+ > **clearReplyHandler**(): `void`
3512
+
3513
+ Clear the reply handler and release the reply channel. Idempotent.
3514
+
3515
+ ###### Returns
3516
+
3517
+ `void`
3518
+
3316
3519
  ##### close()
3317
3520
 
3318
3521
  > **close**(): `void`
@@ -3323,6 +3526,16 @@ Close the channel and release its ports.
3323
3526
 
3324
3527
  `void`
3325
3528
 
3529
+ ##### deactivateReplies()
3530
+
3531
+ > **deactivateReplies**(): `void`
3532
+
3533
+ Release the reply slot. Usually called for you by [clearReplyHandler](#clearreplyhandler).
3534
+
3535
+ ###### Returns
3536
+
3537
+ `void`
3538
+
3326
3539
  ##### getAndResetMetrics()
3327
3540
 
3328
3541
  > **getAndResetMetrics**(): [`OscChannelMetrics`](#oscchannelmetrics)
@@ -3359,6 +3572,30 @@ the root group, 1 is the default group, 2–999 are reserved for manual use).
3359
3572
 
3360
3573
  A unique node ID (>= 1000)
3361
3574
 
3575
+ ##### pollReplies()
3576
+
3577
+ > **pollReplies**(`handler?`): `number`
3578
+
3579
+ Drain pending replies, calling the registered handler (or `handler`
3580
+ argument, if given) once per message. Returns the number of messages
3581
+ processed. Zero-allocation on the hot path.
3582
+
3583
+ Call from an AudioWorklet's `process()` method to receive replies on
3584
+ the audio thread. In other contexts automatic delivery already calls
3585
+ this for you.
3586
+
3587
+ ###### Parameters
3588
+
3589
+ | Parameter | Type | Description |
3590
+ | ---------- | ------------------------------------------------------------------------------------------- | ------------------------------------ |
3591
+ | `handler?` | ((`view`, `offset`, `length`, `sequence`) => `void`) \| ((`oscData`, `sequence`) => `void`) | Optional override for this call only |
3592
+
3593
+ ###### Returns
3594
+
3595
+ `number`
3596
+
3597
+ Number of messages drained
3598
+
3362
3599
  ##### send()
3363
3600
 
3364
3601
  > **send**(`oscData`): `boolean`
@@ -3418,6 +3655,40 @@ Send to prescheduler without classification.
3418
3655
 
3419
3656
  true if sent successfully
3420
3657
 
3658
+ ##### setReplyHandler()
3659
+
3660
+ > **setReplyHandler**(`handler`): `void`
3661
+
3662
+ Register a handler for OSC replies from scsynth. Idempotent — replaces
3663
+ any previously-registered handler. In AudioWorklet contexts the worklet
3664
+ must call [pollReplies](#pollreplies) from `process()` to drain; in all other
3665
+ contexts delivery is automatic. All registered channels receive all
3666
+ replies (broadcast); filter locally if you only need specific addresses.
3667
+
3668
+ SAB mode: handler receives `(view, offset, length, sequence)` — zero-copy
3669
+ into the shared buffer. Read bytes from `view[offset..offset+length]`.
3670
+ Data is valid only for the duration of the handler call.
3671
+
3672
+ PM mode: handler receives `(oscData, sequence)` where `oscData` is a copy.
3673
+
3674
+ ###### Parameters
3675
+
3676
+ | Parameter | Type |
3677
+ | --------- | ------------------------------------------------------------------------------------------- |
3678
+ | `handler` | ((`view`, `offset`, `length`, `sequence`) => `void`) \| ((`oscData`, `sequence`) => `void`) |
3679
+
3680
+ ###### Returns
3681
+
3682
+ `void`
3683
+
3684
+ ###### Example
3685
+
3686
+ ```ts
3687
+ channel.setReplyHandler((view, offset, length, sequence) => {
3688
+ // SAB: read raw OSC bytes from view[offset..offset+length]
3689
+ });
3690
+ ```
3691
+
3421
3692
  ##### fromTransferable()
3422
3693
 
3423
3694
  > `static` **fromTransferable**(`data`): [`OscChannel`](#oscchannel)