supersonic-scsynth 0.66.0 → 0.68.1

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