supersonic-scsynth 0.6.6 → 0.7.0
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 +45 -173
- package/dist/supersonic.js +4 -7
- package/dist/wasm/manifest.json +3 -3
- package/dist/wasm/scsynth-nrt.wasm +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,214 +1,86 @@
|
|
|
1
|
-
|
|
1
|
+
> **Note: Alpha Status**: SuperSonic is in active development. The API may evolve, but the core synthesis engine is solid and ready for experimentation. Feedback and ideas are most welcome.
|
|
2
2
|
|
|
3
|
-
> **Warning - Super Alpha Status**: SuperSonic is currently in active development. The API is likely to change between releases. Feedback welcome!
|
|
4
|
-
|
|
5
|
-
A WebAssembly port of SuperCollider's scsynth audio synthesis engine for the browser. Runs in an AudioWorklet for real-time, high-priority audio processing with full OSC API support.
|
|
6
|
-
|
|
7
|
-
## Quick Start
|
|
8
|
-
|
|
9
|
-
```html
|
|
10
|
-
<script type="module">
|
|
11
|
-
import { SuperSonic } from './dist/supersonic.js';
|
|
12
|
-
|
|
13
|
-
const sonic = new SuperSonic({
|
|
14
|
-
workerBaseURL: './dist/workers/',
|
|
15
|
-
wasmBaseURL: './dist/wasm/',
|
|
16
|
-
sampleBaseURL: './dist/samples/',
|
|
17
|
-
synthdefBaseURL: './dist/synthdefs/'
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
await sonic.init();
|
|
21
|
-
|
|
22
|
-
// Load a synthdef
|
|
23
|
-
await sonic.loadSynthDefs(['sonic-pi-beep']);
|
|
24
|
-
|
|
25
|
-
// Trigger the synth
|
|
26
|
-
sonic.send('/s_new', 'sonic-pi-beep', -1, 0, 0, 'note', 60);
|
|
27
|
-
|
|
28
|
-
// Load and play a sample
|
|
29
|
-
sonic.send('/b_allocRead', 0, 'bd_haus.flac');
|
|
30
|
-
sonic.send('/s_new', 'sonic-pi-basic_mono_player', -1, 0, 0, 'buf', 0);
|
|
31
|
-
</script>
|
|
32
3
|
```
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
## Installation
|
|
37
|
-
|
|
38
|
-
**Via npm (for local bundling):**
|
|
39
|
-
```bash
|
|
40
|
-
# Core engine only (~450KB)
|
|
41
|
-
npm install supersonic-scsynth
|
|
42
|
-
|
|
43
|
-
# Everything (engine + synthdefs + samples)
|
|
44
|
-
npm install supersonic-scsynth-bundle
|
|
4
|
+
░█▀▀░█░█░█▀█░█▀▀░█▀▄░█▀▀░█▀█░█▀█░▀█▀░█▀▀
|
|
5
|
+
░▀▀█░█░█░█▀▀░█▀▀░█▀▄░▀▀█░█░█░█░█░░█░░█░░
|
|
6
|
+
░▀▀▀░▀▀▀░▀░░░▀▀▀░▀░▀░▀▀▀░▀▀▀░▀░▀░▀▀▀░▀▀▀
|
|
45
7
|
```
|
|
46
8
|
|
|
47
|
-
**
|
|
48
|
-
Download the pre-built package (~35MB with all synthdefs and samples) and serve from your own domain:
|
|
49
|
-
https://samaaron.github.io/supersonic/supersonic-dist.zip
|
|
50
|
-
|
|
51
|
-
Extract to your web server and import as:
|
|
52
|
-
```javascript
|
|
53
|
-
import { SuperSonic } from './dist/supersonic.js';
|
|
54
|
-
```
|
|
9
|
+
**SuperSonic** - [SuperCollider](https://supercollider.github.io/)'s powerful audio synthesis engine scsynth running in the browser as an [AudioWorklet](https://developer.mozilla.org/en-US/docs/Web/API/AudioWorklet).
|
|
55
10
|
|
|
56
|
-
|
|
11
|
+
- _AudioWorklet_ - runs in a dedicated high priority audio thread
|
|
12
|
+
- _WebAssembly_ - scsynth's C++ code compiled for the web
|
|
13
|
+
- _OSC API_ - talk to the scsynth server through its native OSC API
|
|
57
14
|
|
|
58
|
-
|
|
15
|
+
**[Try the live demo](https://sonic-pi.net/supersonic/demo.html)**
|
|
59
16
|
|
|
60
|
-
|
|
61
|
-
|---------|------|---------|----------|
|
|
62
|
-
| `supersonic-scsynth` | ~450KB | GPL-3.0-or-later | Core WASM engine |
|
|
63
|
-
| `supersonic-scsynth-synthdefs` | ~67KB | MIT | 120 Sonic Pi synthdefs |
|
|
64
|
-
| `supersonic-scsynth-samples` | ~34MB | CC0-1.0 | 206 Sonic Pi samples |
|
|
65
|
-
| `supersonic-scsynth-bundle` | - | - | All of the above |
|
|
17
|
+
## Getting Started
|
|
66
18
|
|
|
67
|
-
|
|
19
|
+
Injecting the full power of SuperCollider's scsynth audio engine into your browser is simple.
|
|
68
20
|
|
|
69
|
-
|
|
21
|
+
Import SuperSonic and initialise it:
|
|
70
22
|
|
|
71
|
-
**Creating an instance:**
|
|
72
23
|
```javascript
|
|
24
|
+
import { SuperSonic } from "supersonic-scsynth";
|
|
25
|
+
|
|
26
|
+
const baseURL = "/supersonic"; // Configure for your setup
|
|
73
27
|
const sonic = new SuperSonic({
|
|
74
|
-
workerBaseURL:
|
|
75
|
-
wasmBaseURL:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
audioPathMap: { /* optional custom path mappings */ }
|
|
28
|
+
workerBaseURL: `${baseURL}/workers/`,
|
|
29
|
+
wasmBaseURL: `${baseURL}/wasm/`,
|
|
30
|
+
synthdefBaseURL: `${baseURL}/synthdefs/`,
|
|
31
|
+
sampleBaseURL: `${baseURL}/samples/`,
|
|
79
32
|
});
|
|
33
|
+
await sonic.init();
|
|
80
34
|
```
|
|
81
35
|
|
|
82
|
-
|
|
83
|
-
- `await sonic.init()` - Initialize the audio engine
|
|
84
|
-
- `await sonic.loadSynthDefs(names)` - Load synth definitions
|
|
85
|
-
- `sonic.send(address, ...args)` - Send OSC message (types auto-detected)
|
|
86
|
-
- `sonic.sendOSC(oscBytes, options)` - Send pre-encoded OSC bytes
|
|
87
|
-
|
|
88
|
-
**Callbacks:**
|
|
89
|
-
- `sonic.onInitialized` - Called when ready
|
|
90
|
-
- `sonic.onError(error)` - Error handling
|
|
91
|
-
- `sonic.onMessageReceived(msg)` - Incoming OSC messages
|
|
92
|
-
- `sonic.onMessageSent(oscData)` - Outgoing OSC messages
|
|
36
|
+
Load and play a synth:
|
|
93
37
|
|
|
94
|
-
**Common OSC commands:**
|
|
95
38
|
```javascript
|
|
96
|
-
sonic.
|
|
97
|
-
sonic.send(
|
|
98
|
-
sonic.send('/n_set', 1000, 'freq', 440.0, 'amp', 0.5); // Set parameters
|
|
99
|
-
sonic.send('/n_free', 1000); // Free node
|
|
100
|
-
sonic.send('/b_allocRead', 0, 'sample.flac'); // Load audio buffer
|
|
39
|
+
await sonic.loadSynthDef("sonic-pi-prophet");
|
|
40
|
+
sonic.send("/s_new", "sonic-pi-prophet", -1, 0, 0, "note", 60);
|
|
101
41
|
```
|
|
102
42
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
## Browser Requirements
|
|
106
|
-
|
|
107
|
-
**Minimum browser versions:**
|
|
108
|
-
- Chrome/Edge 92+
|
|
109
|
-
- Firefox 79+
|
|
110
|
-
- Safari 15.2+
|
|
111
|
-
|
|
112
|
-
**Required features:**
|
|
113
|
-
- SharedArrayBuffer (requires COOP/COEP headers)
|
|
114
|
-
- AudioWorklet
|
|
115
|
-
- WebAssembly with threads
|
|
116
|
-
|
|
117
|
-
**Required HTTP headers:**
|
|
118
|
-
Your server must send these headers for SharedArrayBuffer support:
|
|
119
|
-
|
|
120
|
-
```
|
|
121
|
-
Cross-Origin-Opener-Policy: same-origin
|
|
122
|
-
Cross-Origin-Embedder-Policy: require-corp
|
|
123
|
-
Cross-Origin-Resource-Policy: cross-origin
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
See `example/server.rb` for a reference implementation.
|
|
127
|
-
|
|
128
|
-
## CDN Usage
|
|
129
|
-
|
|
130
|
-
SuperSonic cannot be loaded from a CDN. The core library must be self-hosted on your domain.
|
|
131
|
-
|
|
132
|
-
### Why Self-Hosting is Required
|
|
133
|
-
|
|
134
|
-
SuperSonic uses `SharedArrayBuffer` for real-time audio performance. Browsers require workers that use `SharedArrayBuffer` to come from the same origin as the page. Even with proper COOP/COEP headers, cross-origin workers with shared memory are blocked. This is a fundamental browser security requirement stemming from Spectre attack mitigation.
|
|
135
|
-
|
|
136
|
-
What this means:
|
|
137
|
-
- You cannot use `import { SuperSonic } from 'https://unpkg.com/supersonic/...'`
|
|
138
|
-
- You must download and self-host the core library on your own domain
|
|
139
|
-
- The npm packages exist for convenience but must be bundled and deployed to your server
|
|
140
|
-
|
|
141
|
-
### Synthdefs and Samples Can Use CDN
|
|
142
|
-
|
|
143
|
-
Pre-compiled synthdefs and audio samples can be loaded from CDNs. They're just data files, not workers.
|
|
43
|
+
Load and play a sample:
|
|
144
44
|
|
|
145
45
|
```javascript
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
// CDN-hosted synthdefs and samples work fine
|
|
150
|
-
const sonic = new SuperSonic({
|
|
151
|
-
workerBaseURL: './dist/workers/', // Must be self-hosted
|
|
152
|
-
wasmBaseURL: './dist/wasm/', // Must be self-hosted
|
|
153
|
-
sampleBaseURL: 'https://unpkg.com/supersonic-scsynth-samples@0.1.6/samples/',
|
|
154
|
-
synthdefBaseURL: 'https://unpkg.com/supersonic-scsynth-synthdefs@0.1.6/synthdefs/'
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
await sonic.init();
|
|
158
|
-
await sonic.loadSynthDefs(['sonic-pi-beep', 'sonic-pi-tb303']);
|
|
46
|
+
await sonic.loadSynthDef("sonic-pi-basic_stereo_player");
|
|
47
|
+
await sonic.loadSample(0, "loop_amen.flac");
|
|
48
|
+
sonic.send("/s_new", "sonic-pi-basic_stereo_player", -1, 0, 0, "buf", 0);
|
|
159
49
|
```
|
|
160
50
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
Self-host the SuperSonic core (JS, WASM, workers) with COOP/COEP headers. Use CDN for synthdefs and samples to save bandwidth. See `example/simple-cdn.html` for a working example.
|
|
51
|
+
Take a look at `example/simple.html` for a minimal working example.
|
|
164
52
|
|
|
165
|
-
##
|
|
53
|
+
## Installation
|
|
166
54
|
|
|
167
|
-
|
|
168
|
-
- [Emscripten SDK](https://emscripten.org/docs/getting_started/downloads.html)
|
|
169
|
-
- [esbuild](https://esbuild.github.io/)
|
|
55
|
+
Grab the latest pre-built distribution and host it on your server:
|
|
170
56
|
|
|
171
|
-
**Build:**
|
|
172
57
|
```bash
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
# Compile and bundle
|
|
177
|
-
./build.sh
|
|
58
|
+
curl -O https://samaaron.github.io/supersonic/supersonic-dist.zip
|
|
59
|
+
unzip supersonic-dist.zip
|
|
178
60
|
```
|
|
179
61
|
|
|
180
|
-
|
|
62
|
+
Or install via npm:
|
|
181
63
|
|
|
182
|
-
**Run demo:**
|
|
183
64
|
```bash
|
|
184
|
-
|
|
65
|
+
npm install supersonic-scsynth-bundle
|
|
185
66
|
```
|
|
186
67
|
|
|
187
|
-
|
|
68
|
+
**Note:** SuperSonic must be self-hosted due to browser security requirements around SharedArrayBuffer. It cannot be loaded from a CDN. See [Browser Setup](docs/BROWSER_SETUP.md) for the details.
|
|
188
69
|
|
|
189
|
-
|
|
190
|
-
```bash
|
|
191
|
-
docker build -t supersonic .
|
|
192
|
-
docker run --rm -it -p 8002:8002 supersonic
|
|
193
|
-
```
|
|
70
|
+
## Documentation
|
|
194
71
|
|
|
195
|
-
|
|
72
|
+
- [API Reference](docs/API.md) - Methods, callbacks, and configuration
|
|
73
|
+
- [Metrics](docs/METRICS.md) - Performance monitoring and debugging
|
|
74
|
+
- [Browser Setup](docs/BROWSER_SETUP.md) - Required headers and browser requirements
|
|
75
|
+
- [CDN and Self-Hosting](docs/CDN.md) - Why self-hosting is required
|
|
76
|
+
- [Building from Source](docs/BUILDING.md) - Compiling the WASM yourself
|
|
196
77
|
|
|
197
|
-
|
|
78
|
+
## Support
|
|
198
79
|
|
|
199
|
-
|
|
200
|
-
dist/
|
|
201
|
-
├── supersonic.js # Main entry point (ES module)
|
|
202
|
-
├── wasm/
|
|
203
|
-
│ └── scsynth-nrt.wasm # Audio engine (~1.5MB)
|
|
204
|
-
└── workers/
|
|
205
|
-
├── scsynth_audio_worklet.js # AudioWorklet processor
|
|
206
|
-
├── osc_in_worker.js # OSC input handler
|
|
207
|
-
├── osc_out_prescheduler_worker.js # OSC pre-scheduler (timers & tag cancellation)
|
|
208
|
-
└── debug_worker.js # Debug logger
|
|
209
|
-
```
|
|
80
|
+
SuperSonic is brought to you by Sam Aaron. Please consider joining the community of supporters enabling Sam's work on creative coding projects like this, [Sonic Pi](https://sonic-pi.net) and [Tau5](https://tau5.live).
|
|
210
81
|
|
|
211
|
-
|
|
82
|
+
- [Patreon](https://patreon.com/samaaron)
|
|
83
|
+
- [GitHub Sponsors](https://github.com/sponsors/samaaron)
|
|
212
84
|
|
|
213
85
|
## License
|
|
214
86
|
|
package/dist/supersonic.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
var n={},n=n||{};(function(){"use strict";n.SECS_70YRS=2208988800,n.TWO_32=4294967296,n.defaults={metadata:!1,unpackSingleArgs:!0},n.isCommonJS=!!(typeof module<"u"&&module.exports),n.isNode=n.isCommonJS&&typeof window>"u",n.isElectron=!!(typeof process<"u"&&process.versions&&process.versions.electron),n.isBufferEnv=n.isNode||n.isElectron,n.isArray=function(s){return s&&Object.prototype.toString.call(s)==="[object Array]"},n.isTypedArrayView=function(s){return s.buffer&&s.buffer instanceof ArrayBuffer},n.isBuffer=function(s){return n.isBufferEnv&&s instanceof Buffer},n.Long=typeof Long<"u"?Long:void 0,n.TextDecoder=typeof TextDecoder<"u"?new TextDecoder("utf-8"):typeof util<"u"&&typeof(util.TextDecoder!=="undefined")?new util.TextDecoder("utf-8"):void 0,n.TextEncoder=typeof TextEncoder<"u"?new TextEncoder("utf-8"):typeof util<"u"&&typeof(util.TextEncoder!=="undefined")?new util.TextEncoder("utf-8"):void 0,n.dataView=function(s,e,t){return s.buffer?new DataView(s.buffer,e,t):s instanceof ArrayBuffer?new DataView(s,e,t):new DataView(new Uint8Array(s),e,t)},n.byteArray=function(s){if(s instanceof Uint8Array)return s;var e=s.buffer?s.buffer:s;if(!(e instanceof ArrayBuffer)&&(typeof e.length>"u"||typeof e=="string"))throw new Error("Can't wrap a non-array-like object as Uint8Array. Object was: "+JSON.stringify(s,null,2));return new Uint8Array(e)},n.nativeBuffer=function(s){return n.isBufferEnv?n.isBuffer(s)?s:Buffer.from(s.buffer?s:new Uint8Array(s)):n.isTypedArrayView(s)?s:new Uint8Array(s)},n.copyByteArray=function(s,e,t){if(n.isTypedArrayView(s)&&n.isTypedArrayView(e))e.set(s,t);else for(var r=t===void 0?0:t,i=Math.min(e.length-t,s.length),o=0,a=r;o<i;o++,a++)e[a]=s[o];return e},n.readString=function(s,e){for(var t=[],r=e.idx;r<s.byteLength;r++){var i=s.getUint8(r);if(i!==0)t.push(i);else{r++;break}}r=r+3&-4,e.idx=r;var o=n.isBufferEnv?n.readString.withBuffer:n.TextDecoder?n.readString.withTextDecoder:n.readString.raw;return o(t)},n.readString.raw=function(s){for(var e="",t=1e4,r=0;r<s.length;r+=t)e+=String.fromCharCode.apply(null,s.slice(r,r+t));return e},n.readString.withTextDecoder=function(s){var e=new Int8Array(s);return n.TextDecoder.decode(e)},n.readString.withBuffer=function(s){return Buffer.from(s).toString("utf-8")},n.writeString=function(s){var e=n.isBufferEnv?n.writeString.withBuffer:n.TextEncoder?n.writeString.withTextEncoder:null,t=s+"\0",r;e&&(r=e(t));for(var i=e?r.length:t.length,o=i+3&-4,a=new Uint8Array(o),c=0;c<i-1;c++){var l=e?r[c]:t.charCodeAt(c);a[c]=l}return a},n.writeString.withTextEncoder=function(s){return n.TextEncoder.encode(s)},n.writeString.withBuffer=function(s){return Buffer.from(s)},n.readPrimitive=function(s,e,t,r){var i=s[e](r.idx,!1);return r.idx+=t,i},n.writePrimitive=function(s,e,t,r,i){i=i===void 0?0:i;var o;return e?o=new Uint8Array(e.buffer):(o=new Uint8Array(r),e=new DataView(o.buffer)),e[t](i,s,!1),o},n.readInt32=function(s,e){return n.readPrimitive(s,"getInt32",4,e)},n.writeInt32=function(s,e,t){return n.writePrimitive(s,e,"setInt32",4,t)},n.readInt64=function(s,e){var t=n.readPrimitive(s,"getInt32",4,e),r=n.readPrimitive(s,"getInt32",4,e);return n.Long?new n.Long(r,t):{high:t,low:r,unsigned:!1}},n.writeInt64=function(s,e,t){var r=new Uint8Array(8);return r.set(n.writePrimitive(s.high,e,"setInt32",4,t),0),r.set(n.writePrimitive(s.low,e,"setInt32",4,t+4),4),r},n.readFloat32=function(s,e){return n.readPrimitive(s,"getFloat32",4,e)},n.writeFloat32=function(s,e,t){return n.writePrimitive(s,e,"setFloat32",4,t)},n.readFloat64=function(s,e){return n.readPrimitive(s,"getFloat64",8,e)},n.writeFloat64=function(s,e,t){return n.writePrimitive(s,e,"setFloat64",8,t)},n.readChar32=function(s,e){var t=n.readPrimitive(s,"getUint32",4,e);return String.fromCharCode(t)},n.writeChar32=function(s,e,t){var r=s.charCodeAt(0);if(!(r===void 0||r<-1))return n.writePrimitive(r,e,"setUint32",4,t)},n.readBlob=function(s,e){var t=n.readInt32(s,e),r=t+3&-4,i=new Uint8Array(s.buffer,e.idx,t);return e.idx+=r,i},n.writeBlob=function(s){s=n.byteArray(s);var e=s.byteLength,t=e+3&-4,r=4,i=t+r,o=new Uint8Array(i),a=new DataView(o.buffer);return n.writeInt32(e,a),o.set(s,r),o},n.readMIDIBytes=function(s,e){var t=new Uint8Array(s.buffer,e.idx,4);return e.idx+=4,t},n.writeMIDIBytes=function(s){s=n.byteArray(s);var e=new Uint8Array(4);return e.set(s),e},n.readColor=function(s,e){var t=new Uint8Array(s.buffer,e.idx,4),r=t[3]/255;return e.idx+=4,{r:t[0],g:t[1],b:t[2],a:r}},n.writeColor=function(s){var e=Math.round(s.a*255),t=new Uint8Array([s.r,s.g,s.b,e]);return t},n.readTrue=function(){return!0},n.readFalse=function(){return!1},n.readNull=function(){return null},n.readImpulse=function(){return 1},n.readTimeTag=function(s,e){var t=n.readPrimitive(s,"getUint32",4,e),r=n.readPrimitive(s,"getUint32",4,e),i=t===0&&r===1?Date.now():n.ntpToJSTime(t,r);return{raw:[t,r],native:i}},n.writeTimeTag=function(s){var e=s.raw?s.raw:n.jsToNTPTime(s.native),t=new Uint8Array(8),r=new DataView(t.buffer);return n.writeInt32(e[0],r,0),n.writeInt32(e[1],r,4),t},n.timeTag=function(s,e){s=s||0,e=e||Date.now();var t=e/1e3,r=Math.floor(t),i=t-r,o=Math.floor(s),a=s-o,c=i+a;if(c>1){var l=Math.floor(c),u=c-l;o+=l,c=u}var f=r+o+n.SECS_70YRS,h=Math.round(n.TWO_32*c);return{raw:[f,h]}},n.ntpToJSTime=function(s,e){var t=s-n.SECS_70YRS,r=e/n.TWO_32,i=(t+r)*1e3;return i},n.jsToNTPTime=function(s){var e=s/1e3,t=Math.floor(e),r=e-t,i=t+n.SECS_70YRS,o=Math.round(n.TWO_32*r);return[i,o]},n.readArguments=function(s,e,t){var r=n.readString(s,t);if(r.indexOf(",")!==0)throw new Error("A malformed type tag string was found while reading the arguments of an OSC message. String was: "+r," at offset: "+t.idx);var i=r.substring(1).split(""),o=[];return n.readArgumentsIntoArray(o,i,r,s,e,t),o},n.readArgument=function(s,e,t,r,i){var o=n.argumentTypes[s];if(!o)throw new Error("'"+s+"' is not a valid OSC type tag. Type tag string was: "+e);var a=o.reader,c=n[a](t,i);return r.metadata&&(c={type:s,value:c}),c},n.readArgumentsIntoArray=function(s,e,t,r,i,o){for(var a=0;a<e.length;){var c=e[a],l;if(c==="["){var u=e.slice(a+1),f=u.indexOf("]");if(f<0)throw new Error("Invalid argument type tag: an open array type tag ('[') was found without a matching close array tag ('[]'). Type tag was: "+t);var h=u.slice(0,f);l=n.readArgumentsIntoArray([],h,t,r,i,o),a+=f+2}else l=n.readArgument(c,t,r,i,o),a++;s.push(l)}return s},n.writeArguments=function(s,e){var t=n.collectArguments(s,e);return n.joinParts(t)},n.joinParts=function(s){for(var e=new Uint8Array(s.byteLength),t=s.parts,r=0,i=0;i<t.length;i++){var o=t[i];n.copyByteArray(o,e,r),r+=o.length}return e},n.addDataPart=function(s,e){e.parts.push(s),e.byteLength+=s.length},n.writeArrayArguments=function(s,e){for(var t="[",r=0;r<s.length;r++){var i=s[r];t+=n.writeArgument(i,e)}return t+="]",t},n.writeArgument=function(s,e){if(n.isArray(s))return n.writeArrayArguments(s,e);var t=s.type,r=n.argumentTypes[t].writer;if(r){var i=n[r](s.value);n.addDataPart(i,e)}return s.type},n.collectArguments=function(s,e,t){n.isArray(s)||(s=typeof s>"u"?[]:[s]),t=t||{byteLength:0,parts:[]},e.metadata||(s=n.annotateArguments(s));for(var r=",",i=t.parts.length,o=0;o<s.length;o++){var a=s[o];r+=n.writeArgument(a,t)}var c=n.writeString(r);return t.byteLength+=c.byteLength,t.parts.splice(i,0,c),t},n.readMessage=function(s,e,t){e=e||n.defaults;var r=n.dataView(s,s.byteOffset,s.byteLength);t=t||{idx:0};var i=n.readString(r,t);return n.readMessageContents(i,r,e,t)},n.readMessageContents=function(s,e,t,r){if(s.indexOf("/")!==0)throw new Error("A malformed OSC address was found while reading an OSC message. String was: "+s);var i=n.readArguments(e,t,r);return{address:s,args:i.length===1&&t.unpackSingleArgs?i[0]:i}},n.collectMessageParts=function(s,e,t){return t=t||{byteLength:0,parts:[]},n.addDataPart(n.writeString(s.address),t),n.collectArguments(s.args,e,t)},n.writeMessage=function(s,e){if(e=e||n.defaults,!n.isValidMessage(s))throw new Error("An OSC message must contain a valid address. Message was: "+JSON.stringify(s,null,2));var t=n.collectMessageParts(s,e);return n.joinParts(t)},n.isValidMessage=function(s){return s.address&&s.address.indexOf("/")===0},n.readBundle=function(s,e,t){return n.readPacket(s,e,t)},n.collectBundlePackets=function(s,e,t){t=t||{byteLength:0,parts:[]},n.addDataPart(n.writeString("#bundle"),t),n.addDataPart(n.writeTimeTag(s.timeTag),t);for(var r=0;r<s.packets.length;r++){var i=s.packets[r],o=i.address?n.collectMessageParts:n.collectBundlePackets,a=o(i,e);t.byteLength+=a.byteLength,n.addDataPart(n.writeInt32(a.byteLength),t),t.parts=t.parts.concat(a.parts)}return t},n.writeBundle=function(s,e){if(!n.isValidBundle(s))throw new Error("An OSC bundle must contain 'timeTag' and 'packets' properties. Bundle was: "+JSON.stringify(s,null,2));e=e||n.defaults;var t=n.collectBundlePackets(s,e);return n.joinParts(t)},n.isValidBundle=function(s){return s.timeTag!==void 0&&s.packets!==void 0},n.readBundleContents=function(s,e,t,r){for(var i=n.readTimeTag(s,t),o=[];t.idx<r;){var a=n.readInt32(s,t),c=t.idx+a,l=n.readPacket(s,e,t,c);o.push(l)}return{timeTag:i,packets:o}},n.readPacket=function(s,e,t,r){var i=n.dataView(s,s.byteOffset,s.byteLength);r=r===void 0?i.byteLength:r,t=t||{idx:0};var o=n.readString(i,t),a=o[0];if(a==="#")return n.readBundleContents(i,e,t,r);if(a==="/")return n.readMessageContents(o,i,e,t);throw new Error("The header of an OSC packet didn't contain an OSC address or a #bundle string. Header was: "+o)},n.writePacket=function(s,e){if(n.isValidMessage(s))return n.writeMessage(s,e);if(n.isValidBundle(s))return n.writeBundle(s,e);throw new Error("The specified packet was not recognized as a valid OSC message or bundle. Packet was: "+JSON.stringify(s,null,2))},n.argumentTypes={i:{reader:"readInt32",writer:"writeInt32"},h:{reader:"readInt64",writer:"writeInt64"},f:{reader:"readFloat32",writer:"writeFloat32"},s:{reader:"readString",writer:"writeString"},S:{reader:"readString",writer:"writeString"},b:{reader:"readBlob",writer:"writeBlob"},t:{reader:"readTimeTag",writer:"writeTimeTag"},T:{reader:"readTrue"},F:{reader:"readFalse"},N:{reader:"readNull"},I:{reader:"readImpulse"},d:{reader:"readFloat64",writer:"writeFloat64"},c:{reader:"readChar32",writer:"writeChar32"},r:{reader:"readColor",writer:"writeColor"},m:{reader:"readMIDIBytes",writer:"writeMIDIBytes"}},n.inferTypeForArgument=function(s){var e=typeof s;switch(e){case"boolean":return s?"T":"F";case"string":return"s";case"number":return"f";case"undefined":return"N";case"object":if(s===null)return"N";if(s instanceof Uint8Array||s instanceof ArrayBuffer)return"b";if(typeof s.high=="number"&&typeof s.low=="number")return"h";break}throw new Error("Can't infer OSC argument type for value: "+JSON.stringify(s,null,2))},n.annotateArguments=function(s){for(var e=[],t=0;t<s.length;t++){var r=s[t],i;if(typeof r=="object"&&r.type&&r.value!==void 0)i=r;else if(n.isArray(r))i=n.annotateArguments(r);else{var o=n.inferTypeForArgument(r);i={type:o,value:r}}e.push(i)}return e}})();var b=function(){};b.prototype.on=function(){};b.prototype.emit=function(){};b.prototype.removeListener=function(){};(function(){"use strict";n.supportsSerial=!1,n.firePacketEvents=function(e,t,r,i){t.address?e.emit("message",t,r,i):n.fireBundleEvents(e,t,r,i)},n.fireBundleEvents=function(e,t,r,i){e.emit("bundle",t,r,i);for(var o=0;o<t.packets.length;o++){var a=t.packets[o];n.firePacketEvents(e,a,t.timeTag,i)}},n.fireClosedPortSendError=function(e,t){t=t||"Can't send packets on a closed osc.Port object. Please open (or reopen) this Port by calling open().",e.emit("error",t)},n.Port=function(e){this.options=e||{},this.on("data",this.decodeOSC.bind(this))};var s=n.Port.prototype=Object.create(b.prototype);s.constructor=n.Port,s.send=function(e){var t=Array.prototype.slice.call(arguments),r=this.encodeOSC(e),i=n.nativeBuffer(r);t[0]=i,this.sendRaw.apply(this,t)},s.encodeOSC=function(e){e=e.buffer?e.buffer:e;var t;try{t=n.writePacket(e,this.options)}catch(r){this.emit("error",r)}return t},s.decodeOSC=function(e,t){e=n.byteArray(e),this.emit("raw",e,t);try{var r=n.readPacket(e,this.options);this.emit("osc",r,t),n.firePacketEvents(this,r,void 0,t)}catch(i){this.emit("error",i)}},n.SLIPPort=function(e){var t=this,r=this.options=e||{};r.useSLIP=r.useSLIP===void 0?!0:r.useSLIP,this.decoder=new slip.Decoder({onMessage:this.decodeOSC.bind(this),onError:function(o){t.emit("error",o)}});var i=r.useSLIP?this.decodeSLIPData:this.decodeOSC;this.on("data",i.bind(this))},s=n.SLIPPort.prototype=Object.create(n.Port.prototype),s.constructor=n.SLIPPort,s.encodeOSC=function(e){e=e.buffer?e.buffer:e;var t;try{var r=n.writePacket(e,this.options);t=slip.encode(r)}catch(i){this.emit("error",i)}return t},s.decodeSLIPData=function(e,t){this.decoder.decode(e,t)},n.relay=function(e,t,r,i,o,a){r=r||"message",i=i||"send",o=o||function(){},a=a?[null].concat(a):[];var c=function(l){a[0]=l,l=o(l),t[i].apply(t,a)};return e.on(r,c),{eventName:r,listener:c}},n.relayPorts=function(e,t,r){var i=r.raw?"raw":"osc",o=r.raw?"sendRaw":"send";return n.relay(e,t,i,o,r.transform)},n.stopRelaying=function(e,t){e.removeListener(t.eventName,t.listener)},n.Relay=function(e,t,r){var i=this.options=r||{};i.raw=!1,this.port1=e,this.port2=t,this.listen()},s=n.Relay.prototype=Object.create(b.prototype),s.constructor=n.Relay,s.open=function(){this.port1.open(),this.port2.open()},s.listen=function(){this.port1Spec&&this.port2Spec&&this.close(),this.port1Spec=n.relayPorts(this.port1,this.port2,this.options),this.port2Spec=n.relayPorts(this.port2,this.port1,this.options);var e=this.close.bind(this);this.port1.on("close",e),this.port2.on("close",e)},s.close=function(){n.stopRelaying(this.port1,this.port1Spec),n.stopRelaying(this.port2,this.port2Spec),this.emit("close",this.port1,this.port2)}})();(function(){"use strict";n.WebSocket=typeof WebSocket<"u"?WebSocket:void 0,n.WebSocketPort=function(e){n.Port.call(this,e),this.on("open",this.listen.bind(this)),this.socket=e.socket,this.socket&&(this.socket.readyState===1?(n.WebSocketPort.setupSocketForBinary(this.socket),this.emit("open",this.socket)):this.open())};var s=n.WebSocketPort.prototype=Object.create(n.Port.prototype);s.constructor=n.WebSocketPort,s.open=function(){(!this.socket||this.socket.readyState>1)&&(this.socket=new n.WebSocket(this.options.url)),n.WebSocketPort.setupSocketForBinary(this.socket);var e=this;this.socket.onopen=function(){e.emit("open",e.socket)},this.socket.onerror=function(t){e.emit("error",t)}},s.listen=function(){var e=this;this.socket.onmessage=function(t){e.emit("data",t.data,t)},this.socket.onclose=function(t){e.emit("close",t)},e.emit("ready")},s.sendRaw=function(e){if(!this.socket||this.socket.readyState!==1){n.fireClosedPortSendError(this);return}this.socket.send(e)},s.close=function(e,t){this.socket.close(e,t)},n.WebSocketPort.setupSocketForBinary=function(e){e.binaryType=n.isNode?"nodebuffer":"arraybuffer"}})();var B=n,{readPacket:Ne,writePacket:Le,readMessage:ze,writeMessage:We,readBundle:Ve,writeBundle:$e}=n;var R=class{constructor(e=null){this.workerBaseURL=e,this.workers={oscOut:null,oscIn:null,debug:null},this.callbacks={onRawOSC:null,onParsedOSC:null,onDebugMessage:null,onError:null,onInitialized:null},this.initialized=!1,this.sharedBuffer=null,this.ringBufferBase=null,this.bufferConstants=null}async init(e,t,r){if(this.initialized){console.warn("[ScsynthOSC] Already initialized");return}this.sharedBuffer=e,this.ringBufferBase=t,this.bufferConstants=r;try{this.workers.oscOut=new Worker(this.workerBaseURL+"osc_out_prescheduler_worker.js",{type:"module"}),this.workers.oscIn=new Worker(this.workerBaseURL+"osc_in_worker.js",{type:"module"}),this.workers.debug=new Worker(this.workerBaseURL+"debug_worker.js",{type:"module"}),this.setupWorkerHandlers();let i=[this.initWorker(this.workers.oscOut,"OSC SCHEDULER+WRITER"),this.initWorker(this.workers.oscIn,"OSC IN"),this.initWorker(this.workers.debug,"DEBUG")];await Promise.all(i),this.workers.oscIn.postMessage({type:"start"}),this.workers.debug.postMessage({type:"start"}),this.initialized=!0,this.callbacks.onInitialized&&this.callbacks.onInitialized()}catch(i){throw console.error("[ScsynthOSC] Initialization failed:",i),this.callbacks.onError&&this.callbacks.onError(i),i}}initWorker(e,t){return new Promise((r,i)=>{let o=setTimeout(()=>{i(new Error(`${t} worker initialization timeout`))},5e3),a=c=>{c.data.type==="initialized"&&(clearTimeout(o),e.removeEventListener("message",a),r())};e.addEventListener("message",a),e.postMessage({type:"init",sharedBuffer:this.sharedBuffer,ringBufferBase:this.ringBufferBase,bufferConstants:this.bufferConstants})})}setupWorkerHandlers(){this.workers.oscIn.onmessage=e=>{let t=e.data;switch(t.type){case"messages":t.messages.forEach(r=>{if(r.oscData&&(this.callbacks.onRawOSC&&this.callbacks.onRawOSC({oscData:r.oscData,sequence:r.sequence}),this.callbacks.onParsedOSC))try{let i={metadata:!1,unpackSingleArgs:!1},o=B.readPacket(r.oscData,i);this.callbacks.onParsedOSC(o)}catch(i){console.error("[ScsynthOSC] Failed to decode OSC message:",i,r)}});break;case"error":console.error("[ScsynthOSC] OSC IN error:",t.error),this.callbacks.onError&&this.callbacks.onError(t.error,"oscIn");break}},this.workers.debug.onmessage=e=>{let t=e.data;switch(t.type){case"debug":this.callbacks.onDebugMessage&&t.messages.forEach(r=>{this.callbacks.onDebugMessage(r)});break;case"error":console.error("[ScsynthOSC] DEBUG error:",t.error),this.callbacks.onError&&this.callbacks.onError(t.error,"debug");break}},this.workers.oscOut.onmessage=e=>{let t=e.data;switch(t.type){case"error":console.error("[ScsynthOSC] OSC OUT error:",t.error),this.callbacks.onError&&this.callbacks.onError(t.error,"oscOut");break}}}send(e,t={}){if(!this.initialized){console.error("[ScsynthOSC] Not initialized");return}let{editorId:r=0,runTag:i="",audioTimeS:o=null,currentTimeS:a=null}=t;this.workers.oscOut.postMessage({type:"send",oscData:e,editorId:r,runTag:i,audioTimeS:o,currentTimeS:a})}sendImmediate(e){if(!this.initialized){console.error("[ScsynthOSC] Not initialized");return}this.workers.oscOut.postMessage({type:"sendImmediate",oscData:e})}cancelEditorTag(e,t){this.initialized&&this.workers.oscOut.postMessage({type:"cancelEditorTag",editorId:e,runTag:t})}cancelEditor(e){this.initialized&&this.workers.oscOut.postMessage({type:"cancelEditor",editorId:e})}cancelAll(){this.initialized&&this.workers.oscOut.postMessage({type:"cancelAll"})}clearDebug(){this.initialized&&this.workers.debug.postMessage({type:"clear"})}onRawOSC(e){this.callbacks.onRawOSC=e}onParsedOSC(e){this.callbacks.onParsedOSC=e}onDebugMessage(e){this.callbacks.onDebugMessage=e}onError(e){this.callbacks.onError=e}onInitialized(e){this.callbacks.onInitialized=e}terminate(){this.workers.oscOut&&(this.workers.oscOut.postMessage({type:"stop"}),this.workers.oscOut.terminate()),this.workers.oscIn&&(this.workers.oscIn.postMessage({type:"stop"}),this.workers.oscIn.terminate()),this.workers.debug&&(this.workers.debug.postMessage({type:"stop"}),this.workers.debug.terminate()),this.workers={oscOut:null,oscIn:null,debug:null},this.initialized=!1}};var ae={5120:"i8",5121:"u8",5122:"i16",5123:"u16",5124:"i32",5125:"u32",5126:"f32"};var z={u8:1,u8c:1,i8:1,u16:2,i16:2,u32:4,i32:4,i64:8,u64:8,f32:4,f64:8};var ce={f32:Float32Array,f64:Float64Array},le={i8:Int8Array,i16:Int16Array,i32:Int32Array},ue={u8:Uint8Array,u8c:Uint8ClampedArray,u16:Uint16Array,u32:Uint32Array},fe={i64:BigInt64Array,u64:BigUint64Array},he={...ce,...le,...ue},de=s=>{let e=ae[s];return e!==void 0?e:s};function W(s,...e){let t=fe[s];return new(t||he[de(s)])(...e)}var I=(s,e)=>(e--,s+e&~e);var V=s=>typeof s=="number";var k=(s,e=t=>t!==void 0?": "+t:"")=>class extends Error{origMessage;constructor(t){super(s(t)+e(t)),this.origMessage=t!==void 0?String(t):""}};var pe=k(()=>"Assertion failed"),D=(typeof process<"u"&&process.env!==void 0?process.env.UMBRELLA_ASSERTS:!import.meta.env||import.meta.env.MODE!=="production"||import.meta.env.UMBRELLA_ASSERTS||import.meta.env.VITE_UMBRELLA_ASSERTS)?(s,e)=>{if(typeof s=="function"&&!s()||!s)throw new pe(typeof e=="function"?e():e)}:()=>{};var me=k(()=>"illegal argument(s)"),$=s=>{throw new me(s)};var G=0,H=1,Z=2,q=3,Y=4,A=5,Q=6,U=1,F=2,j=7*4,x=0,N=1,E=2*4,C=class{buf;start;u8;u32;state;constructor(e={}){if(this.buf=e.buf?e.buf:new ArrayBuffer(e.size||4096),this.start=e.start!=null?I(Math.max(e.start,0),4):0,this.u8=new Uint8Array(this.buf),this.u32=new Uint32Array(this.buf),this.state=new Uint32Array(this.buf,this.start,j/4),!e.skipInitialization){let t=e.align||8;D(t>=8,`invalid alignment: ${t}, must be a pow2 and >= 8`);let r=this.initialTop(t),i=e.end!=null?Math.min(e.end,this.buf.byteLength):this.buf.byteLength;r>=i&&$(`insufficient address range (0x${this.start.toString(16)} - 0x${i.toString(16)})`),this.align=t,this.doCompact=e.compact!==!1,this.doSplit=e.split!==!1,this.minSplit=e.minSplit||16,this.end=i,this.top=r,this._free=0,this._used=0}}stats(){let e=r=>{let i=0,o=0;for(;r;)i++,o+=this.blockSize(r),r=this.blockNext(r);return{count:i,size:o}},t=e(this._free);return{free:t,used:e(this._used),top:this.top,available:this.end-this.top+t.size,total:this.buf.byteLength}}callocAs(e,t,r=0){let i=this.mallocAs(e,t);return i?.fill(r),i}mallocAs(e,t){let r=this.malloc(t*z[e]);return r?W(e,this.buf,r,t):void 0}calloc(e,t=0){let r=this.malloc(e);return r&&this.u8.fill(t,r,r+e),r}malloc(e){if(e<=0)return 0;let t=I(e+E,this.align),r=this.end,i=this.top,o=this._free,a=0;for(;o;){let c=this.blockSize(o),l=o+c>=i;if(l||c>=t)return this.mallocTop(o,a,c,t,l);a=o,o=this.blockNext(o)}return o=i,i=o+t,i<=r?(this.initBlock(o,t,this._used),this._used=o,this.top=i,O(o)):0}mallocTop(e,t,r,i,o){if(o&&e+i>this.end)return 0;if(t?this.unlinkBlock(t,e):this._free=this.blockNext(e),this.setBlockNext(e,this._used),this._used=e,o)this.top=e+this.setBlockSize(e,i);else if(this.doSplit){let a=r-i;a>=this.minSplit&&this.splitBlock(e,i,a)}return O(e)}realloc(e,t){if(t<=0)return 0;let r=L(e),i=0,o=this._used,a=0;for(;o;){if(o===r){[i,a]=this.reallocBlock(o,t);break}o=this.blockNext(o)}return i&&i!==r&&this.u8.copyWithin(O(i),O(r),a),O(i)}reallocBlock(e,t){let r=this.blockSize(e),i=e+r,o=i>=this.top,a=I(t+E,this.align);if(a<=r){if(this.doSplit){let c=r-a;c>=this.minSplit?this.splitBlock(e,a,c):o&&(this.top=e+a)}else o&&(this.top=e+a);return[e,i]}return o&&e+a<this.end?(this.top=e+this.setBlockSize(e,a),[e,i]):(this.free(e),[L(this.malloc(t)),i])}reallocArray(e,t){if(e.buffer!==this.buf)return;let r=this.realloc(e.byteOffset,t*e.BYTES_PER_ELEMENT);return r?new e.constructor(this.buf,r,t):void 0}free(e){let t;if(V(e))t=e;else{if(e.buffer!==this.buf)return!1;t=e.byteOffset}t=L(t);let r=this._used,i=0;for(;r;){if(r===t)return i?this.unlinkBlock(i,r):this._used=this.blockNext(r),this.insert(r),this.doCompact&&this.compact(),!0;i=r,r=this.blockNext(r)}return!1}freeAll(){this._free=0,this._used=0,this.top=this.initialTop()}release(){return delete this.u8,delete this.u32,delete this.state,delete this.buf,!0}get align(){return this.state[Y]}set align(e){this.state[Y]=e}get end(){return this.state[q]}set end(e){this.state[q]=e}get top(){return this.state[Z]}set top(e){this.state[Z]=e}get _free(){return this.state[G]}set _free(e){this.state[G]=e}get _used(){return this.state[H]}set _used(e){this.state[H]=e}get doCompact(){return!!(this.state[A]&U)}set doCompact(e){e?this.state[A]|=1<<U-1:this.state[A]&=~U}get doSplit(){return!!(this.state[A]&F)}set doSplit(e){e?this.state[A]|=1<<F-1:this.state[A]&=~F}get minSplit(){return this.state[Q]}set minSplit(e){D(e>E,`illegal min split threshold: ${e}, require at least ${E+1}`),this.state[Q]=e}blockSize(e){return this.u32[(e>>2)+x]}setBlockSize(e,t){return this.u32[(e>>2)+x]=t,t}blockNext(e){return this.u32[(e>>2)+N]}setBlockNext(e,t){this.u32[(e>>2)+N]=t}initBlock(e,t,r){let i=e>>>2;return this.u32[i+x]=t,this.u32[i+N]=r,e}unlinkBlock(e,t){this.setBlockNext(e,this.blockNext(t))}splitBlock(e,t,r){this.insert(this.initBlock(e+this.setBlockSize(e,t),r,0)),this.doCompact&&this.compact()}initialTop(e=this.align){return I(this.start+j+E,e)-E}compact(){let e=this._free,t=0,r=0,i,o=!1;for(;e;){for(i=e,r=this.blockNext(e);r&&i+this.blockSize(i)===r;)i=r,r=this.blockNext(r);if(i!==e){let a=i-e+this.blockSize(i);this.setBlockSize(e,a);let c=this.blockNext(i),l=this.blockNext(e);for(;l&&l!==c;){let u=this.blockNext(l);this.setBlockNext(l,0),l=u}this.setBlockNext(e,c),o=!0}e+this.blockSize(e)>=this.top&&(this.top=e,t?this.unlinkBlock(t,e):this._free=this.blockNext(e)),t=e,e=this.blockNext(e)}return o}insert(e){let t=this._free,r=0;for(;t&&!(e<=t);)r=t,t=this.blockNext(t);r?this.setBlockNext(r,e):this._free=e,this.setBlockNext(e,t)}},O=s=>s>0?s+E:0,L=s=>s>0?s-E:0;var Se=8,P=class{#i;#n;#o;#p;#t;#r;#e;#s;#c;constructor(e){let{audioContext:t,sharedBuffer:r,bufferPoolConfig:i,sampleBaseURL:o,audioPathMap:a={},maxBuffers:c=1024}=e;if(!t)throw new Error("BufferManager requires audioContext");if(!r||!(r instanceof SharedArrayBuffer))throw new Error("BufferManager requires sharedBuffer (SharedArrayBuffer)");if(!i||typeof i!="object")throw new Error("BufferManager requires bufferPoolConfig (object with start, size, align)");if(!Number.isFinite(i.start)||i.start<0)throw new Error("bufferPoolConfig.start must be a non-negative number");if(!Number.isFinite(i.size)||i.size<=0)throw new Error("bufferPoolConfig.size must be a positive number");if(a&&typeof a!="object")throw new Error("audioPathMap must be an object");if(!Number.isInteger(c)||c<=0)throw new Error("maxBuffers must be a positive integer");this.#o=t,this.#p=r,this.#i=o,this.#n=a,this.#t=new C({buf:r,start:i.start,size:i.size,align:Se}),this.#r=i.size,this.#e=new Map,this.#s=new Map,this.#c=new Map,this.GUARD_BEFORE=3,this.GUARD_AFTER=1,this.MAX_BUFFERS=c;let l=(i.size/(1024*1024)).toFixed(0),u=(i.start/(1024*1024)).toFixed(0)}#l(e){if(typeof e!="string"||e.length===0)throw new Error("Invalid audio path: must be a non-empty string");if(e.includes(".."))throw new Error(`Invalid audio path: path cannot contain '..' (got: ${e})`);if(e.startsWith("/")||/^[a-zA-Z]:/.test(e))throw new Error(`Invalid audio path: path must be relative (got: ${e})`);if(e.includes("%2e")||e.includes("%2E"))throw new Error(`Invalid audio path: path cannot contain URL-encoded characters (got: ${e})`);if(e.includes("\\"))throw new Error(`Invalid audio path: use forward slashes only (got: ${e})`);if(this.#n[e])return this.#n[e];if(!this.#i)throw new Error(`sampleBaseURL not configured. Please set it in SuperSonic constructor options.
|
|
1
|
+
var n={},n=n||{};(function(){"use strict";n.SECS_70YRS=2208988800,n.TWO_32=4294967296,n.defaults={metadata:!1,unpackSingleArgs:!0},n.isCommonJS=!!(typeof module<"u"&&module.exports),n.isNode=n.isCommonJS&&typeof window>"u",n.isElectron=!!(typeof process<"u"&&process.versions&&process.versions.electron),n.isBufferEnv=n.isNode||n.isElectron,n.isArray=function(s){return s&&Object.prototype.toString.call(s)==="[object Array]"},n.isTypedArrayView=function(s){return s.buffer&&s.buffer instanceof ArrayBuffer},n.isBuffer=function(s){return n.isBufferEnv&&s instanceof Buffer},n.Long=typeof Long<"u"?Long:void 0,n.TextDecoder=typeof TextDecoder<"u"?new TextDecoder("utf-8"):typeof util<"u"&&typeof(util.TextDecoder!=="undefined")?new util.TextDecoder("utf-8"):void 0,n.TextEncoder=typeof TextEncoder<"u"?new TextEncoder("utf-8"):typeof util<"u"&&typeof(util.TextEncoder!=="undefined")?new util.TextEncoder("utf-8"):void 0,n.dataView=function(s,e,t){return s.buffer?new DataView(s.buffer,e,t):s instanceof ArrayBuffer?new DataView(s,e,t):new DataView(new Uint8Array(s),e,t)},n.byteArray=function(s){if(s instanceof Uint8Array)return s;var e=s.buffer?s.buffer:s;if(!(e instanceof ArrayBuffer)&&(typeof e.length>"u"||typeof e=="string"))throw new Error("Can't wrap a non-array-like object as Uint8Array. Object was: "+JSON.stringify(s,null,2));return new Uint8Array(e)},n.nativeBuffer=function(s){return n.isBufferEnv?n.isBuffer(s)?s:Buffer.from(s.buffer?s:new Uint8Array(s)):n.isTypedArrayView(s)?s:new Uint8Array(s)},n.copyByteArray=function(s,e,t){if(n.isTypedArrayView(s)&&n.isTypedArrayView(e))e.set(s,t);else for(var r=t===void 0?0:t,i=Math.min(e.length-t,s.length),o=0,a=r;o<i;o++,a++)e[a]=s[o];return e},n.readString=function(s,e){for(var t=[],r=e.idx;r<s.byteLength;r++){var i=s.getUint8(r);if(i!==0)t.push(i);else{r++;break}}r=r+3&-4,e.idx=r;var o=n.isBufferEnv?n.readString.withBuffer:n.TextDecoder?n.readString.withTextDecoder:n.readString.raw;return o(t)},n.readString.raw=function(s){for(var e="",t=1e4,r=0;r<s.length;r+=t)e+=String.fromCharCode.apply(null,s.slice(r,r+t));return e},n.readString.withTextDecoder=function(s){var e=new Int8Array(s);return n.TextDecoder.decode(e)},n.readString.withBuffer=function(s){return Buffer.from(s).toString("utf-8")},n.writeString=function(s){var e=n.isBufferEnv?n.writeString.withBuffer:n.TextEncoder?n.writeString.withTextEncoder:null,t=s+"\0",r;e&&(r=e(t));for(var i=e?r.length:t.length,o=i+3&-4,a=new Uint8Array(o),l=0;l<i-1;l++){var c=e?r[l]:t.charCodeAt(l);a[l]=c}return a},n.writeString.withTextEncoder=function(s){return n.TextEncoder.encode(s)},n.writeString.withBuffer=function(s){return Buffer.from(s)},n.readPrimitive=function(s,e,t,r){var i=s[e](r.idx,!1);return r.idx+=t,i},n.writePrimitive=function(s,e,t,r,i){i=i===void 0?0:i;var o;return e?o=new Uint8Array(e.buffer):(o=new Uint8Array(r),e=new DataView(o.buffer)),e[t](i,s,!1),o},n.readInt32=function(s,e){return n.readPrimitive(s,"getInt32",4,e)},n.writeInt32=function(s,e,t){return n.writePrimitive(s,e,"setInt32",4,t)},n.readInt64=function(s,e){var t=n.readPrimitive(s,"getInt32",4,e),r=n.readPrimitive(s,"getInt32",4,e);return n.Long?new n.Long(r,t):{high:t,low:r,unsigned:!1}},n.writeInt64=function(s,e,t){var r=new Uint8Array(8);return r.set(n.writePrimitive(s.high,e,"setInt32",4,t),0),r.set(n.writePrimitive(s.low,e,"setInt32",4,t+4),4),r},n.readFloat32=function(s,e){return n.readPrimitive(s,"getFloat32",4,e)},n.writeFloat32=function(s,e,t){return n.writePrimitive(s,e,"setFloat32",4,t)},n.readFloat64=function(s,e){return n.readPrimitive(s,"getFloat64",8,e)},n.writeFloat64=function(s,e,t){return n.writePrimitive(s,e,"setFloat64",8,t)},n.readChar32=function(s,e){var t=n.readPrimitive(s,"getUint32",4,e);return String.fromCharCode(t)},n.writeChar32=function(s,e,t){var r=s.charCodeAt(0);if(!(r===void 0||r<-1))return n.writePrimitive(r,e,"setUint32",4,t)},n.readBlob=function(s,e){var t=n.readInt32(s,e),r=t+3&-4,i=new Uint8Array(s.buffer,e.idx,t);return e.idx+=r,i},n.writeBlob=function(s){s=n.byteArray(s);var e=s.byteLength,t=e+3&-4,r=4,i=t+r,o=new Uint8Array(i),a=new DataView(o.buffer);return n.writeInt32(e,a),o.set(s,r),o},n.readMIDIBytes=function(s,e){var t=new Uint8Array(s.buffer,e.idx,4);return e.idx+=4,t},n.writeMIDIBytes=function(s){s=n.byteArray(s);var e=new Uint8Array(4);return e.set(s),e},n.readColor=function(s,e){var t=new Uint8Array(s.buffer,e.idx,4),r=t[3]/255;return e.idx+=4,{r:t[0],g:t[1],b:t[2],a:r}},n.writeColor=function(s){var e=Math.round(s.a*255),t=new Uint8Array([s.r,s.g,s.b,e]);return t},n.readTrue=function(){return!0},n.readFalse=function(){return!1},n.readNull=function(){return null},n.readImpulse=function(){return 1},n.readTimeTag=function(s,e){var t=n.readPrimitive(s,"getUint32",4,e),r=n.readPrimitive(s,"getUint32",4,e),i=t===0&&r===1?Date.now():n.ntpToJSTime(t,r);return{raw:[t,r],native:i}},n.writeTimeTag=function(s){var e=s.raw?s.raw:n.jsToNTPTime(s.native),t=new Uint8Array(8),r=new DataView(t.buffer);return n.writeInt32(e[0],r,0),n.writeInt32(e[1],r,4),t},n.timeTag=function(s,e){s=s||0,e=e||Date.now();var t=e/1e3,r=Math.floor(t),i=t-r,o=Math.floor(s),a=s-o,l=i+a;if(l>1){var c=Math.floor(l),u=l-c;o+=c,l=u}var f=r+o+n.SECS_70YRS,h=Math.round(n.TWO_32*l);return{raw:[f,h]}},n.ntpToJSTime=function(s,e){var t=s-n.SECS_70YRS,r=e/n.TWO_32,i=(t+r)*1e3;return i},n.jsToNTPTime=function(s){var e=s/1e3,t=Math.floor(e),r=e-t,i=t+n.SECS_70YRS,o=Math.round(n.TWO_32*r);return[i,o]},n.readArguments=function(s,e,t){var r=n.readString(s,t);if(r.indexOf(",")!==0)throw new Error("A malformed type tag string was found while reading the arguments of an OSC message. String was: "+r," at offset: "+t.idx);var i=r.substring(1).split(""),o=[];return n.readArgumentsIntoArray(o,i,r,s,e,t),o},n.readArgument=function(s,e,t,r,i){var o=n.argumentTypes[s];if(!o)throw new Error("'"+s+"' is not a valid OSC type tag. Type tag string was: "+e);var a=o.reader,l=n[a](t,i);return r.metadata&&(l={type:s,value:l}),l},n.readArgumentsIntoArray=function(s,e,t,r,i,o){for(var a=0;a<e.length;){var l=e[a],c;if(l==="["){var u=e.slice(a+1),f=u.indexOf("]");if(f<0)throw new Error("Invalid argument type tag: an open array type tag ('[') was found without a matching close array tag ('[]'). Type tag was: "+t);var h=u.slice(0,f);c=n.readArgumentsIntoArray([],h,t,r,i,o),a+=f+2}else c=n.readArgument(l,t,r,i,o),a++;s.push(c)}return s},n.writeArguments=function(s,e){var t=n.collectArguments(s,e);return n.joinParts(t)},n.joinParts=function(s){for(var e=new Uint8Array(s.byteLength),t=s.parts,r=0,i=0;i<t.length;i++){var o=t[i];n.copyByteArray(o,e,r),r+=o.length}return e},n.addDataPart=function(s,e){e.parts.push(s),e.byteLength+=s.length},n.writeArrayArguments=function(s,e){for(var t="[",r=0;r<s.length;r++){var i=s[r];t+=n.writeArgument(i,e)}return t+="]",t},n.writeArgument=function(s,e){if(n.isArray(s))return n.writeArrayArguments(s,e);var t=s.type,r=n.argumentTypes[t].writer;if(r){var i=n[r](s.value);n.addDataPart(i,e)}return s.type},n.collectArguments=function(s,e,t){n.isArray(s)||(s=typeof s>"u"?[]:[s]),t=t||{byteLength:0,parts:[]},e.metadata||(s=n.annotateArguments(s));for(var r=",",i=t.parts.length,o=0;o<s.length;o++){var a=s[o];r+=n.writeArgument(a,t)}var l=n.writeString(r);return t.byteLength+=l.byteLength,t.parts.splice(i,0,l),t},n.readMessage=function(s,e,t){e=e||n.defaults;var r=n.dataView(s,s.byteOffset,s.byteLength);t=t||{idx:0};var i=n.readString(r,t);return n.readMessageContents(i,r,e,t)},n.readMessageContents=function(s,e,t,r){if(s.indexOf("/")!==0)throw new Error("A malformed OSC address was found while reading an OSC message. String was: "+s);var i=n.readArguments(e,t,r);return{address:s,args:i.length===1&&t.unpackSingleArgs?i[0]:i}},n.collectMessageParts=function(s,e,t){return t=t||{byteLength:0,parts:[]},n.addDataPart(n.writeString(s.address),t),n.collectArguments(s.args,e,t)},n.writeMessage=function(s,e){if(e=e||n.defaults,!n.isValidMessage(s))throw new Error("An OSC message must contain a valid address. Message was: "+JSON.stringify(s,null,2));var t=n.collectMessageParts(s,e);return n.joinParts(t)},n.isValidMessage=function(s){return s.address&&s.address.indexOf("/")===0},n.readBundle=function(s,e,t){return n.readPacket(s,e,t)},n.collectBundlePackets=function(s,e,t){t=t||{byteLength:0,parts:[]},n.addDataPart(n.writeString("#bundle"),t),n.addDataPart(n.writeTimeTag(s.timeTag),t);for(var r=0;r<s.packets.length;r++){var i=s.packets[r],o=i.address?n.collectMessageParts:n.collectBundlePackets,a=o(i,e);t.byteLength+=a.byteLength,n.addDataPart(n.writeInt32(a.byteLength),t),t.parts=t.parts.concat(a.parts)}return t},n.writeBundle=function(s,e){if(!n.isValidBundle(s))throw new Error("An OSC bundle must contain 'timeTag' and 'packets' properties. Bundle was: "+JSON.stringify(s,null,2));e=e||n.defaults;var t=n.collectBundlePackets(s,e);return n.joinParts(t)},n.isValidBundle=function(s){return s.timeTag!==void 0&&s.packets!==void 0},n.readBundleContents=function(s,e,t,r){for(var i=n.readTimeTag(s,t),o=[];t.idx<r;){var a=n.readInt32(s,t),l=t.idx+a,c=n.readPacket(s,e,t,l);o.push(c)}return{timeTag:i,packets:o}},n.readPacket=function(s,e,t,r){var i=n.dataView(s,s.byteOffset,s.byteLength);r=r===void 0?i.byteLength:r,t=t||{idx:0};var o=n.readString(i,t),a=o[0];if(a==="#")return n.readBundleContents(i,e,t,r);if(a==="/")return n.readMessageContents(o,i,e,t);throw new Error("The header of an OSC packet didn't contain an OSC address or a #bundle string. Header was: "+o)},n.writePacket=function(s,e){if(n.isValidMessage(s))return n.writeMessage(s,e);if(n.isValidBundle(s))return n.writeBundle(s,e);throw new Error("The specified packet was not recognized as a valid OSC message or bundle. Packet was: "+JSON.stringify(s,null,2))},n.argumentTypes={i:{reader:"readInt32",writer:"writeInt32"},h:{reader:"readInt64",writer:"writeInt64"},f:{reader:"readFloat32",writer:"writeFloat32"},s:{reader:"readString",writer:"writeString"},S:{reader:"readString",writer:"writeString"},b:{reader:"readBlob",writer:"writeBlob"},t:{reader:"readTimeTag",writer:"writeTimeTag"},T:{reader:"readTrue"},F:{reader:"readFalse"},N:{reader:"readNull"},I:{reader:"readImpulse"},d:{reader:"readFloat64",writer:"writeFloat64"},c:{reader:"readChar32",writer:"writeChar32"},r:{reader:"readColor",writer:"writeColor"},m:{reader:"readMIDIBytes",writer:"writeMIDIBytes"}},n.inferTypeForArgument=function(s){var e=typeof s;switch(e){case"boolean":return s?"T":"F";case"string":return"s";case"number":return"f";case"undefined":return"N";case"object":if(s===null)return"N";if(s instanceof Uint8Array||s instanceof ArrayBuffer)return"b";if(typeof s.high=="number"&&typeof s.low=="number")return"h";break}throw new Error("Can't infer OSC argument type for value: "+JSON.stringify(s,null,2))},n.annotateArguments=function(s){for(var e=[],t=0;t<s.length;t++){var r=s[t],i;if(typeof r=="object"&&r.type&&r.value!==void 0)i=r;else if(n.isArray(r))i=n.annotateArguments(r);else{var o=n.inferTypeForArgument(r);i={type:o,value:r}}e.push(i)}return e}})();var b=function(){};b.prototype.on=function(){};b.prototype.emit=function(){};b.prototype.removeListener=function(){};(function(){"use strict";n.supportsSerial=!1,n.firePacketEvents=function(e,t,r,i){t.address?e.emit("message",t,r,i):n.fireBundleEvents(e,t,r,i)},n.fireBundleEvents=function(e,t,r,i){e.emit("bundle",t,r,i);for(var o=0;o<t.packets.length;o++){var a=t.packets[o];n.firePacketEvents(e,a,t.timeTag,i)}},n.fireClosedPortSendError=function(e,t){t=t||"Can't send packets on a closed osc.Port object. Please open (or reopen) this Port by calling open().",e.emit("error",t)},n.Port=function(e){this.options=e||{},this.on("data",this.decodeOSC.bind(this))};var s=n.Port.prototype=Object.create(b.prototype);s.constructor=n.Port,s.send=function(e){var t=Array.prototype.slice.call(arguments),r=this.encodeOSC(e),i=n.nativeBuffer(r);t[0]=i,this.sendRaw.apply(this,t)},s.encodeOSC=function(e){e=e.buffer?e.buffer:e;var t;try{t=n.writePacket(e,this.options)}catch(r){this.emit("error",r)}return t},s.decodeOSC=function(e,t){e=n.byteArray(e),this.emit("raw",e,t);try{var r=n.readPacket(e,this.options);this.emit("osc",r,t),n.firePacketEvents(this,r,void 0,t)}catch(i){this.emit("error",i)}},n.SLIPPort=function(e){var t=this,r=this.options=e||{};r.useSLIP=r.useSLIP===void 0?!0:r.useSLIP,this.decoder=new slip.Decoder({onMessage:this.decodeOSC.bind(this),onError:function(o){t.emit("error",o)}});var i=r.useSLIP?this.decodeSLIPData:this.decodeOSC;this.on("data",i.bind(this))},s=n.SLIPPort.prototype=Object.create(n.Port.prototype),s.constructor=n.SLIPPort,s.encodeOSC=function(e){e=e.buffer?e.buffer:e;var t;try{var r=n.writePacket(e,this.options);t=slip.encode(r)}catch(i){this.emit("error",i)}return t},s.decodeSLIPData=function(e,t){this.decoder.decode(e,t)},n.relay=function(e,t,r,i,o,a){r=r||"message",i=i||"send",o=o||function(){},a=a?[null].concat(a):[];var l=function(c){a[0]=c,c=o(c),t[i].apply(t,a)};return e.on(r,l),{eventName:r,listener:l}},n.relayPorts=function(e,t,r){var i=r.raw?"raw":"osc",o=r.raw?"sendRaw":"send";return n.relay(e,t,i,o,r.transform)},n.stopRelaying=function(e,t){e.removeListener(t.eventName,t.listener)},n.Relay=function(e,t,r){var i=this.options=r||{};i.raw=!1,this.port1=e,this.port2=t,this.listen()},s=n.Relay.prototype=Object.create(b.prototype),s.constructor=n.Relay,s.open=function(){this.port1.open(),this.port2.open()},s.listen=function(){this.port1Spec&&this.port2Spec&&this.close(),this.port1Spec=n.relayPorts(this.port1,this.port2,this.options),this.port2Spec=n.relayPorts(this.port2,this.port1,this.options);var e=this.close.bind(this);this.port1.on("close",e),this.port2.on("close",e)},s.close=function(){n.stopRelaying(this.port1,this.port1Spec),n.stopRelaying(this.port2,this.port2Spec),this.emit("close",this.port1,this.port2)}})();(function(){"use strict";n.WebSocket=typeof WebSocket<"u"?WebSocket:void 0,n.WebSocketPort=function(e){n.Port.call(this,e),this.on("open",this.listen.bind(this)),this.socket=e.socket,this.socket&&(this.socket.readyState===1?(n.WebSocketPort.setupSocketForBinary(this.socket),this.emit("open",this.socket)):this.open())};var s=n.WebSocketPort.prototype=Object.create(n.Port.prototype);s.constructor=n.WebSocketPort,s.open=function(){(!this.socket||this.socket.readyState>1)&&(this.socket=new n.WebSocket(this.options.url)),n.WebSocketPort.setupSocketForBinary(this.socket);var e=this;this.socket.onopen=function(){e.emit("open",e.socket)},this.socket.onerror=function(t){e.emit("error",t)}},s.listen=function(){var e=this;this.socket.onmessage=function(t){e.emit("data",t.data,t)},this.socket.onclose=function(t){e.emit("close",t)},e.emit("ready")},s.sendRaw=function(e){if(!this.socket||this.socket.readyState!==1){n.fireClosedPortSendError(this);return}this.socket.send(e)},s.close=function(e,t){this.socket.close(e,t)},n.WebSocketPort.setupSocketForBinary=function(e){e.binaryType=n.isNode?"nodebuffer":"arraybuffer"}})();var B=n,{readPacket:He,writePacket:Ge,readMessage:Ze,writeMessage:qe,readBundle:Ye,writeBundle:Qe}=n;var R=class{constructor(e=null){this.workerBaseURL=e,this.workers={oscOut:null,oscIn:null,debug:null},this.callbacks={onRawOSC:null,onParsedOSC:null,onDebugMessage:null,onError:null,onInitialized:null},this.initialized=!1,this.sharedBuffer=null,this.ringBufferBase=null,this.bufferConstants=null}async init(e,t,r){if(this.initialized){console.warn("[ScsynthOSC] Already initialized");return}this.sharedBuffer=e,this.ringBufferBase=t,this.bufferConstants=r;try{this.workers.oscOut=new Worker(this.workerBaseURL+"osc_out_prescheduler_worker.js",{type:"module"}),this.workers.oscIn=new Worker(this.workerBaseURL+"osc_in_worker.js",{type:"module"}),this.workers.debug=new Worker(this.workerBaseURL+"debug_worker.js",{type:"module"}),this.setupWorkerHandlers();let i=[this.initWorker(this.workers.oscOut,"OSC SCHEDULER+WRITER"),this.initWorker(this.workers.oscIn,"OSC IN"),this.initWorker(this.workers.debug,"DEBUG")];await Promise.all(i),this.workers.oscIn.postMessage({type:"start"}),this.workers.debug.postMessage({type:"start"}),this.initialized=!0,this.callbacks.onInitialized&&this.callbacks.onInitialized()}catch(i){throw console.error("[ScsynthOSC] Initialization failed:",i),this.callbacks.onError&&this.callbacks.onError(i),i}}initWorker(e,t){return new Promise((r,i)=>{let o=setTimeout(()=>{i(new Error(`${t} worker initialization timeout`))},5e3),a=l=>{l.data.type==="initialized"&&(clearTimeout(o),e.removeEventListener("message",a),r())};e.addEventListener("message",a),e.postMessage({type:"init",sharedBuffer:this.sharedBuffer,ringBufferBase:this.ringBufferBase,bufferConstants:this.bufferConstants})})}setupWorkerHandlers(){this.workers.oscIn.onmessage=e=>{let t=e.data;switch(t.type){case"messages":t.messages.forEach(r=>{if(r.oscData&&(this.callbacks.onRawOSC&&this.callbacks.onRawOSC({oscData:r.oscData,sequence:r.sequence}),this.callbacks.onParsedOSC))try{let i={metadata:!1,unpackSingleArgs:!1},o=B.readPacket(r.oscData,i);this.callbacks.onParsedOSC(o)}catch(i){console.error("[ScsynthOSC] Failed to decode OSC message:",i,r)}});break;case"error":console.error("[ScsynthOSC] OSC IN error:",t.error),this.callbacks.onError&&this.callbacks.onError(t.error,"oscIn");break}},this.workers.debug.onmessage=e=>{let t=e.data;switch(t.type){case"debug":this.callbacks.onDebugMessage&&t.messages.forEach(r=>{this.callbacks.onDebugMessage(r)});break;case"error":console.error("[ScsynthOSC] DEBUG error:",t.error),this.callbacks.onError&&this.callbacks.onError(t.error,"debug");break}},this.workers.oscOut.onmessage=e=>{let t=e.data;switch(t.type){case"error":console.error("[ScsynthOSC] OSC OUT error:",t.error),this.callbacks.onError&&this.callbacks.onError(t.error,"oscOut");break}}}send(e,t={}){if(!this.initialized){console.error("[ScsynthOSC] Not initialized");return}let{editorId:r=0,runTag:i="",audioTimeS:o=null,currentTimeS:a=null}=t;this.workers.oscOut.postMessage({type:"send",oscData:e,editorId:r,runTag:i,audioTimeS:o,currentTimeS:a})}sendImmediate(e){if(!this.initialized){console.error("[ScsynthOSC] Not initialized");return}this.workers.oscOut.postMessage({type:"sendImmediate",oscData:e})}cancelEditorTag(e,t){this.initialized&&this.workers.oscOut.postMessage({type:"cancelEditorTag",editorId:e,runTag:t})}cancelEditor(e){this.initialized&&this.workers.oscOut.postMessage({type:"cancelEditor",editorId:e})}cancelAll(){this.initialized&&this.workers.oscOut.postMessage({type:"cancelAll"})}clearDebug(){this.initialized&&this.workers.debug.postMessage({type:"clear"})}onRawOSC(e){this.callbacks.onRawOSC=e}onParsedOSC(e){this.callbacks.onParsedOSC=e}onDebugMessage(e){this.callbacks.onDebugMessage=e}onError(e){this.callbacks.onError=e}onInitialized(e){this.callbacks.onInitialized=e}terminate(){this.workers.oscOut&&(this.workers.oscOut.postMessage({type:"stop"}),this.workers.oscOut.terminate()),this.workers.oscIn&&(this.workers.oscIn.postMessage({type:"stop"}),this.workers.oscIn.terminate()),this.workers.debug&&(this.workers.debug.postMessage({type:"stop"}),this.workers.debug.terminate()),this.workers={oscOut:null,oscIn:null,debug:null},this.initialized=!1}};var ae={5120:"i8",5121:"u8",5122:"i16",5123:"u16",5124:"i32",5125:"u32",5126:"f32"};var z={u8:1,u8c:1,i8:1,u16:2,i16:2,u32:4,i32:4,i64:8,u64:8,f32:4,f64:8};var le={f32:Float32Array,f64:Float64Array},ce={i8:Int8Array,i16:Int16Array,i32:Int32Array},ue={u8:Uint8Array,u8c:Uint8ClampedArray,u16:Uint16Array,u32:Uint32Array},fe={i64:BigInt64Array,u64:BigUint64Array},he={...le,...ce,...ue},de=s=>{let e=ae[s];return e!==void 0?e:s};function $(s,...e){let t=fe[s];return new(t||he[de(s)])(...e)}var M=(s,e)=>(e--,s+e&~e);var W=s=>typeof s=="number";var k=(s,e=t=>t!==void 0?": "+t:"")=>class extends Error{origMessage;constructor(t){super(s(t)+e(t)),this.origMessage=t!==void 0?String(t):""}};var pe=k(()=>"Assertion failed"),D=(typeof process<"u"&&process.env!==void 0?process.env.UMBRELLA_ASSERTS:!import.meta.env||import.meta.env.MODE!=="production"||import.meta.env.UMBRELLA_ASSERTS||import.meta.env.VITE_UMBRELLA_ASSERTS)?(s,e)=>{if(typeof s=="function"&&!s()||!s)throw new pe(typeof e=="function"?e():e)}:()=>{};var me=k(()=>"illegal argument(s)"),V=s=>{throw new me(s)};var H=0,G=1,Z=2,q=3,Y=4,A=5,Q=6,U=1,F=2,j=7*4,x=0,N=1,g=2*4,P=class{buf;start;u8;u32;state;constructor(e={}){if(this.buf=e.buf?e.buf:new ArrayBuffer(e.size||4096),this.start=e.start!=null?M(Math.max(e.start,0),4):0,this.u8=new Uint8Array(this.buf),this.u32=new Uint32Array(this.buf),this.state=new Uint32Array(this.buf,this.start,j/4),!e.skipInitialization){let t=e.align||8;D(t>=8,`invalid alignment: ${t}, must be a pow2 and >= 8`);let r=this.initialTop(t),i=e.end!=null?Math.min(e.end,this.buf.byteLength):this.buf.byteLength;r>=i&&V(`insufficient address range (0x${this.start.toString(16)} - 0x${i.toString(16)})`),this.align=t,this.doCompact=e.compact!==!1,this.doSplit=e.split!==!1,this.minSplit=e.minSplit||16,this.end=i,this.top=r,this._free=0,this._used=0}}stats(){let e=r=>{let i=0,o=0;for(;r;)i++,o+=this.blockSize(r),r=this.blockNext(r);return{count:i,size:o}},t=e(this._free);return{free:t,used:e(this._used),top:this.top,available:this.end-this.top+t.size,total:this.buf.byteLength}}callocAs(e,t,r=0){let i=this.mallocAs(e,t);return i?.fill(r),i}mallocAs(e,t){let r=this.malloc(t*z[e]);return r?$(e,this.buf,r,t):void 0}calloc(e,t=0){let r=this.malloc(e);return r&&this.u8.fill(t,r,r+e),r}malloc(e){if(e<=0)return 0;let t=M(e+g,this.align),r=this.end,i=this.top,o=this._free,a=0;for(;o;){let l=this.blockSize(o),c=o+l>=i;if(c||l>=t)return this.mallocTop(o,a,l,t,c);a=o,o=this.blockNext(o)}return o=i,i=o+t,i<=r?(this.initBlock(o,t,this._used),this._used=o,this.top=i,v(o)):0}mallocTop(e,t,r,i,o){if(o&&e+i>this.end)return 0;if(t?this.unlinkBlock(t,e):this._free=this.blockNext(e),this.setBlockNext(e,this._used),this._used=e,o)this.top=e+this.setBlockSize(e,i);else if(this.doSplit){let a=r-i;a>=this.minSplit&&this.splitBlock(e,i,a)}return v(e)}realloc(e,t){if(t<=0)return 0;let r=L(e),i=0,o=this._used,a=0;for(;o;){if(o===r){[i,a]=this.reallocBlock(o,t);break}o=this.blockNext(o)}return i&&i!==r&&this.u8.copyWithin(v(i),v(r),a),v(i)}reallocBlock(e,t){let r=this.blockSize(e),i=e+r,o=i>=this.top,a=M(t+g,this.align);if(a<=r){if(this.doSplit){let l=r-a;l>=this.minSplit?this.splitBlock(e,a,l):o&&(this.top=e+a)}else o&&(this.top=e+a);return[e,i]}return o&&e+a<this.end?(this.top=e+this.setBlockSize(e,a),[e,i]):(this.free(e),[L(this.malloc(t)),i])}reallocArray(e,t){if(e.buffer!==this.buf)return;let r=this.realloc(e.byteOffset,t*e.BYTES_PER_ELEMENT);return r?new e.constructor(this.buf,r,t):void 0}free(e){let t;if(W(e))t=e;else{if(e.buffer!==this.buf)return!1;t=e.byteOffset}t=L(t);let r=this._used,i=0;for(;r;){if(r===t)return i?this.unlinkBlock(i,r):this._used=this.blockNext(r),this.insert(r),this.doCompact&&this.compact(),!0;i=r,r=this.blockNext(r)}return!1}freeAll(){this._free=0,this._used=0,this.top=this.initialTop()}release(){return delete this.u8,delete this.u32,delete this.state,delete this.buf,!0}get align(){return this.state[Y]}set align(e){this.state[Y]=e}get end(){return this.state[q]}set end(e){this.state[q]=e}get top(){return this.state[Z]}set top(e){this.state[Z]=e}get _free(){return this.state[H]}set _free(e){this.state[H]=e}get _used(){return this.state[G]}set _used(e){this.state[G]=e}get doCompact(){return!!(this.state[A]&U)}set doCompact(e){e?this.state[A]|=1<<U-1:this.state[A]&=~U}get doSplit(){return!!(this.state[A]&F)}set doSplit(e){e?this.state[A]|=1<<F-1:this.state[A]&=~F}get minSplit(){return this.state[Q]}set minSplit(e){D(e>g,`illegal min split threshold: ${e}, require at least ${g+1}`),this.state[Q]=e}blockSize(e){return this.u32[(e>>2)+x]}setBlockSize(e,t){return this.u32[(e>>2)+x]=t,t}blockNext(e){return this.u32[(e>>2)+N]}setBlockNext(e,t){this.u32[(e>>2)+N]=t}initBlock(e,t,r){let i=e>>>2;return this.u32[i+x]=t,this.u32[i+N]=r,e}unlinkBlock(e,t){this.setBlockNext(e,this.blockNext(t))}splitBlock(e,t,r){this.insert(this.initBlock(e+this.setBlockSize(e,t),r,0)),this.doCompact&&this.compact()}initialTop(e=this.align){return M(this.start+j+g,e)-g}compact(){let e=this._free,t=0,r=0,i,o=!1;for(;e;){for(i=e,r=this.blockNext(e);r&&i+this.blockSize(i)===r;)i=r,r=this.blockNext(r);if(i!==e){let a=i-e+this.blockSize(i);this.setBlockSize(e,a);let l=this.blockNext(i),c=this.blockNext(e);for(;c&&c!==l;){let u=this.blockNext(c);this.setBlockNext(c,0),c=u}this.setBlockNext(e,l),o=!0}e+this.blockSize(e)>=this.top&&(this.top=e,t?this.unlinkBlock(t,e):this._free=this.blockNext(e)),t=e,e=this.blockNext(e)}return o}insert(e){let t=this._free,r=0;for(;t&&!(e<=t);)r=t,t=this.blockNext(t);r?this.setBlockNext(r,e):this._free=e,this.setBlockNext(e,t)}},v=s=>s>0?s+g:0,L=s=>s>0?s-g:0;var Se=8,C=class{#r;#n;#o;#d;#t;#i;#e;#s;#l;constructor(e){let{audioContext:t,sharedBuffer:r,bufferPoolConfig:i,sampleBaseURL:o,audioPathMap:a={},maxBuffers:l=1024}=e;if(!t)throw new Error("BufferManager requires audioContext");if(!r||!(r instanceof SharedArrayBuffer))throw new Error("BufferManager requires sharedBuffer (SharedArrayBuffer)");if(!i||typeof i!="object")throw new Error("BufferManager requires bufferPoolConfig (object with start, size, align)");if(!Number.isFinite(i.start)||i.start<0)throw new Error("bufferPoolConfig.start must be a non-negative number");if(!Number.isFinite(i.size)||i.size<=0)throw new Error("bufferPoolConfig.size must be a positive number");if(a&&typeof a!="object")throw new Error("audioPathMap must be an object");if(!Number.isInteger(l)||l<=0)throw new Error("maxBuffers must be a positive integer");this.#o=t,this.#d=r,this.#r=o,this.#n=a,this.#t=new P({buf:r,start:i.start,size:i.size,align:Se}),this.#i=i.size,this.#e=new Map,this.#s=new Map,this.#l=new Map,this.GUARD_BEFORE=3,this.GUARD_AFTER=1,this.MAX_BUFFERS=l;let c=(i.size/(1024*1024)).toFixed(0),u=(i.start/(1024*1024)).toFixed(0)}#c(e){if(typeof e!="string"||e.length===0)throw new Error("Invalid audio path: must be a non-empty string");if(e.includes(".."))throw new Error(`Invalid audio path: path cannot contain '..' (got: ${e})`);if(e.startsWith("/")||/^[a-zA-Z]:/.test(e))throw new Error(`Invalid audio path: path must be relative (got: ${e})`);if(e.includes("%2e")||e.includes("%2E"))throw new Error(`Invalid audio path: path cannot contain URL-encoded characters (got: ${e})`);if(e.includes("\\"))throw new Error(`Invalid audio path: use forward slashes only (got: ${e})`);if(this.#n[e])return this.#n[e];if(!this.#r)throw new Error(`sampleBaseURL not configured. Please set it in SuperSonic constructor options.
|
|
2
2
|
Example: new SuperSonic({ sampleBaseURL: "./dist/samples/" })
|
|
3
3
|
Or use CDN: new SuperSonic({ sampleBaseURL: "https://unpkg.com/supersonic-scsynth-samples@latest/samples/" })
|
|
4
|
-
Or install: npm install supersonic-scsynth-samples`);return this.#
|
|
4
|
+
Or install: npm install supersonic-scsynth-samples`);return this.#r+e}#w(e){if(!Number.isInteger(e)||e<0||e>=this.MAX_BUFFERS)throw new Error(`Invalid buffer number ${e} (must be 0-${this.MAX_BUFFERS-1})`)}async#p(e,t,r){let i=null,o=null,a=!1,l=await this.#m(e),c=!1;try{await this.#B(e);let{ptr:u,sizeBytes:f,...h}=await r();i=u;let{uuid:S,allocationComplete:m}=this.#u(e,t);o=S,this.#b(e,i,f,S,m),a=!0;let d=this.#_(e,S,m);return l(),c=!0,{ptr:i,uuid:S,allocationComplete:d,...h}}catch(u){throw a&&o?this.#f(e,o,!1):i&&this.#t.free(i),u}finally{c||l()}}async prepareFromFile(e){let{bufnum:t,path:r,startFrame:i=0,numFrames:o=0,channels:a=null}=e;return this.#w(t),this.#p(t,6e4,async()=>{let l=this.#c(r),c=await fetch(l);if(!c.ok)throw new Error(`Failed to fetch ${l}: ${c.status} ${c.statusText}`);let u=await c.arrayBuffer(),f=await this.#o.decodeAudioData(u),h=Math.max(0,Math.floor(i||0)),S=f.length-h,m=o&&o>0?Math.min(Math.floor(o),S):S;if(m<=0)throw new Error(`No audio frames available for buffer ${t} from ${r}`);let d=this.#g(a,f.numberOfChannels),w=d.length,p=m*w+(this.GUARD_BEFORE+this.GUARD_AFTER)*w,E=this.#y(p),y=new Float32Array(p),T=this.GUARD_BEFORE*w;for(let O=0;O<m;O++)for(let I=0;I<w;I++){let ne=d[I],oe=f.getChannelData(ne);y[T+O*w+I]=oe[h+O]}this.#a(E,y);let _=y.length*4;return{ptr:E,sizeBytes:_,numFrames:m,numChannels:w,sampleRate:f.sampleRate}})}async prepareEmpty(e){let{bufnum:t,numFrames:r,numChannels:i=1,sampleRate:o=null}=e;if(this.#w(t),!Number.isFinite(r)||r<=0)throw new Error(`/b_alloc requires a positive number of frames (got ${r})`);if(!Number.isFinite(i)||i<=0)throw new Error(`/b_alloc requires a positive channel count (got ${i})`);let a=Math.floor(r),l=Math.floor(i);return this.#p(t,5e3,async()=>{let c=a*l+(this.GUARD_BEFORE+this.GUARD_AFTER)*l,u=this.#y(c),f=new Float32Array(c);this.#a(u,f);let h=f.length*4;return{ptr:u,sizeBytes:h,numFrames:a,numChannels:l,sampleRate:o||this.#o.sampleRate}})}#g(e,t){return!e||e.length===0?Array.from({length:t},(r,i)=>i):(e.forEach(r=>{if(!Number.isInteger(r)||r<0||r>=t)throw new Error(`Channel ${r} is out of range (file has ${t} channels)`)}),e)}#y(e){let t=e*4,r=this.#t.malloc(t);if(r===0){let i=this.#t.stats(),o=((i.available||0)/(1024*1024)).toFixed(2),a=((i.total||0)/(1024*1024)).toFixed(2),l=(t/(1024*1024)).toFixed(2);throw new Error(`Buffer pool allocation failed: requested ${l}MB, available ${o}MB of ${a}MB total`)}return r}#a(e,t){new Float32Array(this.#d,e,t.length).set(t)}#h(e,t,r){return new Promise((i,o)=>{let a=setTimeout(()=>{this.#s.delete(e),o(new Error(`Buffer ${t} allocation timeout (${r}ms)`))},r);this.#s.set(e,{resolve:i,reject:o,timeout:a})})}#u(e,t){let r=crypto.randomUUID(),i=this.#h(r,e,t);return{uuid:r,allocationComplete:i}}async#m(e){let t=this.#l.get(e)||Promise.resolve(),r,i=new Promise(o=>{r=o});return this.#l.set(e,t.then(()=>i)),await t,()=>{r&&(r(),r=null),this.#l.get(e)===i&&this.#l.delete(e)}}#b(e,t,r,i,o){let a=this.#e.get(e),l={ptr:t,size:r,pendingToken:i,pendingPromise:o,previousAllocation:a?{ptr:a.ptr,size:a.size}:null};return this.#e.set(e,l),l}async#B(e){let t=this.#e.get(e);if(t&&t.pendingToken&&t.pendingPromise)try{await t.pendingPromise}catch{}}#_(e,t,r){return!r||typeof r.then!="function"?(this.#f(e,t,!0),Promise.resolve()):r.then(i=>(this.#f(e,t,!0),i)).catch(i=>{throw this.#f(e,t,!1),i})}#f(e,t,r){let i=this.#e.get(e);if(!i||i.pendingToken!==t)return;let o=i.previousAllocation;if(r){i.pendingToken=null,i.pendingPromise=null,i.previousAllocation=null,o?.ptr&&this.#t.free(o.ptr);return}i.ptr&&this.#t.free(i.ptr),i.pendingPromise=null,o?.ptr?this.#e.set(e,{ptr:o.ptr,size:o.size,pendingToken:null,previousAllocation:null}):this.#e.delete(e)}handleBufferFreed(e){let t=e[0],r=e[1],i=this.#e.get(t);if(!i){typeof r=="number"&&r!==0&&this.#t.free(r);return}if(typeof r=="number"&&r===i.ptr){this.#t.free(i.ptr),this.#e.delete(t);return}if(typeof r=="number"&&i.previousAllocation&&i.previousAllocation.ptr===r){this.#t.free(r),i.previousAllocation=null;return}this.#t.free(i.ptr),this.#e.delete(t)}handleBufferAllocated(e){let t=e[0],r=e[1],i=this.#s.get(t);i&&(clearTimeout(i.timeout),i.resolve({bufnum:r}),this.#s.delete(t))}allocate(e){let t=e*4,r=this.#t.malloc(t);if(r===0){let i=this.#t.stats(),o=((i.available||0)/(1024*1024)).toFixed(2),a=((i.total||0)/(1024*1024)).toFixed(2),l=(t/(1024*1024)).toFixed(2);console.error(`[BufferManager] Allocation failed: requested ${l}MB, available ${o}MB of ${a}MB total`)}return r}free(e){return this.#t.free(e)}getView(e,t){return new Float32Array(this.#d,e,t)}getStats(){return this.#t.stats()}getDiagnostics(){let e=this.#t.stats(),t=0,r=0;for(let i of this.#e.values())i&&(t+=i.size||0,i.pendingToken&&r++);return{active:this.#e.size,pending:r,bytesActive:t,pool:{total:this.#i,available:e.available||0,freeBytes:e.free?.size||0,freeBlocks:e.free?.count||0,usedBytes:e.used?.size||0,usedBlocks:e.used?.count||0}}}destroy(){for(let[e,t]of this.#s.entries())clearTimeout(t.timeout),t.reject(new Error("BufferManager destroyed"));this.#s.clear();for(let[e,t]of this.#e.entries())t.ptr&&this.#t.free(t.ptr);this.#e.clear(),this.#l.clear()}};var K={totalPages:1280,ringBufferReserved:1048576,bufferPoolOffset:17825792,bufferPoolSize:66060288,get totalMemory(){return this.bufferPoolOffset+this.bufferPoolSize},get wasmHeapSize(){return this.bufferPoolOffset-this.ringBufferReserved}};var J={numBuffers:1024,maxNodes:1024,maxGraphDefs:1024,maxWireBufs:64,numAudioBusChannels:128,numInputBusChannels:0,numOutputBusChannels:2,numControlBusChannels:4096,bufLength:128,realTimeMemorySize:8192,numRGens:64,realTime:!1,memoryLocking:!1,loadGraphDefs:0,preferredSampleRate:0,verbosity:0};function Ee(s,e,t=0){for(let r=0;r<=t;r++)if(Atomics.compareExchange(s,e,0,1)===0)return!0;return!1}function ge(s,e){Atomics.store(s,e,0)}function X({atomicView:s,dataView:e,uint8View:t,bufferConstants:r,ringBufferBase:i,controlIndices:o,oscMessage:a,maxSpins:l=0}){let c=a.length,u=r.MESSAGE_HEADER_SIZE+c;if(u>r.IN_BUFFER_SIZE-r.MESSAGE_HEADER_SIZE||!Ee(s,o.IN_WRITE_LOCK,l))return!1;try{let f=Atomics.load(s,o.IN_HEAD),h=Atomics.load(s,o.IN_TAIL);if((r.IN_BUFFER_SIZE-1-f+h)%r.IN_BUFFER_SIZE<u)return!1;let m=Atomics.add(s,o.IN_SEQUENCE,1),d=r.IN_BUFFER_SIZE-f;if(u>d){let p=new Uint8Array(r.MESSAGE_HEADER_SIZE),E=new DataView(p.buffer);E.setUint32(0,r.MESSAGE_MAGIC,!0),E.setUint32(4,u,!0),E.setUint32(8,m,!0),E.setUint32(12,0,!0);let y=i+r.IN_BUFFER_START+f,T=i+r.IN_BUFFER_START;if(d>=r.MESSAGE_HEADER_SIZE){t.set(p,y);let _=d-r.MESSAGE_HEADER_SIZE;t.set(a.subarray(0,_),y+r.MESSAGE_HEADER_SIZE),t.set(a.subarray(_),T)}else{t.set(p.subarray(0,d),y),t.set(p.subarray(d),T);let _=r.MESSAGE_HEADER_SIZE-d;t.set(a,T+_)}}else{let p=i+r.IN_BUFFER_START+f;e.setUint32(p,r.MESSAGE_MAGIC,!0),e.setUint32(p+4,u,!0),e.setUint32(p+8,m,!0),e.setUint32(p+12,0,!0),t.set(a,p+r.MESSAGE_HEADER_SIZE)}Atomics.load(s,o.IN_HEAD);let w=(f+u)%r.IN_BUFFER_SIZE;return Atomics.store(s,o.IN_HEAD,w),!0}finally{ge(s,o.IN_WRITE_LOCK)}}var se=class s{static osc={encode:e=>B.writePacket(e),decode:(e,t={metadata:!1})=>B.readPacket(e,t)};#r;#n;#o;#d;#t;#i;#e;#s;#l;#c;#w;#p;#g;#y;#a;#h;#u;#m;#b;#B;#_;#f;#R=null;#I=!1;#F=100;constructor(e={}){if(this.#a=!1,this.#h=!1,this.#u={},this.#t=null,this.#i=null,this.#e=null,this.#r=null,this.#n=null,this.#o=null,this.#s=null,this.loadedSynthDefs=new Set,this.onOSC=null,this.onMessage=null,this.onMessageSent=null,this.onDebugMessage=null,this.onInitialized=null,this.onError=null,this.onMetricsUpdate=null,!e.workerBaseURL||!e.wasmBaseURL)throw new Error(`SuperSonic requires workerBaseURL and wasmBaseURL options. Example:
|
|
5
5
|
new SuperSonic({
|
|
6
6
|
workerBaseURL: "/supersonic/workers/",
|
|
7
7
|
wasmBaseURL: "/supersonic/wasm/"
|
|
8
|
-
})`);let t=e.workerBaseURL,r=e.wasmBaseURL,i={...J,...e.scsynthOptions};this.config={wasmUrl:e.wasmUrl||r+"scsynth-nrt.wasm",wasmBaseURL:r,workletUrl:e.workletUrl||t+"scsynth_audio_worklet.js",workerBaseURL:t,development:!1,audioContextOptions:{latencyHint:"interactive",sampleRate:48e3},memory:K,worldOptions:i},this.#
|
|
8
|
+
})`);let t=e.workerBaseURL,r=e.wasmBaseURL,i={...J,...e.scsynthOptions};this.config={wasmUrl:e.wasmUrl||r+"scsynth-nrt.wasm",wasmBaseURL:r,workletUrl:e.workletUrl||t+"scsynth_audio_worklet.js",workerBaseURL:t,development:!1,audioContextOptions:{latencyHint:"interactive",sampleRate:48e3},memory:K,worldOptions:i},this.#p=e.sampleBaseURL||null,this.#g=e.synthdefBaseURL||null,this.#y=e.audioPathMap||{},this.bootStats={initStartTime:null,initDuration:null}}get initialized(){return this.#a}get initializing(){return this.#h}get capabilities(){return this.#u}setAndValidateCapabilities(){this.#u={audioWorklet:typeof AudioWorklet<"u",sharedArrayBuffer:typeof SharedArrayBuffer<"u",crossOriginIsolated:window.crossOriginIsolated===!0,atomics:typeof Atomics<"u",webWorker:typeof Worker<"u"};let t=["audioWorklet","sharedArrayBuffer","crossOriginIsolated","atomics","webWorker"].filter(r=>!this.#u[r]);if(t.length>0){let r=new Error(`Missing required features: ${t.join(", ")}`);throw this.#u.crossOriginIsolated||(this.#u.sharedArrayBuffer?r.message+=`
|
|
9
9
|
|
|
10
10
|
SharedArrayBuffer is available but cross-origin isolation is not enabled. Please ensure COOP and COEP headers are set correctly:
|
|
11
11
|
Cross-Origin-Opener-Policy: same-origin
|
|
@@ -14,8 +14,5 @@ SharedArrayBuffer is available but cross-origin isolation is not enabled. Please
|
|
|
14
14
|
SharedArrayBuffer is not available. This may be due to:
|
|
15
15
|
1. Missing COOP/COEP headers
|
|
16
16
|
2. Browser doesn't support SharedArrayBuffer
|
|
17
|
-
3. Browser security settings`),r}return this.#u}#x(){let e=this.config.memory;this.#p=new WebAssembly.Memory({initial:e.totalPages,maximum:e.totalPages,shared:!0}),this.#t=this.#p.buffer}#N(){return this.#i=new AudioContext(this.config.audioContextOptions),this.#i}#L(){this.#s=new P({audioContext:this.#i,sharedBuffer:this.#t,bufferPoolConfig:{start:this.config.memory.bufferPoolOffset,size:this.config.memory.bufferPoolSize},sampleBaseURL:this.#g,audioPathMap:this.#y,maxBuffers:this.config.worldOptions.numBuffers})}async#z(){let e=this.config.wasmBaseURL+"manifest.json";try{let t=await fetch(e);if(!t.ok)return;let r=await t.json();this.config.wasmUrl=this.config.wasmBaseURL+r.wasmFile}catch{}}async#W(){this.config.development&&await this.#z();let e=await fetch(this.config.wasmUrl);if(!e.ok)throw new Error(`Failed to load WASM: ${e.status} ${e.statusText}`);return await e.arrayBuffer()}async#V(e){await this.#i.audioWorklet.addModule(this.config.workletUrl),this.#n=new AudioWorkletNode(this.#i,"scsynth-processor",{numberOfInputs:0,numberOfOutputs:1,outputChannelCount:[2]}),this.#n.connect(this.#i.destination),this.#n.port.postMessage({type:"init",sharedBuffer:this.#t}),this.#n.port.postMessage({type:"loadWasm",wasmBytes:e,wasmMemory:this.#p,worldOptions:this.config.worldOptions,sampleRate:this.#i.sampleRate}),await this.#H()}async#$(){this.#o=new R(this.config.workerBaseURL),this.#o.onRawOSC(e=>{this.onOSC&&this.onOSC(e)}),this.#o.onParsedOSC(e=>{if(e.address==="/buffer/freed")this.#s?.handleBufferFreed(e.args);else if(e.address==="/buffer/allocated")this.#s?.handleBufferAllocated(e.args);else if(e.address==="/synced"&&e.args.length>0){let t=e.args[0];this.#l&&this.#l.has(t)&&this.#l.get(t)(e)}this.onMessage&&this.onMessage(e)}),this.#o.onDebugMessage(e=>{this.onDebugMessage&&this.onDebugMessage(e)}),this.#o.onError((e,t)=>{console.error(`[SuperSonic] ${t} error:`,e),this.onError&&this.onError(new Error(`${t}: ${e}`))}),await this.#o.init(this.#t,this.#r,this.#e)}#G(){this.#a=!0,this.#d=!1,this.bootStats.initDuration=performance.now()-this.bootStats.initStartTime,this.onInitialized&&this.onInitialized({capabilities:this.#u,bootStats:this.bootStats})}async init(e={}){if(this.#a){console.warn("[SuperSonic] Already initialized");return}if(this.#d){console.warn("[SuperSonic] Initialization already in progress");return}this.config={...this.config,...e,audioContextOptions:{...this.config.audioContextOptions,...e.audioContextOptions||{}}},this.#d=!0,this.bootStats.initStartTime=performance.now();try{this.setAndValidateCapabilities(),this.#x(),this.#N(),this.#L();let t=await this.#W();await this.#V(t),await this.#$(),this.#Z(),this.#K(),this.#G()}catch(t){throw this.#d=!1,console.error("[SuperSonic] Initialization failed:",t),this.onError&&this.onError(t),t}}#H(){return new Promise((e,t)=>{let r=setTimeout(()=>{t(new Error("AudioWorklet initialization timeout"))},5e3),i=async o=>{if(o.data.type!=="debug"){if(o.data.type==="error"){console.error("[AudioWorklet] Error:",o.data.error),clearTimeout(r),this.#n.port.removeEventListener("message",i),t(new Error(o.data.error||"AudioWorklet error"));return}o.data.type==="initialized"&&(clearTimeout(r),this.#n.port.removeEventListener("message",i),o.data.success?(o.data.ringBufferBase!==void 0?this.#r=o.data.ringBufferBase:console.warn("[SuperSonic] Warning: ringBufferBase not provided by worklet"),o.data.bufferConstants!==void 0?(this.#e=o.data.bufferConstants,this.#X(),await this.initializeNTPTiming(),this.#re()):console.warn("[SuperSonic] Warning: bufferConstants not provided by worklet"),e()):t(new Error(o.data.error||"AudioWorklet initialization failed")))}};this.#n.port.addEventListener("message",i),this.#n.port.start()})}#Z(){this.#n.port.onmessage=e=>{let{data:t}=e;switch(t.type){case"error":console.error("[Worklet] Error:",t.error),t.diagnostics&&(console.error("[Worklet] Diagnostics:",t.diagnostics),console.table(t.diagnostics)),this.onError&&this.onError(new Error(t.error));break;case"process_debug":break;case"debug":break;case"console":this.onConsoleMessage&&this.onConsoleMessage(t.message);break;case"version":this.onVersion&&this.onVersion(t.version);break}}}#q(){if(!this.#t||!this.#e||!this.#r)return null;let e=this.#r+this.#e.METRICS_START,t=this.#e.METRICS_SIZE/4,r=new Uint32Array(this.#t,e,t);return{processCount:Atomics.load(r,0),messagesProcessed:Atomics.load(r,1),messagesDropped:Atomics.load(r,2),schedulerQueueDepth:Atomics.load(r,3),schedulerQueueMax:Atomics.load(r,4),schedulerQueueDropped:Atomics.load(r,5)}}#Y(){if(!this.#t||!this.#e||!this.#r)return null;let e=new Int32Array(this.#t),t=this.#r+this.#e.CONTROL_START,r=Atomics.load(e,(t+0)/4),i=Atomics.load(e,(t+4)/4),o=Atomics.load(e,(t+8)/4),a=Atomics.load(e,(t+12)/4),c=Atomics.load(e,(t+16)/4),l=Atomics.load(e,(t+20)/4),u=(r-i+this.#e.IN_BUFFER_SIZE)%this.#e.IN_BUFFER_SIZE,f=(o-a+this.#e.OUT_BUFFER_SIZE)%this.#e.OUT_BUFFER_SIZE,h=(c-l+this.#e.DEBUG_BUFFER_SIZE)%this.#e.DEBUG_BUFFER_SIZE;return{inBufferUsed:{bytes:u,percentage:u/this.#e.IN_BUFFER_SIZE*100},outBufferUsed:{bytes:f,percentage:f/this.#e.OUT_BUFFER_SIZE*100},debugBufferUsed:{bytes:h,percentage:h/this.#e.DEBUG_BUFFER_SIZE*100}}}#Q(){if(!this.#t||!this.#e||!this.#r)return null;let e=this.#r+this.#e.METRICS_START,t=this.#e.METRICS_SIZE/4,r=new Uint32Array(this.#t,e,t);return{preschedulerPending:r[6],preschedulerPeak:r[7],preschedulerSent:r[8],retriesSucceeded:r[9],retriesFailed:r[10],bundlesScheduled:r[11],eventsCancelled:r[12],totalDispatches:r[13],messagesRetried:r[14],retryQueueSize:r[15],retryQueueMax:r[16],oscInMessagesReceived:r[17],oscInDroppedMessages:r[18],oscInBytesReceived:r[19],debugMessagesReceived:r[20],debugBytesReceived:r[21],messagesSent:r[22],bytesSent:r[23],directWrites:r[25],sequenceGaps:r[24]}}#v(e,t=1){if(!this.#t||!this.#e||!this.#r)return;let r=this.#r+this.#e.METRICS_START,i=new Uint32Array(this.#t,r,this.#e.METRICS_SIZE/4),o={messagesSent:22,bytesSent:23,directWrites:25};Atomics.add(i,o[e],t)}#j(){let e=performance.now(),t={},r=this.#q();r&&Object.assign(t,r);let i=this.#Y();i&&Object.assign(t,i);let o=this.#Q();o&&Object.assign(t,o),t.driftOffsetMs=this.getDriftOffset();let a=performance.now()-e;return a>1&&console.warn(`[SuperSonic] Slow metrics gathering: ${a.toFixed(2)}ms`),t}#K(){this.#f&&clearInterval(this.#f),this.#f=setInterval(()=>{if(this.onMetricsUpdate){if(this.#M){console.warn("[SuperSonic] Metrics gathering took >100ms, skipping this interval");return}this.#M=!0;try{let e=this.#j();this.onMetricsUpdate(e)}catch(e){console.error("[SuperSonic] Metrics gathering failed:",e)}finally{this.#M=!1}}},100)}#J(){this.#f&&(clearInterval(this.#f),this.#f=null)}async send(e,...t){this.#h("send OSC messages");let r=t.map(a=>{if(typeof a=="string")return{type:"s",value:a};if(typeof a=="number")return{type:Number.isInteger(a)?"i":"f",value:a};if(a instanceof Uint8Array||a instanceof ArrayBuffer)return{type:"b",value:a instanceof ArrayBuffer?new Uint8Array(a):a};throw new Error(`Unsupported argument type: ${typeof a}`)}),i={address:e,args:r},o=s.osc.encode(i);return this.sendOSC(o)}#h(e="perform this operation"){if(!this.#a)throw new Error(`SuperSonic not initialized. Call init() before attempting to ${e}.`)}#X(){if(!this.#t||!this.#r||!this.#e){console.warn("[SuperSonic] Cannot initialize direct write views - missing buffer info");return}this.#_=new Int32Array(this.#t),this.#b=new DataView(this.#t),this.#B=new Uint8Array(this.#t);let e=this.#e.CONTROL_START;this.#A={IN_HEAD:(this.#r+e+0)/4,IN_TAIL:(this.#r+e+4)/4,IN_SEQUENCE:(this.#r+e+24)/4,IN_WRITE_LOCK:(this.#r+e+40)/4}}#ee(e){return e.length>=8&&e[0]===35}#te(e){return!this.#_||!this.#A?!1:X({atomicView:this.#_,dataView:this.#b,uint8View:this.#B,bufferConstants:this.#e,ringBufferBase:this.#r,controlIndices:this.#A,oscMessage:e})}async sendOSC(e,t={}){this.#h("send OSC data");let r=this.#se(e),i=await this.#ne(r);if(this.#v("messagesSent"),this.#v("bytesSent",i.length),this.onMessageSent&&this.onMessageSent(i),!this.#ee(i)&&this.#te(i)){this.#v("directWrites");return}let o=this.#de(i),a={...t};o&&(a.audioTimeS=o.audioTimeS,a.currentTimeS=o.currentTimeS),this.#o.send(i,a)}get audioContext(){return this.#i}get workletNode(){return this.#n}get osc(){return this.#o}getStatus(){return{initialized:this.#a,capabilities:this.#u,bootStats:this.bootStats,audioContextState:this.#i?.state}}getConfig(){return this.config?{memory:{...this.config.memory},worldOptions:{...this.config.worldOptions}}:null}async destroy(){this.#D(),this.#J(),this.#o&&(this.#o.terminate(),this.#o=null),this.#n&&(this.#n.disconnect(),this.#n=null),this.#i&&(await this.#i.close(),this.#i=null),this.#s&&(this.#s.destroy(),this.#s=null),this.#t=null,this.#a=!1,this.loadedSynthDefs.clear()}waitForTimeSync(){return this.#h("wait for time sync"),new Float64Array(this.#t,this.#r+this.#e.NTP_START_TIME_START,1)[0]}async loadSample(e,t,r=0,i=0){this.#h("load samples");let o=await this.#O().prepareFromFile({bufnum:e,path:t,startFrame:r,numFrames:i});return await this.send("/b_allocPtr",e,o.ptr,o.numFrames,o.numChannels,o.sampleRate,o.uuid),o.allocationComplete}async loadSynthDef(e){if(!this.#a)throw new Error("SuperSonic not initialized. Call init() first.");try{let t=await fetch(e);if(!t.ok)throw new Error(`Failed to load synthdef from ${e}: ${t.status} ${t.statusText}`);let r=await t.arrayBuffer(),i=new Uint8Array(r);await this.send("/d_recv",i);let o=this.#ie(e);o&&this.loadedSynthDefs.add(o)}catch(t){throw console.error("[SuperSonic] Failed to load synthdef:",t),t}}async loadSynthDefs(e){if(!this.#a)throw new Error("SuperSonic not initialized. Call init() first.");if(!this.#E)throw new Error(`synthdefBaseURL not configured. Please set it in SuperSonic constructor options.
|
|
18
|
-
Example: new SuperSonic({ synthdefBaseURL: "./dist/synthdefs/" })
|
|
19
|
-
Or use CDN: new SuperSonic({ synthdefBaseURL: "https://unpkg.com/supersonic-scsynth-synthdefs@latest/synthdefs/" })
|
|
20
|
-
Or install: npm install supersonic-scsynth-synthdefs`);let t={};await Promise.all(e.map(async i=>{try{let o=`${this.#E}${i}.scsyndef`;await this.loadSynthDef(o),t[i]={success:!0}}catch(o){console.error(`[SuperSonic] Failed to load ${i}:`,o),t[i]={success:!1,error:o.message}}}));let r=Object.values(t).filter(i=>i.success).length;return t}async sync(e){if(!this.#a)throw new Error("SuperSonic not initialized. Call init() first.");if(!Number.isInteger(e))throw new Error("sync() requires an integer syncId parameter");let t=new Promise((r,i)=>{let o=setTimeout(()=>{this.#l&&this.#l.delete(e),i(new Error("Timeout waiting for /synced response"))},1e4),a=c=>{clearTimeout(o),this.#l.delete(e),r()};this.#l||(this.#l=new Map),this.#l.set(e,a)});await this.send("/sync",e),await t}allocBuffer(e){return this.#h("allocate buffers"),this.#s.allocate(e)}freeBuffer(e){return this.#h("free buffers"),this.#s.free(e)}getBufferView(e,t){return this.#h("get buffer views"),this.#s.getView(e,t)}getBufferPoolStats(){return this.#h("get buffer pool stats"),this.#s.getStats()}getDiagnostics(){return this.#h("get diagnostics"),{buffers:this.#s.getDiagnostics(),synthdefs:{count:this.loadedSynthDefs.size}}}async initializeNTPTiming(){if(!this.#e||!this.#i)return;let e;for(;e=this.#i.getOutputTimestamp(),!(e.contextTime>0);)await new Promise(a=>setTimeout(a,50));let i=(performance.timeOrigin+e.performanceTime)/1e3+2208988800-e.contextTime,o=new Float64Array(this.#t,this.#r+this.#e.NTP_START_TIME_START,1);o[0]=i,this.#S=i}updateDriftOffset(){if(!this.#e||!this.#i||this.#S===void 0)return;let e=this.#i.getOutputTimestamp(),o=(performance.timeOrigin+e.performanceTime)/1e3+2208988800-this.#S-e.contextTime,a=Math.round(o*1e3),c=new Int32Array(this.#t,this.#r+this.#e.DRIFT_OFFSET_START,1);Atomics.store(c,0,a)}getDriftOffset(){if(!this.#e)return 0;let e=new Int32Array(this.#t,this.#r+this.#e.DRIFT_OFFSET_START,1);return Atomics.load(e,0)}#re(){this.#D(),this.#c=setInterval(()=>{this.updateDriftOffset()},15e3)}#D(){this.#c&&(clearInterval(this.#c),this.#c=null)}#ie(e){return!e||typeof e!="string"?null:(e.split("/").filter(Boolean).pop()||e).replace(/\.scsyndef$/i,"")}#se(e){if(e instanceof Uint8Array)return e;if(e instanceof ArrayBuffer)return new Uint8Array(e);throw new Error("oscData must be ArrayBuffer or Uint8Array")}async#ne(e){let t={metadata:!0,unpackSingleArgs:!1};try{let r=s.osc.decode(e,t),{packet:i,changed:o}=await this.#U(r);return o?s.osc.encode(i):e}catch(r){throw console.error("[SuperSonic] Failed to prepare OSC packet:",r),r}}async#U(e){if(e&&e.address){let{message:t,changed:r}=await this.#oe(e);return{packet:t,changed:r}}if(this.#he(e)){let t=await Promise.all(e.packets.map(o=>this.#U(o)));if(!t.some(o=>o.changed))return{packet:e,changed:!1};let i=t.map(o=>o.packet);return{packet:{timeTag:e.timeTag,packets:i},changed:!0}}return{packet:e,changed:!1}}async#oe(e){switch(e.address){case"/b_alloc":return{message:await this.#le(e),changed:!0};case"/b_allocRead":return{message:await this.#ae(e),changed:!0};case"/b_allocReadChannel":return{message:await this.#ce(e),changed:!0};default:return{message:e,changed:!1}}}async#ae(e){let t=this.#O(),r=this.#I(e.args,0,"/b_allocRead requires a buffer number"),i=this.#F(e.args,1,"/b_allocRead requires a file path"),o=this.#T(e.args,2,0),a=this.#T(e.args,3,0),c=await t.prepareFromFile({bufnum:r,path:i,startFrame:o,numFrames:a});return this.#P(c.allocationComplete,`/b_allocRead ${r}`),this.#k(r,c)}async#ce(e){let t=this.#O(),r=this.#I(e.args,0,"/b_allocReadChannel requires a buffer number"),i=this.#F(e.args,1,"/b_allocReadChannel requires a file path"),o=this.#T(e.args,2,0),a=this.#T(e.args,3,0),c=[];for(let u=4;u<(e.args?.length||0)&&this.#C(e.args[u]);u++)c.push(Math.floor(this.#w(e.args[u])));let l=await t.prepareFromFile({bufnum:r,path:i,startFrame:o,numFrames:a,channels:c.length>0?c:null});return this.#P(l.allocationComplete,`/b_allocReadChannel ${r}`),this.#k(r,l)}async#le(e){let t=this.#O(),r=this.#I(e.args,0,"/b_alloc requires a buffer number"),i=this.#I(e.args,1,"/b_alloc requires a frame count"),o=2,a=1,c=this.#i?.sampleRate||44100;this.#C(this.#m(e.args,o))&&(a=Math.max(1,this.#T(e.args,o,1)),o++),this.#m(e.args,o)?.type==="b"&&o++,this.#C(this.#m(e.args,o))&&(c=this.#w(this.#m(e.args,o)));let l=await t.prepareEmpty({bufnum:r,numFrames:i,numChannels:a,sampleRate:c});return this.#P(l.allocationComplete,`/b_alloc ${r}`),this.#k(r,l)}#k(e,t){return{address:"/b_allocPtr",args:[this.#R(e),this.#R(t.ptr),this.#R(t.numFrames),this.#R(t.numChannels),this.#ue(t.sampleRate),this.#fe(t.uuid)]}}#R(e){return{type:"i",value:Math.floor(e)}}#ue(e){return{type:"f",value:e}}#fe(e){return{type:"s",value:String(e)}}#m(e,t){if(Array.isArray(e))return e[t]}#w(e){if(e!=null)return typeof e=="object"&&Object.prototype.hasOwnProperty.call(e,"value")?e.value:e}#I(e,t,r){let i=this.#w(this.#m(e,t));if(!Number.isFinite(i))throw new Error(r);return Math.floor(i)}#T(e,t,r=0){let i=this.#w(this.#m(e,t));return Number.isFinite(i)?Math.floor(i):r}#F(e,t,r){let i=this.#w(this.#m(e,t));if(typeof i!="string")throw new Error(r);return i}#C(e){if(!e)return!1;let t=this.#w(e);return Number.isFinite(t)}#P(e,t){!e||typeof e.catch!="function"||e.catch(r=>{console.error(`[SuperSonic] ${t} allocation failed:`,r)})}#O(){if(!this.#s)throw new Error("Buffer manager not ready. Call init() before issuing buffer commands.");return this.#s}#he(e){return e&&e.timeTag!==void 0&&Array.isArray(e.packets)}#de(e){if(e.length<16||String.fromCharCode.apply(null,e.slice(0,8))!=="#bundle\0")return null;let i=new Float64Array(this.#t,this.#r+this.#e.NTP_START_TIME_START,1)[0];if(i===0)return console.warn("[SuperSonic] NTP start time not yet initialized"),null;let o=new Int32Array(this.#t,this.#r+this.#e.DRIFT_OFFSET_START,1),c=Atomics.load(o,0)/1e3,l=new Int32Array(this.#t,this.#r+this.#e.GLOBAL_OFFSET_START,1),f=Atomics.load(l,0)/1e3,h=i+c+f,S=new DataView(e.buffer,e.byteOffset),m=S.getUint32(8,!1),d=S.getUint32(12,!1);if(m===0&&(d===0||d===1))return null;let p=m+d/4294967296-h,g=this.#i.currentTime;return{audioTimeS:p,currentTimeS:g}}};export{se as SuperSonic};
|
|
17
|
+
3. Browser security settings`),r}return this.#u}#V(){let e=this.config.memory;this.#d=new WebAssembly.Memory({initial:e.totalPages,maximum:e.totalPages,shared:!0}),this.#t=this.#d.buffer}#H(){return this.#r=new AudioContext(this.config.audioContextOptions),this.#r}#G(){this.#s=new C({audioContext:this.#r,sharedBuffer:this.#t,bufferPoolConfig:{start:this.config.memory.bufferPoolOffset,size:this.config.memory.bufferPoolSize},sampleBaseURL:this.#p,audioPathMap:this.#y,maxBuffers:this.config.worldOptions.numBuffers})}async#Z(){let e=this.config.wasmBaseURL+"manifest.json";try{let t=await fetch(e);if(!t.ok)return;let r=await t.json();this.config.wasmUrl=this.config.wasmBaseURL+r.wasmFile}catch{}}async#q(){this.config.development&&await this.#Z();let e=await fetch(this.config.wasmUrl);if(!e.ok)throw new Error(`Failed to load WASM: ${e.status} ${e.statusText}`);return await e.arrayBuffer()}async#Y(e){await this.#r.audioWorklet.addModule(this.config.workletUrl),this.#n=new AudioWorkletNode(this.#r,"scsynth-processor",{numberOfInputs:0,numberOfOutputs:1,outputChannelCount:[2]}),this.#n.connect(this.#r.destination),this.#n.port.postMessage({type:"init",sharedBuffer:this.#t}),this.#n.port.postMessage({type:"loadWasm",wasmBytes:e,wasmMemory:this.#d,worldOptions:this.config.worldOptions,sampleRate:this.#r.sampleRate}),await this.#K()}async#Q(){this.#o=new R(this.config.workerBaseURL),this.#o.onRawOSC(e=>{this.onOSC&&this.onOSC(e)}),this.#o.onParsedOSC(e=>{if(e.address==="/buffer/freed")this.#s?.handleBufferFreed(e.args);else if(e.address==="/buffer/allocated")this.#s?.handleBufferAllocated(e.args);else if(e.address==="/synced"&&e.args.length>0){let t=e.args[0];this.#c&&this.#c.has(t)&&this.#c.get(t)(e)}this.onMessage&&this.onMessage(e)}),this.#o.onDebugMessage(e=>{this.onDebugMessage&&this.onDebugMessage(e)}),this.#o.onError((e,t)=>{console.error(`[SuperSonic] ${t} error:`,e),this.onError&&this.onError(new Error(`${t}: ${e}`))}),await this.#o.init(this.#t,this.#i,this.#e)}#j(){this.#a=!0,this.#h=!1,this.bootStats.initDuration=performance.now()-this.bootStats.initStartTime,this.onInitialized&&this.onInitialized({capabilities:this.#u,bootStats:this.bootStats})}async init(e={}){if(this.#a){console.warn("[SuperSonic] Already initialized");return}if(this.#h){console.warn("[SuperSonic] Initialization already in progress");return}this.config={...this.config,...e,audioContextOptions:{...this.config.audioContextOptions,...e.audioContextOptions||{}}},this.#h=!0,this.bootStats.initStartTime=performance.now();try{this.setAndValidateCapabilities(),this.#V(),this.#H(),this.#G();let t=await this.#q();await this.#Y(t),await this.#Q(),this.#J(),this.#N(),this.#j()}catch(t){throw this.#h=!1,console.error("[SuperSonic] Initialization failed:",t),this.onError&&this.onError(t),t}}#K(){return new Promise((e,t)=>{let r=setTimeout(()=>{t(new Error("AudioWorklet initialization timeout"))},5e3),i=async o=>{if(o.data.type!=="debug"){if(o.data.type==="error"){console.error("[AudioWorklet] Error:",o.data.error),clearTimeout(r),this.#n.port.removeEventListener("message",i),t(new Error(o.data.error||"AudioWorklet error"));return}o.data.type==="initialized"&&(clearTimeout(r),this.#n.port.removeEventListener("message",i),o.data.success?(o.data.ringBufferBase!==void 0?this.#i=o.data.ringBufferBase:console.warn("[SuperSonic] Warning: ringBufferBase not provided by worklet"),o.data.bufferConstants!==void 0?(this.#e=o.data.bufferConstants,this.#te(),await this.initializeNTPTiming(),this.#se()):console.warn("[SuperSonic] Warning: bufferConstants not provided by worklet"),e()):t(new Error(o.data.error||"AudioWorklet initialization failed")))}};this.#n.port.addEventListener("message",i),this.#n.port.start()})}#J(){this.#n.port.onmessage=e=>{let{data:t}=e;switch(t.type){case"error":console.error("[Worklet] Error:",t.error),t.diagnostics&&(console.error("[Worklet] Diagnostics:",t.diagnostics),console.table(t.diagnostics)),this.onError&&this.onError(new Error(t.error));break;case"process_debug":break;case"debug":break;case"console":this.onConsoleMessage&&this.onConsoleMessage(t.message);break;case"version":this.onVersion&&this.onVersion(t.version);break}}}#X(){if(!this.#f)return null;let e=this.#f;return{workletProcessCount:e[0],workletMessagesProcessed:e[1],workletMessagesDropped:e[2],workletSchedulerDepth:e[3],workletSchedulerMax:e[4],workletSchedulerDropped:e[5],workletSequenceGaps:e[24],preschedulerPending:e[6],preschedulerPeak:e[7],preschedulerSent:e[8],preschedulerRetriesSucceeded:e[9],preschedulerRetriesFailed:e[10],preschedulerBundlesScheduled:e[11],preschedulerEventsCancelled:e[12],preschedulerTotalDispatches:e[13],preschedulerMessagesRetried:e[14],preschedulerRetryQueueSize:e[15],preschedulerRetryQueueMax:e[16],preschedulerBypassed:e[25],oscInMessagesReceived:e[17],oscInMessagesDropped:e[18],oscInBytesReceived:e[19],debugMessagesReceived:e[20],debugBytesReceived:e[21],mainMessagesSent:e[22],mainBytesSent:e[23]}}#ee(){if(!this.#m||!this.#e||!this.#i)return null;let e=this.#i+this.#e.CONTROL_START,t=this.#m,r=Atomics.load(t,(e+0)/4),i=Atomics.load(t,(e+4)/4),o=Atomics.load(t,(e+8)/4),a=Atomics.load(t,(e+12)/4),l=Atomics.load(t,(e+16)/4),c=Atomics.load(t,(e+20)/4),u=(r-i+this.#e.IN_BUFFER_SIZE)%this.#e.IN_BUFFER_SIZE,f=(o-a+this.#e.OUT_BUFFER_SIZE)%this.#e.OUT_BUFFER_SIZE,h=(l-c+this.#e.DEBUG_BUFFER_SIZE)%this.#e.DEBUG_BUFFER_SIZE;return{inBufferUsed:{bytes:u,percentage:u/this.#e.IN_BUFFER_SIZE*100},outBufferUsed:{bytes:f,percentage:f/this.#e.OUT_BUFFER_SIZE*100},debugBufferUsed:{bytes:h,percentage:h/this.#e.DEBUG_BUFFER_SIZE*100}}}#k(e,t=1){if(!this.#f)return;let r={mainMessagesSent:22,mainBytesSent:23,preschedulerBypassed:25};Atomics.add(this.#f,r[e],t)}#x(){let e=performance.now(),t=this.#X()||{},r=this.#ee();if(r&&Object.assign(t,r),t.driftOffsetMs=this.getDriftOffset(),t.audioContextState=this.#r?.state||"unknown",this.#s){let o=this.#s.getStats();t.bufferPoolUsedBytes=o.used,t.bufferPoolAvailableBytes=o.available,t.bufferPoolAllocations=o.allocations}t.loadedSynthDefs=this.loadedSynthDefs?.size||0;let i=performance.now()-e;return i>1&&console.warn(`[SuperSonic] Slow metrics gathering: ${i.toFixed(2)}ms`),t}#N(){this.#P();let e=this.#F;this.#R=setInterval(()=>{if(this.onMetricsUpdate){if(this.#I){console.warn(`[SuperSonic] Metrics gathering took >${e}ms, skipping this interval`);return}this.#I=!0;try{let t=this.#x();this.onMetricsUpdate(t)}catch(t){console.error("[SuperSonic] Metrics gathering failed:",t)}finally{this.#I=!1}}},e)}#P(){this.#R&&(clearInterval(this.#R),this.#R=null)}getMetrics(){return this.#x()}setMetricsInterval(e){this.#F=e,this.#N()}stopMetricsPolling(){this.#P()}async send(e,...t){this.#A("send OSC messages");let r=t.map(a=>{if(typeof a=="string")return{type:"s",value:a};if(typeof a=="number")return{type:Number.isInteger(a)?"i":"f",value:a};if(a instanceof Uint8Array||a instanceof ArrayBuffer)return{type:"b",value:a instanceof ArrayBuffer?new Uint8Array(a):a};throw new Error(`Unsupported argument type: ${typeof a}`)}),i={address:e,args:r},o=s.osc.encode(i);return this.sendOSC(o)}#A(e="perform this operation"){if(!this.#a)throw new Error(`SuperSonic not initialized. Call init() before attempting to ${e}.`)}#te(){if(!this.#t||!this.#i||!this.#e){console.warn("[SuperSonic] Cannot initialize direct write views - missing buffer info");return}this.#m=new Int32Array(this.#t),this.#b=new DataView(this.#t),this.#B=new Uint8Array(this.#t);let e=this.#i+this.#e.METRICS_START;this.#f=new Uint32Array(this.#t,e,this.#e.METRICS_SIZE/4);let t=this.#e.CONTROL_START;this.#_={IN_HEAD:(this.#i+t+0)/4,IN_TAIL:(this.#i+t+4)/4,IN_SEQUENCE:(this.#i+t+24)/4,IN_WRITE_LOCK:(this.#i+t+40)/4}}#re(e){return e.length>=8&&e[0]===35}#ie(e){return!this.#m||!this.#_?!1:X({atomicView:this.#m,dataView:this.#b,uint8View:this.#B,bufferConstants:this.#e,ringBufferBase:this.#i,controlIndices:this.#_,oscMessage:e})}async sendOSC(e,t={}){this.#A("send OSC data");let r=this.#oe(e),i=await this.#ae(r);if(this.#k("mainMessagesSent"),this.#k("mainBytesSent",i.length),this.onMessageSent&&this.onMessageSent(i),!this.#re(i)&&this.#ie(i)){this.#k("preschedulerBypassed");return}let o=this.#me(i),a={...t};o&&(a.audioTimeS=o.audioTimeS,a.currentTimeS=o.currentTimeS),this.#o.send(i,a)}get audioContext(){return this.#r}get workletNode(){return this.#n}get osc(){return this.#o}getInfo(){return this.#A("get info"),{sampleRate:this.#r.sampleRate,numBuffers:this.config.worldOptions.numBuffers,totalMemory:this.config.memory.totalMemory,wasmHeapSize:this.config.memory.wasmHeapSize,bufferPoolSize:this.config.memory.bufferPoolSize,bootTimeMs:this.bootStats.initDuration,capabilities:{...this.#u}}}async destroy(){this.#z(),this.#P(),this.#o&&(this.#o.terminate(),this.#o=null),this.#n&&(this.#n.disconnect(),this.#n=null),this.#r&&(await this.#r.close(),this.#r=null),this.#s&&(this.#s.destroy(),this.#s=null),this.#t=null,this.#a=!1,this.loadedSynthDefs.clear()}waitForTimeSync(){return this.#A("wait for time sync"),new Float64Array(this.#t,this.#i+this.#e.NTP_START_TIME_START,1)[0]}async loadSample(e,t,r=0,i=0){this.#A("load samples");let o;if(this.#L(t))o=t;else{if(!this.#p)throw new Error("sampleBaseURL not configured. Either provide a full path or set sampleBaseURL in constructor options.");o=`${this.#p}${t}`}let a=await this.#O().prepareFromFile({bufnum:e,path:o,startFrame:r,numFrames:i});return await this.send("/b_allocPtr",e,a.ptr,a.numFrames,a.numChannels,a.sampleRate,a.uuid),a.allocationComplete}#L(e){return e.includes("/")||e.includes("://")}async loadSynthDef(e){if(!this.#a)throw new Error("SuperSonic not initialized. Call init() first.");let t;if(this.#L(e))t=e;else{if(!this.#g)throw new Error("synthdefBaseURL not configured. Either provide a full path or set synthdefBaseURL in constructor options.");t=`${this.#g}${e}.scsyndef`}try{let r=await fetch(t);if(!r.ok)throw new Error(`Failed to load synthdef from ${t}: ${r.status} ${r.statusText}`);let i=await r.arrayBuffer(),o=new Uint8Array(i);await this.send("/d_recv",o);let a=this.#ne(t);a&&this.loadedSynthDefs.add(a)}catch(r){throw console.error("[SuperSonic] Failed to load synthdef:",r),r}}async loadSynthDefs(e){if(!this.#a)throw new Error("SuperSonic not initialized. Call init() first.");let t={};await Promise.all(e.map(async i=>{try{await this.loadSynthDef(i),t[i]={success:!0}}catch(o){console.error(`[SuperSonic] Failed to load ${i}:`,o),t[i]={success:!1,error:o.message}}}));let r=Object.values(t).filter(i=>i.success).length;return t}async sync(e){if(!this.#a)throw new Error("SuperSonic not initialized. Call init() first.");if(!Number.isInteger(e))throw new Error("sync() requires an integer syncId parameter");let t=new Promise((r,i)=>{let o=setTimeout(()=>{this.#c&&this.#c.delete(e),i(new Error("Timeout waiting for /synced response"))},1e4),a=l=>{clearTimeout(o),this.#c.delete(e),r()};this.#c||(this.#c=new Map),this.#c.set(e,a)});await this.send("/sync",e),await t}#Se(){return this.#s?.getStats()}async initializeNTPTiming(){if(!this.#e||!this.#r)return;let e;for(;e=this.#r.getOutputTimestamp(),!(e.contextTime>0);)await new Promise(a=>setTimeout(a,50));let i=(performance.timeOrigin+e.performanceTime)/1e3+2208988800-e.contextTime,o=new Float64Array(this.#t,this.#i+this.#e.NTP_START_TIME_START,1);o[0]=i,this.#w=i}updateDriftOffset(){if(!this.#e||!this.#r||this.#w===void 0)return;let e=this.#r.getOutputTimestamp(),o=(performance.timeOrigin+e.performanceTime)/1e3+2208988800-this.#w-e.contextTime,a=Math.round(o*1e3),l=new Int32Array(this.#t,this.#i+this.#e.DRIFT_OFFSET_START,1);Atomics.store(l,0,a)}getDriftOffset(){if(!this.#e)return 0;let e=new Int32Array(this.#t,this.#i+this.#e.DRIFT_OFFSET_START,1);return Atomics.load(e,0)}#se(){this.#z(),this.#l=setInterval(()=>{this.updateDriftOffset()},15e3)}#z(){this.#l&&(clearInterval(this.#l),this.#l=null)}#ne(e){return!e||typeof e!="string"?null:(e.split("/").filter(Boolean).pop()||e).replace(/\.scsyndef$/i,"")}#oe(e){if(e instanceof Uint8Array)return e;if(e instanceof ArrayBuffer)return new Uint8Array(e);throw new Error("oscData must be ArrayBuffer or Uint8Array")}async#ae(e){let t={metadata:!0,unpackSingleArgs:!1};try{let r=s.osc.decode(e,t),{packet:i,changed:o}=await this.#$(r);return o?s.osc.encode(i):e}catch(r){throw console.error("[SuperSonic] Failed to prepare OSC packet:",r),r}}async#$(e){if(e&&e.address){let{message:t,changed:r}=await this.#le(e);return{packet:t,changed:r}}if(this.#pe(e)){let t=await Promise.all(e.packets.map(o=>this.#$(o)));if(!t.some(o=>o.changed))return{packet:e,changed:!1};let i=t.map(o=>o.packet);return{packet:{timeTag:e.timeTag,packets:i},changed:!0}}return{packet:e,changed:!1}}async#le(e){switch(e.address){case"/b_alloc":return{message:await this.#fe(e),changed:!0};case"/b_allocRead":return{message:await this.#ce(e),changed:!0};case"/b_allocReadChannel":return{message:await this.#ue(e),changed:!0};default:return{message:e,changed:!1}}}async#ce(e){let t=this.#O(),r=this.#v(e.args,0,"/b_allocRead requires a buffer number"),i=this.#W(e.args,1,"/b_allocRead requires a file path"),o=this.#T(e.args,2,0),a=this.#T(e.args,3,0),l=await t.prepareFromFile({bufnum:r,path:i,startFrame:o,numFrames:a});return this.#U(l.allocationComplete,`/b_allocRead ${r}`),this.#C(r,l)}async#ue(e){let t=this.#O(),r=this.#v(e.args,0,"/b_allocReadChannel requires a buffer number"),i=this.#W(e.args,1,"/b_allocReadChannel requires a file path"),o=this.#T(e.args,2,0),a=this.#T(e.args,3,0),l=[];for(let u=4;u<(e.args?.length||0)&&this.#D(e.args[u]);u++)l.push(Math.floor(this.#E(e.args[u])));let c=await t.prepareFromFile({bufnum:r,path:i,startFrame:o,numFrames:a,channels:l.length>0?l:null});return this.#U(c.allocationComplete,`/b_allocReadChannel ${r}`),this.#C(r,c)}async#fe(e){let t=this.#O(),r=this.#v(e.args,0,"/b_alloc requires a buffer number"),i=this.#v(e.args,1,"/b_alloc requires a frame count"),o=2,a=1,l=this.#r?.sampleRate||44100;this.#D(this.#S(e.args,o))&&(a=Math.max(1,this.#T(e.args,o,1)),o++),this.#S(e.args,o)?.type==="b"&&o++,this.#D(this.#S(e.args,o))&&(l=this.#E(this.#S(e.args,o)));let c=await t.prepareEmpty({bufnum:r,numFrames:i,numChannels:a,sampleRate:l});return this.#U(c.allocationComplete,`/b_alloc ${r}`),this.#C(r,c)}#C(e,t){return{address:"/b_allocPtr",args:[this.#M(e),this.#M(t.ptr),this.#M(t.numFrames),this.#M(t.numChannels),this.#he(t.sampleRate),this.#de(t.uuid)]}}#M(e){return{type:"i",value:Math.floor(e)}}#he(e){return{type:"f",value:e}}#de(e){return{type:"s",value:String(e)}}#S(e,t){if(Array.isArray(e))return e[t]}#E(e){if(e!=null)return typeof e=="object"&&Object.prototype.hasOwnProperty.call(e,"value")?e.value:e}#v(e,t,r){let i=this.#E(this.#S(e,t));if(!Number.isFinite(i))throw new Error(r);return Math.floor(i)}#T(e,t,r=0){let i=this.#E(this.#S(e,t));return Number.isFinite(i)?Math.floor(i):r}#W(e,t,r){let i=this.#E(this.#S(e,t));if(typeof i!="string")throw new Error(r);return i}#D(e){if(!e)return!1;let t=this.#E(e);return Number.isFinite(t)}#U(e,t){!e||typeof e.catch!="function"||e.catch(r=>{console.error(`[SuperSonic] ${t} allocation failed:`,r)})}#O(){if(!this.#s)throw new Error("Buffer manager not ready. Call init() before issuing buffer commands.");return this.#s}#pe(e){return e&&e.timeTag!==void 0&&Array.isArray(e.packets)}#me(e){if(e.length<16||String.fromCharCode.apply(null,e.slice(0,8))!=="#bundle\0")return null;let i=new Float64Array(this.#t,this.#i+this.#e.NTP_START_TIME_START,1)[0];if(i===0)return console.warn("[SuperSonic] NTP start time not yet initialized"),null;let o=new Int32Array(this.#t,this.#i+this.#e.DRIFT_OFFSET_START,1),l=Atomics.load(o,0)/1e3,c=new Int32Array(this.#t,this.#i+this.#e.GLOBAL_OFFSET_START,1),f=Atomics.load(c,0)/1e3,h=i+l+f,S=new DataView(e.buffer,e.byteOffset),m=S.getUint32(8,!1),d=S.getUint32(12,!1);if(m===0&&(d===0||d===1))return null;let p=m+d/4294967296-h,E=this.#r.currentTime;return{audioTimeS:p,currentTimeS:E}}};export{se as SuperSonic};
|
|
21
18
|
/*! osc.js 2.4.5, Copyright 2024 Colin Clark | github.com/colinbdclark/osc.js */
|
package/dist/wasm/manifest.json
CHANGED
|
Binary file
|
package/package.json
CHANGED