supersonic-scsynth 0.52.0 → 0.53.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 +8 -1
- package/dist/supersonic.js +5 -5
- package/package.json +10 -3
- package/supersonic.d.ts +218 -13
package/README.md
CHANGED
|
@@ -96,7 +96,14 @@ SuperSonic is brought to you by Sam Aaron. Please consider joining the community
|
|
|
96
96
|
|
|
97
97
|
See [LICENSE](LICENSE) for details.
|
|
98
98
|
|
|
99
|
-
SuperSonic is
|
|
99
|
+
SuperSonic is structured to cleanly separate and isolate the GPL-licensed code (SuperCollider's scsynth WASM engine and its AudioWorklet) from the MIT-licensed code (everything else). This separation consists of:
|
|
100
|
+
|
|
101
|
+
- **Separate packages** — GPL code is distributed independently in `supersonic-scsynth-core`
|
|
102
|
+
- **Separate execution contexts** — the GPL code runs in a restricted and highly-isolated AudioWorklet thread
|
|
103
|
+
- **Protocol boundary** — all communication uses the OSC protocol; there is no linking and no function calls across the boundary
|
|
104
|
+
- **Transport only** — in SharedArrayBuffer mode, the shared memory is used purely as a transport layer (ring buffers for OSC messages, a memory region for audio sample data, flat arrays for metrics). In postMessage mode, all data crosses via `postMessage`
|
|
105
|
+
|
|
106
|
+
Your application code interacts only with the MIT-licensed client API and is not intended to be a derivative work of the GPL components.
|
|
100
107
|
|
|
101
108
|
**Bundler note:** This isolation depends on the GPL code remaining a separate package loaded at runtime. If `supersonic-scsynth-core` is bundled into your application by a JavaScript bundler (webpack, Rollup, esbuild, etc.), the result is a single combined work and the GPL applies to the entire bundle.
|
|
102
109
|
|
package/dist/supersonic.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var Rt=Object.defineProperty;var It=(i,e)=>{for(var t in e)Rt(i,t,{get:e[t],enumerable:!0})};var O=class i{constructor(e){if(new.target===i)throw new Error("Transport is abstract - use SABTransport or PostMessageTransport");this._config=e,this._disposed=!1}get mode(){return this._config.mode}send(e,t){throw new Error("Abstract method - implement in subclass")}onReply(e){throw new Error("Abstract method - implement in subclass")}onDebug(e){throw new Error("Abstract method - implement in subclass")}onError(e){throw new Error("Abstract method - implement in subclass")}getMetrics(){throw new Error("Abstract method - implement in subclass")}async initialize(){throw new Error("Abstract method - implement in subclass")}createOscChannel(){throw new Error("Abstract method - implement in subclass")}dispose(){this._disposed=!0}get ready(){throw new Error("Abstract method - implement in subclass")}};var pe=new Map;function ze(i){try{return new URL(i,window.location.href).origin!==window.location.origin}catch{return!1}}async function Ye(i){if(pe.has(i))return pe.get(i);let e=await fetch(i);if(!e.ok)throw new Error(`Failed to fetch ${i}: ${e.status} ${e.statusText}`);let t=await e.text(),s=new Blob([t],{type:"application/javascript"}),r=URL.createObjectURL(s);return pe.set(i,r),r}async function U(i,e={}){let t=i;return ze(i)&&(t=await Ye(i)),new Worker(t,e)}async function Ge(i,e){let t=e;ze(e)&&(t=await Ye(e)),await i.addModule(t)}function $e(i,e,t){return(t-1-i+e)%t}function We({uint8View:i,dataView:e,bufferStart:t,bufferSize:s,head:r,payload:n,sequence:o,messageMagic:a,headerSize:c,sourceId:l=0,headerScratch:f=null,headerScratchView:u=null}){let d=n.length,m=c+d+3&-4,g=s-r;if(m>g){let y=f||new Uint8Array(c),S=u||new DataView(y.buffer);S.setUint32(0,a,!0),S.setUint32(4,m,!0),S.setUint32(8,o,!0),S.setUint32(12,l,!0);let _=t+r,h=t;if(g>=c){i.set(y,_);let T=g-c;T>0&&i.set(n.subarray(0,T),_+c),i.set(n.subarray(T),h)}else{i.set(y.subarray(0,g),_),i.set(y.subarray(g),h);let T=c-g;i.set(n,h+T)}}else{let y=t+r;e.setUint32(y,a,!0),e.setUint32(y+4,m,!0),e.setUint32(y+8,o,!0),e.setUint32(y+12,l,!0),i.set(n,y+c)}return(r+m)%s}function Dt(i,e,t=0,s=!1){for(let r=0;r<=t;r++)if(Atomics.compareExchange(i,e,0,1)===0)return!0;if(s){for(let n=0;n<100;n++)if(Atomics.wait(i,e,1,100),Atomics.compareExchange(i,e,0,1)===0)return!0;return console.error("[RingBuffer] Lock acquisition timeout after 10s - possible deadlock"),!1}return!1}function Lt(i,e){Atomics.store(i,e,0),Atomics.notify(i,e,1)}function Ve({atomicView:i,dataView:e,uint8View:t,bufferConstants:s,ringBufferBase:r,controlIndices:n,oscMessage:o,sourceId:a=0,maxSpins:c=0,useWait:l=!1}){let f=o.length,u=s.MESSAGE_HEADER_SIZE+f;if(u>s.IN_BUFFER_SIZE-s.MESSAGE_HEADER_SIZE||!Dt(i,n.IN_WRITE_LOCK,c,l))return!1;try{let d=Atomics.load(i,n.IN_HEAD),p=Atomics.load(i,n.IN_TAIL),m=u+3&-4;if($e(d,p,s.IN_BUFFER_SIZE)<m)return!1;let y=Atomics.add(i,n.IN_SEQUENCE,1),S=We({uint8View:t,dataView:e,bufferStart:r+s.IN_BUFFER_START,bufferSize:s.IN_BUFFER_SIZE,head:d,payload:o,sequence:y,messageMagic:s.MESSAGE_MAGIC,headerSize:s.MESSAGE_HEADER_SIZE,sourceId:a});return Atomics.load(i,n.IN_HEAD),Atomics.store(i,n.IN_HEAD,S),Atomics.notify(i,n.IN_HEAD,1),!0}finally{Lt(i,n.IN_WRITE_LOCK)}}function Z(i,e){let t=i+e;return{IN_HEAD:(t+0)/4,IN_TAIL:(t+4)/4,IN_SEQUENCE:(t+24)/4,IN_WRITE_LOCK:(t+40)/4,IN_LOG_TAIL:(t+44)/4}}function Ze(i,e){let t=i+e;return{IN_HEAD:(t+0)/4,IN_TAIL:(t+4)/4,OUT_HEAD:(t+8)/4,OUT_TAIL:(t+12)/4,DEBUG_HEAD:(t+16)/4,DEBUG_TAIL:(t+20)/4,IN_SEQUENCE:(t+24)/4,OUT_SEQUENCE:(t+28)/4,DEBUG_SEQUENCE:(t+32)/4,STATUS_FLAGS:(t+36)/4,IN_WRITE_LOCK:(t+40)/4,IN_LOG_TAIL:(t+44)/4}}function Pt(i){return i.length>=8&&i[0]===35&&i[1]===98&&i[2]===117&&i[3]===110&&i[4]===100&&i[5]===108&&i[6]===101&&i[7]===0}function me(i){if(i.length<16)return null;let e=new DataView(i.buffer,i.byteOffset,i.byteLength);return{ntpSeconds:e.getUint32(8,!1),ntpFraction:e.getUint32(12,!1)}}function w(){return(performance.timeOrigin+performance.now())/1e3+2208988800}function Xe(i,e={}){let{getCurrentNTP:t=w,bypassLookaheadS:s=.5}=e;if(!Pt(i))return"nonBundle";let r=me(i);if(!r)return"nonBundle";let{ntpSeconds:n,ntpFraction:o}=r;if(n===0&&o<=1)return"immediate";let a=t();if(a===null||a===0)return"immediate";let l=n+o/4294967296-a;return l<0?"late":l<s?"nearFuture":"farFuture"}function X(i){return i!=="farFuture"}var M=class i{#r;#e;#t;#h;#n;#s;#l;#o;#a;#c;#u={messagesSent:0,bytesSent:0,nonBundle:0,immediate:0,nearFuture:0,late:0,bypassed:0};constructor(e,t){if(this.#r=e,this.#n=t.preschedulerPort||null,this.#l=t.bypassLookaheadS??.5,this.#o=t.sourceId??0,this.#a=t.blocking??this.#o!==0,this.#c=t.getCurrentNTP??w,e==="postMessage")this.#e=t.port;else if(this.#t={sharedBuffer:t.sharedBuffer,ringBufferBase:t.ringBufferBase,bufferConstants:t.bufferConstants,controlIndices:t.controlIndices},this.#p(),t.sharedBuffer&&t.bufferConstants){let s=t.ringBufferBase+t.bufferConstants.METRICS_START;this.#s=new Int32Array(t.sharedBuffer,s,t.bufferConstants.METRICS_SIZE/4)}}#p(){let e=this.#t.sharedBuffer;this.#h={atomicView:new Int32Array(e),dataView:new DataView(e),uint8View:new Uint8Array(e)}}classify(e){return Xe(e,{getCurrentNTP:this.#c,bypassLookaheadS:this.#l})}#_(e,t=null){if(this.#r==="sab"&&this.#s){if(Atomics.add(this.#s,24,1),Atomics.add(this.#s,25,e),t){let r={nonBundle:38,immediate:39,nearFuture:40,late:41}[t];r!==void 0&&(Atomics.add(this.#s,r,1),Atomics.add(this.#s,22,1))}}else this.#u.messagesSent++,this.#u.bytesSent+=e,t&&t in this.#u&&(this.#u[t]++,this.#u.bypassed++)}getAndResetMetrics(){let e={...this.#u};return this.#u={messagesSent:0,bytesSent:0,nonBundle:0,immediate:0,nearFuture:0,late:0,bypassed:0},e}getMetrics(){return this.#r==="sab"&&this.#s?{messagesSent:Atomics.load(this.#s,24),bytesSent:Atomics.load(this.#s,25),nonBundle:Atomics.load(this.#s,38),immediate:Atomics.load(this.#s,39),nearFuture:Atomics.load(this.#s,40),late:Atomics.load(this.#s,41),bypassed:Atomics.load(this.#s,22)}:{...this.#u}}#m(e,t=null,s=!0){if(this.#r==="postMessage")return this.#e?(this.#e.postMessage({type:"osc",oscData:e,bypassCategory:t,sourceId:this.#o}),!0):!1;{let r=this.#a,n=Ve({atomicView:this.#h.atomicView,dataView:this.#h.dataView,uint8View:this.#h.uint8View,bufferConstants:this.#t.bufferConstants,ringBufferBase:this.#t.ringBufferBase,controlIndices:this.#t.controlIndices,oscMessage:e,sourceId:this.#o,maxSpins:r?10:0,useWait:r});return!n&&!r&&s&&this.#n?(this.#s&&Atomics.add(this.#s,45,1),this.#n.postMessage({type:"directDispatch",oscData:e,sourceId:this.#o}),!0):n}}#d(e){return this.#n?(this.#n.postMessage({type:"osc",oscData:e,sourceId:this.#o}),!0):(console.error("[OscChannel] No prescheduler port, sending direct"),this.#m(e))}send(e){let t=this.classify(e);if(X(t)){let s=this.#m(e,t);return s&&this.#_(e.length,t),s}else{let s=this.#d(e);return s&&this.#_(e.length,null),s}}sendDirect(e){return this.#m(e)}sendToPrescheduler(e){return this.#d(e)}set getCurrentNTP(e){this.#c=e}get mode(){return this.#r}get transferable(){let e={mode:this.#r,preschedulerPort:this.#n,bypassLookaheadS:this.#l,sourceId:this.#o,blocking:this.#a};return this.#r==="postMessage"?{...e,port:this.#e}:{...e,sharedBuffer:this.#t.sharedBuffer,ringBufferBase:this.#t.ringBufferBase,bufferConstants:this.#t.bufferConstants,controlIndices:this.#t.controlIndices}}get transferList(){let e=[];return this.#r==="postMessage"&&this.#e&&e.push(this.#e),this.#n&&e.push(this.#n),e}close(){this.#r==="postMessage"&&this.#e&&(this.#e.close(),this.#e=null),this.#n&&(this.#n.close(),this.#n=null)}static createPostMessage(e){return e instanceof MessagePort?new i("postMessage",{port:e}):new i("postMessage",e)}static createSAB(e){let t=e.controlIndices;return t||(t=Z(e.ringBufferBase,e.bufferConstants.CONTROL_START)),new i("sab",{sharedBuffer:e.sharedBuffer,ringBufferBase:e.ringBufferBase,bufferConstants:e.bufferConstants,controlIndices:t,preschedulerPort:e.preschedulerPort,bypassLookaheadS:e.bypassLookaheadS,sourceId:e.sourceId,blocking:e.blocking})}static fromTransferable(e){return e.mode==="postMessage"?new i("postMessage",{port:e.port,preschedulerPort:e.preschedulerPort,bypassLookaheadS:e.bypassLookaheadS,sourceId:e.sourceId,blocking:e.blocking}):new i("sab",{sharedBuffer:e.sharedBuffer,ringBufferBase:e.ringBufferBase,bufferConstants:e.bufferConstants,controlIndices:e.controlIndices,preschedulerPort:e.preschedulerPort,bypassLookaheadS:e.bypassLookaheadS,sourceId:e.sourceId,blocking:e.blocking})}};var v=class extends O{#r;#e;#t;#h;#n;#s;#l;#o;#a;#c;#u;#p;#_;#m;#d;#S;#b=1;#g=!1;#i;#f=0;#y=0;#E=0;#A=null;constructor(e){if(super({...e,mode:"sab"}),this.#r=e.sharedBuffer,this.#e=e.ringBufferBase,this.#t=e.bufferConstants,this.#p=e.workerBaseURL,this.#i=e.preschedulerCapacity||65536,!(this.#r instanceof SharedArrayBuffer))throw new Error("SABTransport requires a SharedArrayBuffer");this.#w()}async initialize(){if(this.#g)return;let[e,t,s,r]=await Promise.all([U(this.#p+"osc_out_prescheduler_worker.js",{type:"module"}),U(this.#p+"osc_in_worker.js",{type:"module"}),U(this.#p+"debug_worker.js",{type:"module"}),U(this.#p+"osc_out_log_sab_worker.js",{type:"module"})]);this.#o=e,this.#a=t,this.#c=s,this.#u=r,this.#B(),await Promise.all([this.#M(this.#o,"OSC OUT",{maxPendingMessages:this.#i,bypassLookaheadS:this._config.bypassLookaheadS}),this.#M(this.#a,"OSC IN"),this.#M(this.#c,"DEBUG"),this.#M(this.#u,"OSC OUT LOG")]),this.#a.postMessage({type:"start"}),this.#c.postMessage({type:"start"}),this.#u.postMessage({type:"start"}),this.#g=!0}send(e,t){return!this.#g||this._disposed?!1:(this.#o.postMessage({type:"send",oscData:e,sessionId:0,runTag:"",audioTimeS:null,currentTimeS:null}),this.#f++,this.#E+=e.length,!0)}sendWithOptions(e,t={}){if(!this.#g||this._disposed)return!1;let{sessionId:s=0,runTag:r="",audioTimeS:n=null,currentTimeS:o=null}=t;return this.#o.postMessage({type:"send",oscData:e,sessionId:s,runTag:r,audioTimeS:n,currentTimeS:o}),this.#f++,this.#E+=e.length,!0}sendImmediate(e){return!this.#g||this._disposed?!1:(this.#o.postMessage({type:"sendImmediate",oscData:e}),this.#f++,this.#E+=e.length,!0)}createOscChannel(e={}){if(!this.#g)throw new Error("Transport not initialized");let t=e.sourceId??this.#b++,s=new MessageChannel;return this.#o.postMessage({type:"addOscSource"},[s.port1]),M.createSAB({sharedBuffer:this.#r,ringBufferBase:this.#e,bufferConstants:this.#t,controlIndices:this.#l,preschedulerPort:s.port2,bypassLookaheadS:this._config.bypassLookaheadS,sourceId:t,blocking:e.blocking})}cancelSessionTag(e,t){this.#g&&this.#o.postMessage({type:"cancelSessionTag",sessionId:e,runTag:t})}cancelSession(e){this.#g&&this.#o.postMessage({type:"cancelSession",sessionId:e})}cancelTag(e){this.#g&&this.#o.postMessage({type:"cancelTag",runTag:e})}cancelAll(){this.#g&&this.#o.postMessage({type:"cancelAll"})}cancelAllWithAck(){return this.#g?new Promise(e=>{let t=s=>{s.data.type==="cancelAllAck"&&(this.#o.removeEventListener("message",t),e())};this.#o.addEventListener("message",t),this.#o.postMessage({type:"cancelAll",ack:!0})}):Promise.resolve()}onReply(e){this.#_=e}onDebug(e){this.#m=e}onError(e){this.#d=e}onOscLog(e){this.#S=e}handleOscLog(e){this.#S&&this.#S(e)}getMetrics(){return{oscOutMessagesSent:this.#f,oscOutMessagesDropped:this.#y,oscOutBytesSent:this.#E}}get ready(){return this.#g&&!this._disposed}dispose(){this._disposed||(this.#o&&(this.#o.postMessage({type:"stop"}),this.#o.terminate(),this.#o=null),this.#a&&(this.#a.postMessage({type:"stop"}),this.#a.terminate(),this.#a=null),this.#c&&(this.#c.postMessage({type:"stop"}),this.#c.terminate(),this.#c=null),this.#u&&(this.#u.postMessage({type:"stop"}),this.#u.terminate(),this.#u=null),this.#g=!1,super.dispose())}#w(){this.#h=new Int32Array(this.#r),this.#n=new DataView(this.#r),this.#s=new Uint8Array(this.#r),this.#l=Z(this.#e,this.#t.CONTROL_START)}#M(e,t,s={}){return new Promise((r,n)=>{let o=setTimeout(()=>{n(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.#r,ringBufferBase:this.#e,bufferConstants:this.#t,...s})})}#B(){this.#a.onmessage=e=>{let t=e.data;t.type==="messages"&&this.#_?t.messages.forEach(s=>{s.oscData&&this.#_(s.oscData,s.sequence,s.timestamp)}):t.type==="error"&&(console.error("[SABTransport] OSC IN error:",t.error),this.#d&&this.#d(t.error,"oscIn"))},this.#c.onmessage=e=>{let t=e.data;t.type==="debug"&&this.#m?t.messages.forEach(s=>{this.#m(s)}):t.type==="error"&&(console.error("[SABTransport] DEBUG error:",t.error),this.#d&&this.#d(t.error,"debug"))},this.#o.onmessage=e=>{let t=e.data;t.type==="preschedulerMetrics"?this.#A=t.metrics:t.type==="error"&&(console.error("[SABTransport] OSC OUT error:",t.error),this.#y++,this.#d&&this.#d(t.error,"oscOut"))},this.#u.onmessage=e=>{let t=e.data;t.type==="oscLog"&&this.#S?this.#S(t.entries):t.type==="error"&&(console.error("[SABTransport] OSC OUT LOG error:",t.error),this.#d&&this.#d(t.error,"oscOutLog"))}}getPreschedulerMetrics(){return this.#A}};var H=class extends O{#r;#e;#t;#h;#n;#s;#l;#o=1;#a=null;#c=!1;#u;#p;#_=null;#m=0;#d=0;#S=0;#b=0;#g=0;#i=-1;#f=0;#y=0;#E;#A;constructor(e){super({...e,mode:"postMessage"}),this.#t=e.workerBaseURL,this.#u=e.preschedulerCapacity||65536,this.#p=e.snapshotIntervalMs,this.#E=e.getAudioContextTime,this.#A=e.getNTPStartTime}async initialize(e){if(this.#c)return;if(!e)throw new Error("PostMessageTransport requires workletPort");this.#r=e,this.#r.onmessage=s=>{this.#M(s.data)};let t=new MessageChannel;this.#r.postMessage({type:"addOscPort"},[t.port1]),this.#e=await U(this.#t+"osc_out_prescheduler_worker.js",{type:"module"}),this.#e.onmessage=s=>{this.#B(s.data)},await this.#w(t.port2),this.#c=!0}setBufferConstants(e){this.#_=e}send(e,t){return!this.#c||this._disposed?!1:(this.#e.postMessage({type:"send",oscData:e,sessionId:0,runTag:"",audioTimeS:null,currentTimeS:null}),this.#m++,this.#S+=e.length,!0)}sendWithOptions(e,t={}){if(!this.#c||this._disposed)return!1;let{sessionId:s=0,runTag:r="",audioTimeS:n=null,currentTimeS:o=null}=t;return this.#e.postMessage({type:"send",oscData:e,sessionId:s,runTag:r,audioTimeS:n,currentTimeS:o}),this.#m++,this.#S+=e.length,!0}sendImmediate(e,t){return!this.#c||this._disposed?!1:(this.#r.postMessage({type:"osc",oscData:e,bypassCategory:t}),this.#m++,this.#S+=e.length,!0)}createOscChannel(e={}){if(!this.#c)throw new Error("Transport not initialized");let t=e.sourceId??this.#o++,s=new MessageChannel;this.#r.postMessage({type:"addOscPort",sourceId:t},[s.port1]);let r=new MessageChannel;return this.#e.postMessage({type:"addOscSource"},[r.port1]),M.createPostMessage({port:s.port2,preschedulerPort:r.port2,bypassLookaheadS:this._config.bypassLookaheadS,sourceId:t,blocking:e.blocking})}cancelSessionTag(e,t){this.#c&&this.#e.postMessage({type:"cancelSessionTag",sessionId:e,runTag:t})}cancelSession(e){this.#c&&this.#e.postMessage({type:"cancelSession",sessionId:e})}cancelTag(e){this.#c&&this.#e.postMessage({type:"cancelTag",runTag:e})}cancelAll(){this.#c&&this.#e.postMessage({type:"cancelAll"})}cancelAllWithAck(){return this.#c?new Promise(e=>{let t=s=>{s.data.type==="cancelAllAck"&&(this.#e.removeEventListener("message",t),e())};this.#e.addEventListener("message",t),this.#e.postMessage({type:"cancelAll",ack:!0})}):Promise.resolve()}onReply(e){this.#h=e}onDebug(e){this.#n=e}onError(e){this.#s=e}onOscLog(e){this.#l=e}handleDebugRaw(e){if(e.messages&&e.count>0&&e.buffer){let t=new TextDecoder("utf-8"),s=new Uint8Array(e.buffer);for(let r=0;r<e.count;r++){let n=e.messages[r];try{let o=s.subarray(n.offset,n.offset+n.length),a=t.decode(o);a.endsWith(`
|
|
2
|
-
`)&&(a=a.slice(0,-1)),this.#f++,this.#y+=n.length,this.#n&&this.#n({text:a,timestamp:performance.now(),sequence:n.sequence})}catch(o){console.error("[PostMessageTransport] Failed to decode debug message:",o)}}}}getPreschedulerMetrics(){return this.#a}getMetrics(){return{oscInMessagesReceived:this.#b,oscInBytesReceived:this.#g,oscInMessagesDropped:this.#d,debugMessagesReceived:this.#f,debugBytesReceived:this.#y}}get ready(){return this.#c&&!this._disposed}dispose(){this._disposed||(this.#e&&(this.#e.postMessage({type:"stop"}),this.#e.terminate(),this.#e=null),this.#r=null,this.#c=!1,super.dispose())}#w(e){return new Promise((t,s)=>{let r=setTimeout(()=>{s(new Error("Prescheduler worker initialization timeout"))},5e3),n=o=>{o.data.type==="initialized"&&(clearTimeout(r),this.#e.removeEventListener("message",n),t())};this.#e.addEventListener("message",n),this.#e.postMessage({type:"init",mode:"postMessage",maxPendingMessages:this.#u,snapshotIntervalMs:this.#p,bypassLookaheadS:this._config.bypassLookaheadS,workletPort:e},[e])})}#M(e){switch(e.type){case"oscReplies":if(e.messages&&e.count>0&&e.buffer){let t=new Uint8Array(e.buffer);for(let s=0;s<e.count;s++){let r=e.messages[s],n=t.subarray(r.offset,r.offset+r.length);if(r.sequence!==void 0&&this.#i>=0){let o=this.#i+1&4294967295;if(r.sequence!==o){let a=r.sequence-o+4294967296&4294967295;a<1e3&&(this.#d+=a)}}r.sequence!==void 0&&(this.#i=r.sequence),this.#b++,this.#g+=r.length,this.#h&&this.#h(n,r.sequence,w())}}break;case"metrics":break;case"bufferLoaded":break;case"debugRawBatch":this.handleDebugRaw(e);break;case"oscLog":if(this.#l&&e.count>0&&e.buffer&&e.entries){let t=new Uint8Array(e.buffer),s=[];for(let r=0;r<e.count;r++){let n=e.entries[r],o=t.subarray(n.offset,n.offset+n.length);s.push({oscData:o,sourceId:n.sourceId,sequence:n.sequence,timestamp:w(),truncated:n.length<n.originalLength,originalLength:n.originalLength})}this.#l(s)}break;case"error":console.error("[PostMessageTransport] Worklet error:",e.error),this.#d++,this.#s&&this.#s(e.error,"worklet");break;case"debug":break}}#B(e){switch(e.type){case"preschedulerMetrics":this.#a=e.metrics;break;case"error":console.error("[PostMessageTransport] Prescheduler error:",e.error),this.#d++,this.#s&&this.#s(e.error,"oscOut");break}}};function Ke(i,e){if(i==="sab")return new v(e);if(i==="postMessage")return new H(e);throw new Error(`Unknown transport mode: ${i}. Use 'sab' or 'postMessage'`)}var Ft={5120:"i8",5121:"u8",5122:"i16",5123:"u16",5124:"i32",5125:"u32",5126:"f32"};var Qe={u8:1,u8c:1,i8:1,u16:2,i16:2,u32:4,i32:4,i64:8,u64:8,f32:4,f64:8};var xt={f32:Float32Array,f64:Float64Array},Nt={i8:Int8Array,i16:Int16Array,i32:Int32Array},vt={u8:Uint8Array,u8c:Uint8ClampedArray,u16:Uint16Array,u32:Uint32Array},Ht={i64:BigInt64Array,u64:BigUint64Array},zt={...xt,...Nt,...vt},Yt=i=>{let e=Ft[i];return e!==void 0?e:i};function je(i,...e){let t=Ht[i];return new(t||zt[Yt(i)])(...e)}var z=(i,e)=>(e--,i+e&~e);var Je=i=>typeof i=="number";var K=(i,e=t=>t!==void 0?": "+t:"")=>class extends Error{origMessage;constructor(t){super(i(t)+e(t)),this.origMessage=t!==void 0?String(t):""}};var Gt=K(()=>"Assertion failed"),Ee=(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)?(i,e)=>{if(typeof i=="function"&&!i()||!i)throw new Gt(typeof e=="function"?e():e)}:()=>{};var $t=K(()=>"illegal argument(s)"),et=i=>{throw new $t(i)};var tt=0,st=1,rt=2,it=3,nt=4,x=5,ot=6,Se=1,ge=2,at=7*4,_e=0,be=1,C=2*4,G=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?z(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,at/4),!e.skipInitialization){let t=e.align||8;Ee(t>=8,`invalid alignment: ${t}, must be a pow2 and >= 8`);let s=this.initialTop(t),r=e.end!=null?Math.min(e.end,this.buf.byteLength):this.buf.byteLength;s>=r&&et(`insufficient address range (0x${this.start.toString(16)} - 0x${r.toString(16)})`),this.align=t,this.doCompact=e.compact!==!1,this.doSplit=e.split!==!1,this.minSplit=e.minSplit||16,this.end=r,this.top=s,this._free=0,this._used=0}}stats(){let e=s=>{let r=0,n=0;for(;s;)r++,n+=this.blockSize(s),s=this.blockNext(s);return{count:r,size:n}},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,s=0){let r=this.mallocAs(e,t);return r?.fill(s),r}mallocAs(e,t){let s=this.malloc(t*Qe[e]);return s?je(e,this.buf,s,t):void 0}calloc(e,t=0){let s=this.malloc(e);return s&&this.u8.fill(t,s,s+e),s}malloc(e){if(e<=0)return 0;let t=z(e+C,this.align),s=this.end,r=this.top,n=this._free,o=0;for(;n;){let a=this.blockSize(n),c=n+a>=r;if(c||a>=t)return this.mallocTop(n,o,a,t,c);o=n,n=this.blockNext(n)}return n=r,r=n+t,r<=s?(this.initBlock(n,t,this._used),this._used=n,this.top=r,Y(n)):0}mallocTop(e,t,s,r,n){if(n&&e+r>this.end)return 0;if(t?this.unlinkBlock(t,e):this._free=this.blockNext(e),this.setBlockNext(e,this._used),this._used=e,n)this.top=e+this.setBlockSize(e,r);else if(this.doSplit){let o=s-r;o>=this.minSplit&&this.splitBlock(e,r,o)}return Y(e)}realloc(e,t){if(t<=0)return 0;let s=Te(e),r=0,n=this._used,o=0;for(;n;){if(n===s){[r,o]=this.reallocBlock(n,t);break}n=this.blockNext(n)}return r&&r!==s&&this.u8.copyWithin(Y(r),Y(s),o),Y(r)}reallocBlock(e,t){let s=this.blockSize(e),r=e+s,n=r>=this.top,o=z(t+C,this.align);if(o<=s){if(this.doSplit){let a=s-o;a>=this.minSplit?this.splitBlock(e,o,a):n&&(this.top=e+o)}else n&&(this.top=e+o);return[e,r]}return n&&e+o<this.end?(this.top=e+this.setBlockSize(e,o),[e,r]):(this.free(e),[Te(this.malloc(t)),r])}reallocArray(e,t){if(e.buffer!==this.buf)return;let s=this.realloc(e.byteOffset,t*e.BYTES_PER_ELEMENT);return s?new e.constructor(this.buf,s,t):void 0}free(e){let t;if(Je(e))t=e;else{if(e.buffer!==this.buf)return!1;t=e.byteOffset}t=Te(t);let s=this._used,r=0;for(;s;){if(s===t)return r?this.unlinkBlock(r,s):this._used=this.blockNext(s),this.insert(s),this.doCompact&&this.compact(),!0;r=s,s=this.blockNext(s)}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[nt]}set align(e){this.state[nt]=e}get end(){return this.state[it]}set end(e){this.state[it]=e}get top(){return this.state[rt]}set top(e){this.state[rt]=e}get _free(){return this.state[tt]}set _free(e){this.state[tt]=e}get _used(){return this.state[st]}set _used(e){this.state[st]=e}get doCompact(){return!!(this.state[x]&Se)}set doCompact(e){e?this.state[x]|=1<<Se-1:this.state[x]&=~Se}get doSplit(){return!!(this.state[x]&ge)}set doSplit(e){e?this.state[x]|=1<<ge-1:this.state[x]&=~ge}get minSplit(){return this.state[ot]}set minSplit(e){Ee(e>C,`illegal min split threshold: ${e}, require at least ${C+1}`),this.state[ot]=e}blockSize(e){return this.u32[(e>>2)+_e]}setBlockSize(e,t){return this.u32[(e>>2)+_e]=t,t}blockNext(e){return this.u32[(e>>2)+be]}setBlockNext(e,t){this.u32[(e>>2)+be]=t}initBlock(e,t,s){let r=e>>>2;return this.u32[r+_e]=t,this.u32[r+be]=s,e}unlinkBlock(e,t){this.setBlockNext(e,this.blockNext(t))}splitBlock(e,t,s){this.insert(this.initBlock(e+this.setBlockSize(e,t),s,0)),this.doCompact&&this.compact()}initialTop(e=this.align){return z(this.start+at+C,e)-C}compact(){let e=this._free,t=0,s=0,r,n=!1;for(;e;){for(r=e,s=this.blockNext(e);s&&r+this.blockSize(r)===s;)r=s,s=this.blockNext(s);if(r!==e){let o=r-e+this.blockSize(r);this.setBlockSize(e,o);let a=this.blockNext(r),c=this.blockNext(e);for(;c&&c!==a;){let l=this.blockNext(c);this.setBlockNext(c,0),c=l}this.setBlockNext(e,a),n=!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 n}insert(e){let t=this._free,s=0;for(;t&&!(e<=t);)s=t,t=this.blockNext(t);s?this.setBlockNext(s,e):this._free=e,this.setBlockNext(e,t)}},Y=i=>i>0?i+C:0,Te=i=>i>0?i-C:0;function ct(i){if(i.byteLength<12)return!1;let e=new Uint8Array(i,0,12),t=String.fromCharCode(e[0],e[1],e[2],e[3]),s=String.fromCharCode(e[8],e[9],e[10],e[11]);return t==="FORM"&&(s==="AIFF"||s==="AIFC")}function Wt(i){let e=i[0]>>7&1,t=(i[0]&127)<<8|i[1],s=0;for(let n=2;n<10;n++)s=s*256+i[n];if(t===0)return 0;let r=s*Math.pow(2,t-16383-63);return e?-r:r}function Ae(i,e){let t=12;for(;t<i.byteLength-8;){let s=String.fromCharCode(i.getUint8(t),i.getUint8(t+1),i.getUint8(t+2),i.getUint8(t+3)),r=i.getUint32(t+4,!1);if(s===e)return{offset:t+8,size:r};t+=8+r+r%2}return null}function lt(i){let e=new DataView(i),t=String.fromCharCode(e.getUint8(8),e.getUint8(9),e.getUint8(10),e.getUint8(11)),s=Ae(e,"COMM");if(!s)throw new Error("AIFF file missing COMM chunk");let r=e.getUint16(s.offset,!1),n=e.getUint32(s.offset+2,!1),o=e.getUint16(s.offset+6,!1),a=new Uint8Array(i,s.offset+8,10),c=Wt(a);if(t==="AIFC"&&s.size>=22){let h=String.fromCharCode(e.getUint8(s.offset+18),e.getUint8(s.offset+19),e.getUint8(s.offset+20),e.getUint8(s.offset+21));if(h!=="NONE"&&h!=="sowt")throw new Error(`AIFC compression type '${h}' is not supported. Only uncompressed AIFF/AIFC files are supported.`);if(h==="sowt")return Vt(i,r,n,o,c)}let l=Ae(e,"SSND");if(!l)throw new Error("AIFF file missing SSND chunk");let f=e.getUint32(l.offset,!1),u=l.offset+8+f,d=o/8,p=n*r*d;if(u+p>i.byteLength)throw new Error("AIFF file truncated: not enough audio data");let m=44,g=new ArrayBuffer(m+p),y=new DataView(g),S=new Uint8Array(g);ut(y,{numChannels:r,sampleRate:Math.round(c),bitsPerSample:o,dataSize:p});let _=new Uint8Array(i,u,p);if(d===1)for(let h=0;h<p;h++)S[m+h]=_[h]+128;else if(d===2)for(let h=0;h<p;h+=2)S[m+h]=_[h+1],S[m+h+1]=_[h];else if(d===3)for(let h=0;h<p;h+=3)S[m+h]=_[h+2],S[m+h+1]=_[h+1],S[m+h+2]=_[h];else if(d===4)for(let h=0;h<p;h+=4)S[m+h]=_[h+3],S[m+h+1]=_[h+2],S[m+h+2]=_[h+1],S[m+h+3]=_[h];else throw new Error(`Unsupported bit depth: ${o}`);return g}function Vt(i,e,t,s,r){let n=new DataView(i),o=Ae(n,"SSND");if(!o)throw new Error("AIFF file missing SSND chunk");let a=n.getUint32(o.offset,!1),c=o.offset+8+a,l=s/8,f=t*e*l;if(c+f>i.byteLength)throw new Error("AIFF file truncated: not enough audio data");let u=44,d=new ArrayBuffer(u+f),p=new DataView(d),m=new Uint8Array(d);ut(p,{numChannels:e,sampleRate:Math.round(r),bitsPerSample:s,dataSize:f});let g=new Uint8Array(i,c,f);if(l===1)for(let y=0;y<f;y++)m[u+y]=g[y]+128;else m.set(g,u);return d}function ut(i,{numChannels:e,sampleRate:t,bitsPerSample:s,dataSize:r}){let n=t*e*(s/8),o=e*(s/8);i.setUint8(0,82),i.setUint8(1,73),i.setUint8(2,70),i.setUint8(3,70),i.setUint32(4,36+r,!0),i.setUint8(8,87),i.setUint8(9,65),i.setUint8(10,86),i.setUint8(11,69),i.setUint8(12,102),i.setUint8(13,109),i.setUint8(14,116),i.setUint8(15,32),i.setUint32(16,16,!0),i.setUint16(20,1,!0),i.setUint16(22,e,!0),i.setUint32(24,t,!0),i.setUint32(28,n,!0),i.setUint16(32,o,!0),i.setUint16(34,s,!0),i.setUint8(36,100),i.setUint8(37,97),i.setUint8(38,116),i.setUint8(39,97),i.setUint32(40,r,!0)}var ft=8,Q=class{#r;#e;#t;#h;#n;#s;#l;#o;#a;#c;#u;#p;constructor(e){let{mode:t="sab",audioContext:s,sharedBuffer:r,bufferPoolConfig:n,sampleBaseURL:o,maxBuffers:a=1024,assetLoader:c=null,workletPort:l=null}=e;if(this.#r=t,!s)throw new Error("BufferManager requires audioContext");if(t==="sab"){if(!r||!(r instanceof SharedArrayBuffer))throw new Error("BufferManager requires sharedBuffer (SharedArrayBuffer) in SAB mode");if(!n||typeof n!="object")throw new Error("BufferManager requires bufferPoolConfig (object with start, size, align)");if(!Number.isFinite(n.start)||n.start<0)throw new Error("bufferPoolConfig.start must be a non-negative number");if(!Number.isFinite(n.size)||n.size<=0)throw new Error("bufferPoolConfig.size must be a positive number")}if(t==="postMessage"&&(!n||typeof n!="object"))throw new Error("BufferManager requires bufferPoolConfig in postMessage mode");if(!Number.isInteger(a)||a<=0)throw new Error("maxBuffers must be a positive integer");if(this.#h=s,this.#n=r,this.#e=o,this.#t=c,this.#p=l,t==="sab")this.#s=new G({buf:r,start:n.start,size:n.size,align:ft}),this.#l=n.size,this.#o=n.start;else{let d=new ArrayBuffer(n.start+n.size);this.#s=new G({buf:d,start:n.start,size:n.size,align:ft}),this.#l=n.size,this.#o=n.start}this.#a=new Map,this.#c=new Map,this.#u=new Map,this.GUARD_BEFORE=3,this.GUARD_AFTER=1,this.MAX_BUFFERS=a;let f=(n.size/(1024*1024)).toFixed(0),u=(n.start/(1024*1024)).toFixed(0)}async#_(e){return ct(e)&&(e=lt(e)),this.#h.decodeAudioData(e)}setWorkletPort(e){if(this.#r==="postMessage"){if(!e)throw new Error("BufferManager.setWorkletPort() requires a valid port");this.#p=e}}#m(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.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(e.includes("://")||e.startsWith("/")||e.startsWith("./"))return e;if(!this.#e)throw new Error(`sampleBaseURL not configured. Please set it in SuperSonic constructor options.
|
|
1
|
+
var Ut=Object.defineProperty;var Rt=(i,e)=>{for(var t in e)Ut(i,t,{get:e[t],enumerable:!0})};var M=class i{constructor(e){if(new.target===i)throw new Error("Transport is abstract - use SABTransport or PostMessageTransport");this._config=e,this._disposed=!1}get mode(){return this._config.mode}send(e,t){throw new Error("Abstract method - implement in subclass")}onReply(e){throw new Error("Abstract method - implement in subclass")}onDebug(e){throw new Error("Abstract method - implement in subclass")}onError(e){throw new Error("Abstract method - implement in subclass")}getMetrics(){throw new Error("Abstract method - implement in subclass")}async initialize(){throw new Error("Abstract method - implement in subclass")}createOscChannel(){throw new Error("Abstract method - implement in subclass")}dispose(){this._disposed=!0}get ready(){throw new Error("Abstract method - implement in subclass")}};var de=new Map;function He(i){try{return new URL(i,window.location.href).origin!==window.location.origin}catch{return!1}}async function ze(i){if(de.has(i))return de.get(i);let e=await fetch(i);if(!e.ok)throw new Error(`Failed to fetch ${i}: ${e.status} ${e.statusText}`);let t=await e.text(),s=new Blob([t],{type:"application/javascript"}),r=URL.createObjectURL(s);return de.set(i,r),r}async function C(i,e={}){let t=i;return He(i)&&(t=await ze(i)),new Worker(t,e)}async function Ye(i,e){let t=e;He(e)&&(t=await ze(e)),await i.addModule(t)}function Ge(i,e,t){return(t-1-i+e)%t}function $e({uint8View:i,dataView:e,bufferStart:t,bufferSize:s,head:r,payload:n,sequence:o,messageMagic:a,headerSize:c,sourceId:l=0,headerScratch:u=null,headerScratchView:f=null}){let h=n.length,m=c+h+3&-4,g=s-r;if(m>g){let p=u||new Uint8Array(c),y=f||new DataView(p.buffer);y.setUint32(0,a,!0),y.setUint32(4,m,!0),y.setUint32(8,o,!0),y.setUint32(12,l,!0);let _=t+r,d=t;if(g>=c){i.set(p,_);let w=g-c;w>0&&i.set(n.subarray(0,w),_+c),i.set(n.subarray(w),d)}else{i.set(p.subarray(0,g),_),i.set(p.subarray(g),d);let w=c-g;i.set(n,d+w)}}else{let p=t+r;e.setUint32(p,a,!0),e.setUint32(p+4,m,!0),e.setUint32(p+8,o,!0),e.setUint32(p+12,l,!0),i.set(n,p+c)}return(r+m)%s}function It(i,e,t=0,s=!1){for(let r=0;r<=t;r++)if(Atomics.compareExchange(i,e,0,1)===0)return!0;if(s){for(let n=0;n<100;n++)if(Atomics.wait(i,e,1,100),Atomics.compareExchange(i,e,0,1)===0)return!0;return console.error("[RingBuffer] Lock acquisition timeout after 10s - possible deadlock"),!1}return!1}function Dt(i,e){Atomics.store(i,e,0),Atomics.notify(i,e,1)}function We({atomicView:i,dataView:e,uint8View:t,bufferConstants:s,ringBufferBase:r,controlIndices:n,oscMessage:o,sourceId:a=0,maxSpins:c=0,useWait:l=!1}){let u=o.length,f=s.MESSAGE_HEADER_SIZE+u;if(f>s.IN_BUFFER_SIZE-s.MESSAGE_HEADER_SIZE||!It(i,n.IN_WRITE_LOCK,c,l))return!1;try{let h=Atomics.load(i,n.IN_HEAD),S=Atomics.load(i,n.IN_TAIL),m=f+3&-4;if(Ge(h,S,s.IN_BUFFER_SIZE)<m)return!1;let p=Atomics.add(i,n.IN_SEQUENCE,1),y=$e({uint8View:t,dataView:e,bufferStart:r+s.IN_BUFFER_START,bufferSize:s.IN_BUFFER_SIZE,head:h,payload:o,sequence:p,messageMagic:s.MESSAGE_MAGIC,headerSize:s.MESSAGE_HEADER_SIZE,sourceId:a});return Atomics.load(i,n.IN_HEAD),Atomics.store(i,n.IN_HEAD,y),Atomics.notify(i,n.IN_HEAD,1),!0}finally{Dt(i,n.IN_WRITE_LOCK)}}function V(i,e){let t=i+e;return{IN_HEAD:(t+0)/4,IN_TAIL:(t+4)/4,IN_SEQUENCE:(t+24)/4,IN_WRITE_LOCK:(t+40)/4,IN_LOG_TAIL:(t+44)/4}}function qe(i,e){let t=i+e;return{IN_HEAD:(t+0)/4,IN_TAIL:(t+4)/4,OUT_HEAD:(t+8)/4,OUT_TAIL:(t+12)/4,DEBUG_HEAD:(t+16)/4,DEBUG_TAIL:(t+20)/4,IN_SEQUENCE:(t+24)/4,OUT_SEQUENCE:(t+28)/4,DEBUG_SEQUENCE:(t+32)/4,STATUS_FLAGS:(t+36)/4,IN_WRITE_LOCK:(t+40)/4,IN_LOG_TAIL:(t+44)/4}}function Lt(i){return i.length>=8&&i[0]===35&&i[1]===98&&i[2]===117&&i[3]===110&&i[4]===100&&i[5]===108&&i[6]===101&&i[7]===0}function pe(i){if(i.length<16)return null;let e=new DataView(i.buffer,i.byteOffset,i.byteLength);return{ntpSeconds:e.getUint32(8,!1),ntpFraction:e.getUint32(12,!1)}}function T(){return(performance.timeOrigin+performance.now())/1e3+2208988800}function Ze(i,e={}){let{getCurrentNTP:t=T,bypassLookaheadS:s=.5}=e;if(!Lt(i))return"nonBundle";let r=pe(i);if(!r)return"nonBundle";let{ntpSeconds:n,ntpFraction:o}=r;if(n===0&&o<=1)return"immediate";let a=t();if(a===null||a===0)return"immediate";let l=n+o/4294967296-a;return l<0?"late":l<s?"nearFuture":"farFuture"}function q(i){return i!=="farFuture"}var A=class i{#r;#e;#t;#h;#n;#s;#l;#a;#o;#c;#u={messagesSent:0,bytesSent:0,nonBundle:0,immediate:0,nearFuture:0,late:0,bypassed:0};constructor(e,t){if(this.#r=e,this.#n=t.preschedulerPort||null,this.#l=t.bypassLookaheadS??.5,this.#a=t.sourceId??0,this.#o=t.blocking??this.#a!==0,this.#c=t.getCurrentNTP??T,e==="postMessage")this.#e=t.port;else if(this.#t={sharedBuffer:t.sharedBuffer,ringBufferBase:t.ringBufferBase,bufferConstants:t.bufferConstants,controlIndices:t.controlIndices},this.#p(),t.sharedBuffer&&t.bufferConstants){let s=t.ringBufferBase+t.bufferConstants.METRICS_START;this.#s=new Int32Array(t.sharedBuffer,s,t.bufferConstants.METRICS_SIZE/4)}}#p(){let e=this.#t.sharedBuffer;this.#h={atomicView:new Int32Array(e),dataView:new DataView(e),uint8View:new Uint8Array(e)}}classify(e){return Ze(e,{getCurrentNTP:this.#c,bypassLookaheadS:this.#l})}#_(e,t=null){if(this.#r==="sab"&&this.#s){if(Atomics.add(this.#s,24,1),Atomics.add(this.#s,25,e),t){let r={nonBundle:38,immediate:39,nearFuture:40,late:41}[t];r!==void 0&&(Atomics.add(this.#s,r,1),Atomics.add(this.#s,22,1))}}else this.#u.messagesSent++,this.#u.bytesSent+=e,t&&t in this.#u&&(this.#u[t]++,this.#u.bypassed++)}getAndResetMetrics(){let e={...this.#u};return this.#u={messagesSent:0,bytesSent:0,nonBundle:0,immediate:0,nearFuture:0,late:0,bypassed:0},e}getMetrics(){return this.#r==="sab"&&this.#s?{messagesSent:Atomics.load(this.#s,24),bytesSent:Atomics.load(this.#s,25),nonBundle:Atomics.load(this.#s,38),immediate:Atomics.load(this.#s,39),nearFuture:Atomics.load(this.#s,40),late:Atomics.load(this.#s,41),bypassed:Atomics.load(this.#s,22)}:{...this.#u}}#d(e,t=null,s=!0){if(this.#r==="postMessage")return this.#e?(this.#e.postMessage({type:"osc",oscData:e,bypassCategory:t,sourceId:this.#a}),!0):!1;{let r=this.#o,n=We({atomicView:this.#h.atomicView,dataView:this.#h.dataView,uint8View:this.#h.uint8View,bufferConstants:this.#t.bufferConstants,ringBufferBase:this.#t.ringBufferBase,controlIndices:this.#t.controlIndices,oscMessage:e,sourceId:this.#a,maxSpins:r?10:0,useWait:r});return!n&&!r&&s&&this.#n?(this.#s&&Atomics.add(this.#s,45,1),this.#n.postMessage({type:"directDispatch",oscData:e,sourceId:this.#a}),!0):n}}#m(e){return this.#n?(this.#n.postMessage({type:"osc",oscData:e,sourceId:this.#a}),!0):(console.error("[OscChannel] No prescheduler port, sending direct"),this.#d(e))}send(e){let t=this.classify(e);if(q(t)){let s=this.#d(e,t);return s&&this.#_(e.length,t),s}else{let s=this.#m(e);return s&&this.#_(e.length,null),s}}sendDirect(e){return this.#d(e)}sendToPrescheduler(e){return this.#m(e)}set getCurrentNTP(e){this.#c=e}get mode(){return this.#r}get transferable(){let e={mode:this.#r,preschedulerPort:this.#n,bypassLookaheadS:this.#l,sourceId:this.#a,blocking:this.#o};return this.#r==="postMessage"?{...e,port:this.#e}:{...e,sharedBuffer:this.#t.sharedBuffer,ringBufferBase:this.#t.ringBufferBase,bufferConstants:this.#t.bufferConstants,controlIndices:this.#t.controlIndices}}get transferList(){let e=[];return this.#r==="postMessage"&&this.#e&&e.push(this.#e),this.#n&&e.push(this.#n),e}close(){this.#r==="postMessage"&&this.#e&&(this.#e.close(),this.#e=null),this.#n&&(this.#n.close(),this.#n=null)}static createPostMessage(e){return e instanceof MessagePort?new i("postMessage",{port:e}):new i("postMessage",e)}static createSAB(e){let t=e.controlIndices;return t||(t=V(e.ringBufferBase,e.bufferConstants.CONTROL_START)),new i("sab",{sharedBuffer:e.sharedBuffer,ringBufferBase:e.ringBufferBase,bufferConstants:e.bufferConstants,controlIndices:t,preschedulerPort:e.preschedulerPort,bypassLookaheadS:e.bypassLookaheadS,sourceId:e.sourceId,blocking:e.blocking})}static fromTransferable(e){return e.mode==="postMessage"?new i("postMessage",{port:e.port,preschedulerPort:e.preschedulerPort,bypassLookaheadS:e.bypassLookaheadS,sourceId:e.sourceId,blocking:e.blocking}):new i("sab",{sharedBuffer:e.sharedBuffer,ringBufferBase:e.ringBufferBase,bufferConstants:e.bufferConstants,controlIndices:e.controlIndices,preschedulerPort:e.preschedulerPort,bypassLookaheadS:e.bypassLookaheadS,sourceId:e.sourceId,blocking:e.blocking})}};var x=class extends M{#r;#e;#t;#h;#n;#s;#l;#a;#o;#c;#u;#p;#_;#d;#m;#S;#b=1;#g=!1;#i;#f=0;#y=0;#E=0;#A=null;constructor(e){if(super({...e,mode:"sab"}),this.#r=e.sharedBuffer,this.#e=e.ringBufferBase,this.#t=e.bufferConstants,this.#p=e.workerBaseURL,this.#i=e.preschedulerCapacity||65536,!(this.#r instanceof SharedArrayBuffer))throw new Error("SABTransport requires a SharedArrayBuffer");this.#B()}async initialize(){if(this.#g)return;let[e,t,s,r]=await Promise.all([C(this.#p+"osc_out_prescheduler_worker.js",{type:"module"}),C(this.#p+"osc_in_worker.js",{type:"module"}),C(this.#p+"debug_worker.js",{type:"module"}),C(this.#p+"osc_out_log_sab_worker.js",{type:"module"})]);this.#a=e,this.#o=t,this.#c=s,this.#u=r,this.#M(),await Promise.all([this.#w(this.#a,"OSC OUT",{maxPendingMessages:this.#i,bypassLookaheadS:this._config.bypassLookaheadS}),this.#w(this.#o,"OSC IN"),this.#w(this.#c,"DEBUG"),this.#w(this.#u,"OSC OUT LOG")]),this.#o.postMessage({type:"start"}),this.#c.postMessage({type:"start"}),this.#u.postMessage({type:"start"}),this.#g=!0}send(e,t){return!this.#g||this._disposed?!1:(this.#a.postMessage({type:"send",oscData:e,sessionId:0,runTag:"",audioTimeS:null,currentTimeS:null}),this.#f++,this.#E+=e.length,!0)}sendWithOptions(e,t={}){if(!this.#g||this._disposed)return!1;let{sessionId:s=0,runTag:r="",audioTimeS:n=null,currentTimeS:o=null}=t;return this.#a.postMessage({type:"send",oscData:e,sessionId:s,runTag:r,audioTimeS:n,currentTimeS:o}),this.#f++,this.#E+=e.length,!0}sendImmediate(e){return!this.#g||this._disposed?!1:(this.#a.postMessage({type:"sendImmediate",oscData:e}),this.#f++,this.#E+=e.length,!0)}createOscChannel(e={}){if(!this.#g)throw new Error("Transport not initialized");let t=e.sourceId??this.#b++,s=new MessageChannel;return this.#a.postMessage({type:"addOscSource"},[s.port1]),A.createSAB({sharedBuffer:this.#r,ringBufferBase:this.#e,bufferConstants:this.#t,controlIndices:this.#l,preschedulerPort:s.port2,bypassLookaheadS:this._config.bypassLookaheadS,sourceId:t,blocking:e.blocking})}cancelSessionTag(e,t){this.#g&&this.#a.postMessage({type:"cancelSessionTag",sessionId:e,runTag:t})}cancelSession(e){this.#g&&this.#a.postMessage({type:"cancelSession",sessionId:e})}cancelTag(e){this.#g&&this.#a.postMessage({type:"cancelTag",runTag:e})}cancelAll(){this.#g&&this.#a.postMessage({type:"cancelAll"})}cancelAllWithAck(){return this.#g?new Promise(e=>{let t=s=>{s.data.type==="cancelAllAck"&&(this.#a.removeEventListener("message",t),e())};this.#a.addEventListener("message",t),this.#a.postMessage({type:"cancelAll",ack:!0})}):Promise.resolve()}onReply(e){this.#_=e}onDebug(e){this.#d=e}onError(e){this.#m=e}onOscLog(e){this.#S=e}handleOscLog(e){this.#S&&this.#S(e)}getMetrics(){return{oscOutMessagesSent:this.#f,oscOutMessagesDropped:this.#y,oscOutBytesSent:this.#E}}get ready(){return this.#g&&!this._disposed}dispose(){this._disposed||(this.#a&&(this.#a.postMessage({type:"stop"}),this.#a.terminate(),this.#a=null),this.#o&&(this.#o.postMessage({type:"stop"}),this.#o.terminate(),this.#o=null),this.#c&&(this.#c.postMessage({type:"stop"}),this.#c.terminate(),this.#c=null),this.#u&&(this.#u.postMessage({type:"stop"}),this.#u.terminate(),this.#u=null),this.#g=!1,super.dispose())}#B(){this.#h=new Int32Array(this.#r),this.#n=new DataView(this.#r),this.#s=new Uint8Array(this.#r),this.#l=V(this.#e,this.#t.CONTROL_START)}#w(e,t,s={}){return new Promise((r,n)=>{let o=setTimeout(()=>{n(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.#r,ringBufferBase:this.#e,bufferConstants:this.#t,...s})})}#M(){this.#o.onmessage=e=>{let t=e.data;t.type==="messages"&&this.#_?t.messages.forEach(s=>{s.oscData&&this.#_(s.oscData,s.sequence,s.timestamp)}):t.type==="error"&&(console.error("[SABTransport] OSC IN error:",t.error),this.#m&&this.#m(t.error,"oscIn"))},this.#c.onmessage=e=>{let t=e.data;t.type==="debug"&&this.#d?t.messages.forEach(s=>{this.#d(s)}):t.type==="error"&&(console.error("[SABTransport] DEBUG error:",t.error),this.#m&&this.#m(t.error,"debug"))},this.#a.onmessage=e=>{let t=e.data;t.type==="preschedulerMetrics"?this.#A=t.metrics:t.type==="error"&&(console.error("[SABTransport] OSC OUT error:",t.error),this.#y++,this.#m&&this.#m(t.error,"oscOut"))},this.#u.onmessage=e=>{let t=e.data;t.type==="oscLog"&&this.#S?this.#S(t.entries):t.type==="error"&&(console.error("[SABTransport] OSC OUT LOG error:",t.error),this.#m&&this.#m(t.error,"oscOutLog"))}}getPreschedulerMetrics(){return this.#A}};var N=class extends M{#r;#e;#t;#h;#n;#s;#l;#a=1;#o=null;#c=!1;#u;#p;#_=null;#d=0;#m=0;#S=0;#b=0;#g=0;#i=-1;#f=0;#y=0;#E;#A;constructor(e){super({...e,mode:"postMessage"}),this.#t=e.workerBaseURL,this.#u=e.preschedulerCapacity||65536,this.#p=e.snapshotIntervalMs,this.#E=e.getAudioContextTime,this.#A=e.getNTPStartTime}async initialize(e){if(this.#c)return;if(!e)throw new Error("PostMessageTransport requires workletPort");this.#r=e,this.#r.onmessage=s=>{this.#w(s.data)};let t=new MessageChannel;this.#r.postMessage({type:"addOscPort"},[t.port1]),this.#e=await C(this.#t+"osc_out_prescheduler_worker.js",{type:"module"}),this.#e.onmessage=s=>{this.#M(s.data)},await this.#B(t.port2),this.#c=!0}setBufferConstants(e){this.#_=e}send(e,t){return!this.#c||this._disposed?!1:(this.#e.postMessage({type:"send",oscData:e,sessionId:0,runTag:"",audioTimeS:null,currentTimeS:null}),this.#d++,this.#S+=e.length,!0)}sendWithOptions(e,t={}){if(!this.#c||this._disposed)return!1;let{sessionId:s=0,runTag:r="",audioTimeS:n=null,currentTimeS:o=null}=t;return this.#e.postMessage({type:"send",oscData:e,sessionId:s,runTag:r,audioTimeS:n,currentTimeS:o}),this.#d++,this.#S+=e.length,!0}sendImmediate(e,t){return!this.#c||this._disposed?!1:(this.#r.postMessage({type:"osc",oscData:e,bypassCategory:t}),this.#d++,this.#S+=e.length,!0)}createOscChannel(e={}){if(!this.#c)throw new Error("Transport not initialized");let t=e.sourceId??this.#a++,s=new MessageChannel;this.#r.postMessage({type:"addOscPort",sourceId:t},[s.port1]);let r=new MessageChannel;return this.#e.postMessage({type:"addOscSource"},[r.port1]),A.createPostMessage({port:s.port2,preschedulerPort:r.port2,bypassLookaheadS:this._config.bypassLookaheadS,sourceId:t,blocking:e.blocking})}cancelSessionTag(e,t){this.#c&&this.#e.postMessage({type:"cancelSessionTag",sessionId:e,runTag:t})}cancelSession(e){this.#c&&this.#e.postMessage({type:"cancelSession",sessionId:e})}cancelTag(e){this.#c&&this.#e.postMessage({type:"cancelTag",runTag:e})}cancelAll(){this.#c&&this.#e.postMessage({type:"cancelAll"})}cancelAllWithAck(){return this.#c?new Promise(e=>{let t=s=>{s.data.type==="cancelAllAck"&&(this.#e.removeEventListener("message",t),e())};this.#e.addEventListener("message",t),this.#e.postMessage({type:"cancelAll",ack:!0})}):Promise.resolve()}onReply(e){this.#h=e}onDebug(e){this.#n=e}onError(e){this.#s=e}onOscLog(e){this.#l=e}handleDebugRaw(e){if(e.messages&&e.count>0&&e.buffer){let t=new TextDecoder("utf-8"),s=new Uint8Array(e.buffer);for(let r=0;r<e.count;r++){let n=e.messages[r];try{let o=s.subarray(n.offset,n.offset+n.length),a=t.decode(o);a.endsWith(`
|
|
2
|
+
`)&&(a=a.slice(0,-1)),this.#f++,this.#y+=n.length,this.#n&&this.#n({text:a,timestamp:performance.now(),sequence:n.sequence})}catch(o){console.error("[PostMessageTransport] Failed to decode debug message:",o)}}}}getPreschedulerMetrics(){return this.#o}getMetrics(){return{oscInMessagesReceived:this.#b,oscInBytesReceived:this.#g,oscInMessagesDropped:this.#m,debugMessagesReceived:this.#f,debugBytesReceived:this.#y}}get ready(){return this.#c&&!this._disposed}dispose(){this._disposed||(this.#e&&(this.#e.postMessage({type:"stop"}),this.#e.terminate(),this.#e=null),this.#r=null,this.#c=!1,super.dispose())}#B(e){return new Promise((t,s)=>{let r=setTimeout(()=>{s(new Error("Prescheduler worker initialization timeout"))},5e3),n=o=>{o.data.type==="initialized"&&(clearTimeout(r),this.#e.removeEventListener("message",n),t())};this.#e.addEventListener("message",n),this.#e.postMessage({type:"init",mode:"postMessage",maxPendingMessages:this.#u,snapshotIntervalMs:this.#p,bypassLookaheadS:this._config.bypassLookaheadS,workletPort:e},[e])})}#w(e){switch(e.type){case"oscReplies":if(e.messages&&e.count>0&&e.buffer){let t=new Uint8Array(e.buffer);for(let s=0;s<e.count;s++){let r=e.messages[s],n=t.subarray(r.offset,r.offset+r.length);if(r.sequence!==void 0&&this.#i>=0){let o=this.#i+1&4294967295;if(r.sequence!==o){let a=r.sequence-o+4294967296&4294967295;a<1e3&&(this.#m+=a)}}r.sequence!==void 0&&(this.#i=r.sequence),this.#b++,this.#g+=r.length,this.#h&&this.#h(n,r.sequence,T())}}break;case"metrics":break;case"bufferLoaded":break;case"debugRawBatch":this.handleDebugRaw(e);break;case"oscLog":if(this.#l&&e.count>0&&e.buffer&&e.entries){let t=new Uint8Array(e.buffer),s=[];for(let r=0;r<e.count;r++){let n=e.entries[r],o=t.subarray(n.offset,n.offset+n.length);s.push({oscData:o,sourceId:n.sourceId,sequence:n.sequence,timestamp:T(),truncated:n.length<n.originalLength,originalLength:n.originalLength})}this.#l(s)}break;case"error":console.error("[PostMessageTransport] Worklet error:",e.error),this.#m++,this.#s&&this.#s(e.error,"worklet");break;case"debug":break}}#M(e){switch(e.type){case"preschedulerMetrics":this.#o=e.metrics;break;case"error":console.error("[PostMessageTransport] Prescheduler error:",e.error),this.#m++,this.#s&&this.#s(e.error,"oscOut");break}}};function Xe(i,e){if(i==="sab")return new x(e);if(i==="postMessage")return new N(e);throw new Error(`Unknown transport mode: ${i}. Use 'sab' or 'postMessage'`)}var kt={5120:"i8",5121:"u8",5122:"i16",5123:"u16",5124:"i32",5125:"u32",5126:"f32"};var Ke={u8:1,u8c:1,i8:1,u16:2,i16:2,u32:4,i32:4,i64:8,u64:8,f32:4,f64:8};var Ft={f32:Float32Array,f64:Float64Array},xt={i8:Int8Array,i16:Int16Array,i32:Int32Array},Nt={u8:Uint8Array,u8c:Uint8ClampedArray,u16:Uint16Array,u32:Uint32Array},vt={i64:BigInt64Array,u64:BigUint64Array},Ht={...Ft,...xt,...Nt},zt=i=>{let e=kt[i];return e!==void 0?e:i};function Qe(i,...e){let t=vt[i];return new(t||Ht[zt(i)])(...e)}var v=(i,e)=>(e--,i+e&~e);var je=i=>typeof i=="number";var Z=(i,e=t=>t!==void 0?": "+t:"")=>class extends Error{origMessage;constructor(t){super(i(t)+e(t)),this.origMessage=t!==void 0?String(t):""}};var Yt=Z(()=>"Assertion failed"),ye=(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)?(i,e)=>{if(typeof i=="function"&&!i()||!i)throw new Yt(typeof e=="function"?e():e)}:()=>{};var Gt=Z(()=>"illegal argument(s)"),Je=i=>{throw new Gt(i)};var et=0,tt=1,st=2,rt=3,it=4,k=5,nt=6,Ee=1,Se=2,ot=7*4,ge=0,_e=1,B=2*4,z=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?v(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,ot/4),!e.skipInitialization){let t=e.align||8;ye(t>=8,`invalid alignment: ${t}, must be a pow2 and >= 8`);let s=this.initialTop(t),r=e.end!=null?Math.min(e.end,this.buf.byteLength):this.buf.byteLength;s>=r&&Je(`insufficient address range (0x${this.start.toString(16)} - 0x${r.toString(16)})`),this.align=t,this.doCompact=e.compact!==!1,this.doSplit=e.split!==!1,this.minSplit=e.minSplit||16,this.end=r,this.top=s,this._free=0,this._used=0}}stats(){let e=s=>{let r=0,n=0;for(;s;)r++,n+=this.blockSize(s),s=this.blockNext(s);return{count:r,size:n}},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,s=0){let r=this.mallocAs(e,t);return r?.fill(s),r}mallocAs(e,t){let s=this.malloc(t*Ke[e]);return s?Qe(e,this.buf,s,t):void 0}calloc(e,t=0){let s=this.malloc(e);return s&&this.u8.fill(t,s,s+e),s}malloc(e){if(e<=0)return 0;let t=v(e+B,this.align),s=this.end,r=this.top,n=this._free,o=0;for(;n;){let a=this.blockSize(n),c=n+a>=r;if(c||a>=t)return this.mallocTop(n,o,a,t,c);o=n,n=this.blockNext(n)}return n=r,r=n+t,r<=s?(this.initBlock(n,t,this._used),this._used=n,this.top=r,H(n)):0}mallocTop(e,t,s,r,n){if(n&&e+r>this.end)return 0;if(t?this.unlinkBlock(t,e):this._free=this.blockNext(e),this.setBlockNext(e,this._used),this._used=e,n)this.top=e+this.setBlockSize(e,r);else if(this.doSplit){let o=s-r;o>=this.minSplit&&this.splitBlock(e,r,o)}return H(e)}realloc(e,t){if(t<=0)return 0;let s=be(e),r=0,n=this._used,o=0;for(;n;){if(n===s){[r,o]=this.reallocBlock(n,t);break}n=this.blockNext(n)}return r&&r!==s&&this.u8.copyWithin(H(r),H(s),o),H(r)}reallocBlock(e,t){let s=this.blockSize(e),r=e+s,n=r>=this.top,o=v(t+B,this.align);if(o<=s){if(this.doSplit){let a=s-o;a>=this.minSplit?this.splitBlock(e,o,a):n&&(this.top=e+o)}else n&&(this.top=e+o);return[e,r]}return n&&e+o<this.end?(this.top=e+this.setBlockSize(e,o),[e,r]):(this.free(e),[be(this.malloc(t)),r])}reallocArray(e,t){if(e.buffer!==this.buf)return;let s=this.realloc(e.byteOffset,t*e.BYTES_PER_ELEMENT);return s?new e.constructor(this.buf,s,t):void 0}free(e){let t;if(je(e))t=e;else{if(e.buffer!==this.buf)return!1;t=e.byteOffset}t=be(t);let s=this._used,r=0;for(;s;){if(s===t)return r?this.unlinkBlock(r,s):this._used=this.blockNext(s),this.insert(s),this.doCompact&&this.compact(),!0;r=s,s=this.blockNext(s)}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[it]}set align(e){this.state[it]=e}get end(){return this.state[rt]}set end(e){this.state[rt]=e}get top(){return this.state[st]}set top(e){this.state[st]=e}get _free(){return this.state[et]}set _free(e){this.state[et]=e}get _used(){return this.state[tt]}set _used(e){this.state[tt]=e}get doCompact(){return!!(this.state[k]&Ee)}set doCompact(e){e?this.state[k]|=1<<Ee-1:this.state[k]&=~Ee}get doSplit(){return!!(this.state[k]&Se)}set doSplit(e){e?this.state[k]|=1<<Se-1:this.state[k]&=~Se}get minSplit(){return this.state[nt]}set minSplit(e){ye(e>B,`illegal min split threshold: ${e}, require at least ${B+1}`),this.state[nt]=e}blockSize(e){return this.u32[(e>>2)+ge]}setBlockSize(e,t){return this.u32[(e>>2)+ge]=t,t}blockNext(e){return this.u32[(e>>2)+_e]}setBlockNext(e,t){this.u32[(e>>2)+_e]=t}initBlock(e,t,s){let r=e>>>2;return this.u32[r+ge]=t,this.u32[r+_e]=s,e}unlinkBlock(e,t){this.setBlockNext(e,this.blockNext(t))}splitBlock(e,t,s){this.insert(this.initBlock(e+this.setBlockSize(e,t),s,0)),this.doCompact&&this.compact()}initialTop(e=this.align){return v(this.start+ot+B,e)-B}compact(){let e=this._free,t=0,s=0,r,n=!1;for(;e;){for(r=e,s=this.blockNext(e);s&&r+this.blockSize(r)===s;)r=s,s=this.blockNext(s);if(r!==e){let o=r-e+this.blockSize(r);this.setBlockSize(e,o);let a=this.blockNext(r),c=this.blockNext(e);for(;c&&c!==a;){let l=this.blockNext(c);this.setBlockNext(c,0),c=l}this.setBlockNext(e,a),n=!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 n}insert(e){let t=this._free,s=0;for(;t&&!(e<=t);)s=t,t=this.blockNext(t);s?this.setBlockNext(s,e):this._free=e,this.setBlockNext(e,t)}},H=i=>i>0?i+B:0,be=i=>i>0?i-B:0;function at(i){if(i.byteLength<12)return!1;let e=new Uint8Array(i,0,12),t=String.fromCharCode(e[0],e[1],e[2],e[3]),s=String.fromCharCode(e[8],e[9],e[10],e[11]);return t==="FORM"&&(s==="AIFF"||s==="AIFC")}function $t(i){let e=i[0]>>7&1,t=(i[0]&127)<<8|i[1],s=0;for(let n=2;n<10;n++)s=s*256+i[n];if(t===0)return 0;let r=s*Math.pow(2,t-16383-63);return e?-r:r}function Te(i,e){let t=12;for(;t<i.byteLength-8;){let s=String.fromCharCode(i.getUint8(t),i.getUint8(t+1),i.getUint8(t+2),i.getUint8(t+3)),r=i.getUint32(t+4,!1);if(s===e)return{offset:t+8,size:r};t+=8+r+r%2}return null}function ct(i){let e=new DataView(i),t=String.fromCharCode(e.getUint8(8),e.getUint8(9),e.getUint8(10),e.getUint8(11)),s=Te(e,"COMM");if(!s)throw new Error("AIFF file missing COMM chunk");let r=e.getUint16(s.offset,!1),n=e.getUint32(s.offset+2,!1),o=e.getUint16(s.offset+6,!1),a=new Uint8Array(i,s.offset+8,10),c=$t(a);if(t==="AIFC"&&s.size>=22){let d=String.fromCharCode(e.getUint8(s.offset+18),e.getUint8(s.offset+19),e.getUint8(s.offset+20),e.getUint8(s.offset+21));if(d!=="NONE"&&d!=="sowt")throw new Error(`AIFC compression type '${d}' is not supported. Only uncompressed AIFF/AIFC files are supported.`);if(d==="sowt")return Wt(i,r,n,o,c)}let l=Te(e,"SSND");if(!l)throw new Error("AIFF file missing SSND chunk");let u=e.getUint32(l.offset,!1),f=l.offset+8+u,h=o/8,S=n*r*h;if(f+S>i.byteLength)throw new Error("AIFF file truncated: not enough audio data");let m=44,g=new ArrayBuffer(m+S),p=new DataView(g),y=new Uint8Array(g);lt(p,{numChannels:r,sampleRate:Math.round(c),bitsPerSample:o,dataSize:S});let _=new Uint8Array(i,f,S);if(h===1)for(let d=0;d<S;d++)y[m+d]=_[d]+128;else if(h===2)for(let d=0;d<S;d+=2)y[m+d]=_[d+1],y[m+d+1]=_[d];else if(h===3)for(let d=0;d<S;d+=3)y[m+d]=_[d+2],y[m+d+1]=_[d+1],y[m+d+2]=_[d];else if(h===4)for(let d=0;d<S;d+=4)y[m+d]=_[d+3],y[m+d+1]=_[d+2],y[m+d+2]=_[d+1],y[m+d+3]=_[d];else throw new Error(`Unsupported bit depth: ${o}`);return g}function Wt(i,e,t,s,r){let n=new DataView(i),o=Te(n,"SSND");if(!o)throw new Error("AIFF file missing SSND chunk");let a=n.getUint32(o.offset,!1),c=o.offset+8+a,l=s/8,u=t*e*l;if(c+u>i.byteLength)throw new Error("AIFF file truncated: not enough audio data");let f=44,h=new ArrayBuffer(f+u),S=new DataView(h),m=new Uint8Array(h);lt(S,{numChannels:e,sampleRate:Math.round(r),bitsPerSample:s,dataSize:u});let g=new Uint8Array(i,c,u);if(l===1)for(let p=0;p<u;p++)m[f+p]=g[p]+128;else m.set(g,f);return h}function lt(i,{numChannels:e,sampleRate:t,bitsPerSample:s,dataSize:r}){let n=t*e*(s/8),o=e*(s/8);i.setUint8(0,82),i.setUint8(1,73),i.setUint8(2,70),i.setUint8(3,70),i.setUint32(4,36+r,!0),i.setUint8(8,87),i.setUint8(9,65),i.setUint8(10,86),i.setUint8(11,69),i.setUint8(12,102),i.setUint8(13,109),i.setUint8(14,116),i.setUint8(15,32),i.setUint32(16,16,!0),i.setUint16(20,1,!0),i.setUint16(22,e,!0),i.setUint32(24,t,!0),i.setUint32(28,n,!0),i.setUint16(32,o,!0),i.setUint16(34,s,!0),i.setUint8(36,100),i.setUint8(37,97),i.setUint8(38,116),i.setUint8(39,97),i.setUint32(40,r,!0)}var ut=8,X=class{#r;#e;#t;#h;#n;#s;#l;#a;#o;#c;#u;#p;constructor(e){let{mode:t="sab",audioContext:s,sharedBuffer:r,bufferPoolConfig:n,sampleBaseURL:o,maxBuffers:a=1024,assetLoader:c=null,workletPort:l=null}=e;if(this.#r=t,!s)throw new Error("BufferManager requires audioContext");if(t==="sab"){if(!r||!(r instanceof SharedArrayBuffer))throw new Error("BufferManager requires sharedBuffer (SharedArrayBuffer) in SAB mode");if(!n||typeof n!="object")throw new Error("BufferManager requires bufferPoolConfig (object with start, size, align)");if(!Number.isFinite(n.start)||n.start<0)throw new Error("bufferPoolConfig.start must be a non-negative number");if(!Number.isFinite(n.size)||n.size<=0)throw new Error("bufferPoolConfig.size must be a positive number")}if(t==="postMessage"&&(!n||typeof n!="object"))throw new Error("BufferManager requires bufferPoolConfig in postMessage mode");if(!Number.isInteger(a)||a<=0)throw new Error("maxBuffers must be a positive integer");if(this.#h=s,this.#n=r,this.#e=o,this.#t=c,this.#p=l,t==="sab")this.#s=new z({buf:r,start:n.start,size:n.size,align:ut}),this.#l=n.size,this.#a=n.start;else{let h=new ArrayBuffer(n.start+n.size);this.#s=new z({buf:h,start:n.start,size:n.size,align:ut}),this.#l=n.size,this.#a=n.start}this.#o=new Map,this.#c=new Map,this.#u=new Map,this.GUARD_BEFORE=3,this.GUARD_AFTER=1,this.MAX_BUFFERS=a;let u=(n.size/(1024*1024)).toFixed(0),f=(n.start/(1024*1024)).toFixed(0)}async#_(e){let t=e.byteOffset===0&&e.byteLength===e.buffer.byteLength?e.buffer:e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength),s=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(s)).map(r=>r.toString(16).padStart(2,"0")).join("")}async#d({source:e,startFrame:t=0,numFrames:s=0,channels:r=null}){let n,o;if(typeof e=="string"){let p=this.#g(e),y=e.split("/").pop();n=await this.#t.fetch(p,{type:"sample",name:y}),o={type:"file",path:e,startFrame:t,numFrames:s,channels:r}}else n=e instanceof ArrayBuffer?e:e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength),o=null;let a=await this.#b(n),c=Math.max(0,Math.floor(t||0)),l=a.length-c,u=s&&s>0?Math.min(Math.floor(s),l):l;if(u<=0)throw new Error("No audio frames available");let f=this.#y(r,a.numberOfChannels),h=f.length,S=u*h+(this.GUARD_BEFORE+this.GUARD_AFTER)*h,m=new Float32Array(S),g=this.GUARD_BEFORE*h;for(let p=0;p<u;p++)for(let y=0;y<h;y++){let _=a.getChannelData(f[y]);m[g+p*h+y]=_[c+p]}return{interleaved:m,numFrames:u,numChannels:h,sampleRate:a.sampleRate,sourceInfo:o}}async#m(e){let t=this.#E(e.length);return await this.#A(t,e),t}async#S(e,t,s,r){let n,o=await this.#f(e,t,async()=>{let[c,l]=await Promise.all([this.#_(s.interleaved),this.#m(s.interleaved)]);return n=c,{ptr:l,sizeBytes:s.interleaved.length*4,numFrames:s.numFrames,numChannels:s.numChannels,sampleRate:s.sampleRate,source:r||null}}),a=this.#o.get(e);return a&&(a.hash=n),{...o,hash:n}}async#b(e){return at(e)&&(e=ct(e)),this.#h.decodeAudioData(e)}setWorkletPort(e){if(this.#r==="postMessage"){if(!e)throw new Error("BufferManager.setWorkletPort() requires a valid port");this.#p=e}}#g(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.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(e.includes("://")||e.startsWith("/")||e.startsWith("./"))return e;if(!this.#e)throw new Error(`sampleBaseURL not configured. Please set it in SuperSonic constructor options.
|
|
3
3
|
Example: new SuperSonic({ sampleBaseURL: "./dist/samples/" })
|
|
4
4
|
Or use CDN: new SuperSonic({ sampleBaseURL: "https://unpkg.com/supersonic-scsynth-samples@latest/samples/" })
|
|
5
|
-
Or install: npm install supersonic-scsynth-samples`);return this.#e+e}#d(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#S(e,t,s){let r=null,n=null,o=!1,a=await this.#E(e),c=!1;try{await this.#w(e);let{ptr:l,sizeBytes:f,numFrames:u,numChannels:d,sampleRate:p,source:m,...g}=await s();r=l;let{uuid:y,allocationComplete:S}=this.#y(e,t);n=y,this.#A(e,r,f,y,S,{numFrames:u,numChannels:d,sampleRate:p,source:m}),o=!0;let _=this.#M(e,y,S);return a(),c=!0,{ptr:r,uuid:y,allocationComplete:_,numFrames:u,numChannels:d,sampleRate:p,...g}}catch(l){throw o&&n?this.#B(e,n,!1):r&&this.#s.free(r),l}finally{c||a()}}async prepareFromBlob(e){let{bufnum:t,blob:s,startFrame:r=0,numFrames:n=0,channels:o=null}=e;if(this.#d(t),!s||!(s instanceof ArrayBuffer||ArrayBuffer.isView(s)))throw new Error("/b_allocFile requires audio data as ArrayBuffer or typed array");let a=s instanceof ArrayBuffer?s:s.buffer.slice(s.byteOffset,s.byteOffset+s.byteLength);return this.#S(t,3e4,async()=>{let c=await this.#_(a),l=Math.max(0,Math.floor(r||0)),f=c.length-l,u=n&&n>0?Math.min(Math.floor(n),f):f;if(u<=0)throw new Error(`No audio frames available for buffer ${t}`);let d=this.#b(o,c.numberOfChannels),p=d.length,m=u*p+(this.GUARD_BEFORE+this.GUARD_AFTER)*p,g=this.#g(m),y=new Float32Array(m),S=this.GUARD_BEFORE*p;for(let h=0;h<u;h++)for(let T=0;T<p;T++){let A=d[T],B=c.getChannelData(A);y[S+h*p+T]=B[l+h]}await this.#i(g,y);let _=y.length*4;return{ptr:g,sizeBytes:_,numFrames:u,numChannels:p,sampleRate:c.sampleRate}})}async prepareFromFile(e){let{bufnum:t,path:s,startFrame:r=0,numFrames:n=0,channels:o=null}=e;return this.#d(t),this.#S(t,6e4,async()=>{let a=this.#m(s),c=s.split("/").pop(),l=await this.#t.fetch(a,{type:"sample",name:c}),f=await this.#_(l),u=Math.max(0,Math.floor(r||0)),d=f.length-u,p=n&&n>0?Math.min(Math.floor(n),d):d;if(p<=0)throw new Error(`No audio frames available for buffer ${t} from ${s}`);let m=this.#b(o,f.numberOfChannels),g=m.length,y=p*g+(this.GUARD_BEFORE+this.GUARD_AFTER)*g,S=this.#g(y),_=new Float32Array(y),h=this.GUARD_BEFORE*g;for(let A=0;A<p;A++)for(let B=0;B<g;B++){let de=m[B],Ut=f.getChannelData(de);_[h+A*g+B]=Ut[u+A]}await this.#i(S,_);let T=_.length*4;return{ptr:S,sizeBytes:T,numFrames:p,numChannels:g,sampleRate:f.sampleRate,source:{type:"file",path:s,startFrame:r,numFrames:n,channels:o}}})}async prepareEmpty(e){let{bufnum:t,numFrames:s,numChannels:r=1,sampleRate:n=null}=e;if(this.#d(t),!Number.isFinite(s)||s<=0)throw new Error(`/b_alloc requires a positive number of frames (got ${s})`);if(!Number.isFinite(r)||r<=0)throw new Error(`/b_alloc requires a positive channel count (got ${r})`);let o=Math.floor(s),a=Math.floor(r);return this.#S(t,5e3,async()=>{let c=o*a+(this.GUARD_BEFORE+this.GUARD_AFTER)*a,l=this.#g(c),f=new Float32Array(c);await this.#i(l,f);let u=f.length*4;return{ptr:l,sizeBytes:u,numFrames:o,numChannels:a,sampleRate:n||this.#h.sampleRate}})}#b(e,t){return!e||e.length===0?Array.from({length:t},(s,r)=>r):(e.forEach(s=>{if(!Number.isInteger(s)||s<0||s>=t)throw new Error(`Channel ${s} is out of range (file has ${t} channels)`)}),e)}#g(e){let t=e*4,s=this.#s.malloc(t);if(s===0){let r=this.#s.stats(),n=((r.available||0)/(1024*1024)).toFixed(2),o=((r.total||0)/(1024*1024)).toFixed(2),a=(t/(1024*1024)).toFixed(2);throw new Error(`Buffer pool allocation failed: requested ${a}MB, available ${n}MB of ${o}MB total`)}return s}async#i(e,t){if(this.#r==="sab")new Float32Array(this.#n,e,t.length).set(t);else{let s=crypto.randomUUID(),r=new Promise((o,a)=>{let c=setTimeout(()=>{a(new Error("Buffer copy to WASM memory timed out"))},1e4),l=f=>{let u=f.data;u.type==="bufferCopied"&&u.copyId===s&&(this.#p.removeEventListener("message",l),clearTimeout(c),u.success?o():a(new Error(u.error||"Buffer copy failed")))};this.#p.addEventListener("message",l)}),n=t.buffer.slice(t.byteOffset,t.byteOffset+t.byteLength);this.#p.postMessage({type:"copyBufferData",copyId:s,ptr:e,data:n},[n]),await r}}#f(e,t,s){return new Promise((r,n)=>{let o=setTimeout(()=>{this.#c.delete(e),n(new Error(`Buffer ${t} allocation timeout (${s}ms)`))},s);this.#c.set(e,{resolve:r,reject:n,timeout:o})})}#y(e,t){let s=crypto.randomUUID(),r=this.#f(s,e,t);return{uuid:s,allocationComplete:r}}async#E(e){let t=this.#u.get(e)||Promise.resolve(),s,r=new Promise(n=>{s=n});return this.#u.set(e,t.then(()=>r)),await t,()=>{s&&(s(),s=null),this.#u.get(e)===r&&this.#u.delete(e)}}#A(e,t,s,r,n,o={}){let a=this.#a.get(e),c={ptr:t,size:s,numFrames:o.numFrames||0,numChannels:o.numChannels||1,sampleRate:o.sampleRate||48e3,pendingToken:r,pendingPromise:n,previousAllocation:a?{ptr:a.ptr,size:a.size}:null,source:o.source||null};return this.#a.set(e,c),c}async#w(e){let t=this.#a.get(e);if(t&&t.pendingToken&&t.pendingPromise)try{await t.pendingPromise}catch{}}#M(e,t,s){return!s||typeof s.then!="function"?(this.#B(e,t,!0),Promise.resolve()):s.then(r=>(this.#B(e,t,!0),r)).catch(r=>{throw this.#B(e,t,!1),r})}#B(e,t,s){let r=this.#a.get(e);if(!r||r.pendingToken!==t)return;let n=r.previousAllocation;if(s){r.pendingToken=null,r.pendingPromise=null,r.previousAllocation=null,n?.ptr&&this.#s.free(n.ptr);return}r.ptr&&this.#s.free(r.ptr),r.pendingPromise=null,n?.ptr?this.#a.set(e,{ptr:n.ptr,size:n.size,pendingToken:null,previousAllocation:null}):this.#a.delete(e)}handleBufferFreed(e){let t=e[0],s=e[1],r=this.#a.get(t);if(!r){typeof s=="number"&&s!==0&&this.#s.free(s);return}if(typeof s=="number"&&s===r.ptr){this.#s.free(r.ptr),this.#a.delete(t);return}if(typeof s=="number"&&r.previousAllocation&&r.previousAllocation.ptr===s){this.#s.free(s),r.previousAllocation=null;return}this.#s.free(r.ptr),this.#a.delete(t)}handleBufferAllocated(e){let t=e[0],s=e[1],r=this.#c.get(t);r&&(clearTimeout(r.timeout),r.resolve({bufnum:s}),this.#c.delete(t))}allocate(e){let t=e*4,s=this.#s.malloc(t);if(s===0){let r=this.#s.stats(),n=((r.available||0)/(1024*1024)).toFixed(2),o=((r.total||0)/(1024*1024)).toFixed(2),a=(t/(1024*1024)).toFixed(2);console.error(`[BufferManager] Allocation failed: requested ${a}MB, available ${n}MB of ${o}MB total`)}return s}free(e){return this.#s.free(e)}getView(e,t){return new Float32Array(this.#n,e,t)}getStats(){return this.#s?this.#s.stats():{total:0,available:0,used:0,allocations:0}}getAllocatedBuffers(){let e=[];for(let[t,s]of this.#a.entries())!s||!s.ptr||e.push({bufnum:t,ptr:s.ptr,numFrames:s.numFrames,numChannels:s.numChannels,sampleRate:s.sampleRate,source:s.source||null});return e}updateAudioContext(e){if(!e)throw new Error("BufferManager.updateAudioContext requires audioContext");this.#h=e}getDiagnostics(){let e=this.#s.stats(),t=0,s=0;for(let r of this.#a.values())r&&(t+=r.size||0,r.pendingToken&&s++);return{active:this.#a.size,pending:s,bytesActive:t,pool:{total:this.#l,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.#c.entries())clearTimeout(t.timeout),t.reject(new Error("BufferManager destroyed"));this.#c.clear();for(let[e,t]of this.#a.entries())t.ptr&&this.#s.free(t.ptr);this.#a.clear(),this.#u.clear()}};var j=class{#r;#e;#t;constructor(e={}){let{onLoadingEvent:t=null,maxRetries:s=3,baseDelay:r=1e3}=e;this.#r=t,this.#e=s,this.#t=r}async fetch(e,{type:t,name:s}){let r=this.#h(e),n=this.#n(e),o=await r;this.#r?.("loading:start",{type:t,name:s,...o!=null&&{size:o}});let c=await(await n).arrayBuffer();return this.#r?.("loading:complete",{type:t,name:s,size:c.byteLength}),c}async#h(e){try{let t=await fetch(e,{method:"HEAD"});if(t.ok){let s=t.headers.get("Content-Length");return s?parseInt(s,10):null}return null}catch{return null}}async#n(e){let t;for(let s=0;s<=this.#e;s++)try{let r=await fetch(e);if(r.status>=400&&r.status<500)throw new Error(`Failed to fetch ${e}: ${r.status} ${r.statusText}`);if(!r.ok)throw new Error(`Server error fetching ${e}: ${r.status} ${r.statusText}`);return r}catch(r){if(t=r,r.message.includes("Failed to fetch")&&r.message.includes("4"))throw r;if(s<this.#e){let n=this.#t*Math.pow(2,s);await this.#s(n)}}throw t}#s(e){return new Promise(t=>setTimeout(t,e))}};var J=class{#r;#e;constructor({bufferManager:e,getDefaultSampleRate:t}){if(!e)throw new Error("OSCRewriter requires bufferManager");if(typeof t!="function")throw new Error("OSCRewriter requires getDefaultSampleRate callback");this.#r=e,this.#e=t}async rewritePacket(e){if(Array.isArray(e)){let{message:t,changed:s}=await this.#t(e);return{packet:t,changed:s}}if(this.#a(e)){let t=await Promise.all(e.packets.map(n=>this.rewritePacket(n)));if(!t.some(n=>n.changed))return{packet:e,changed:!1};let r=t.map(n=>n.packet);return{packet:{timeTag:e.timeTag,packets:r},changed:!0}}return{packet:e,changed:!1}}async#t(e){let t=e[0],s=e.slice(1);switch(t){case"/b_alloc":return{message:await this.#h(s),changed:!0};case"/b_allocRead":return{message:await this.#n(s),changed:!0};case"/b_allocReadChannel":return{message:await this.#s(s),changed:!0};case"/b_allocFile":return{message:await this.#l(s),changed:!0};default:return{message:e,changed:!1}}}async#h(e){let t=this.#p(e,0,"/b_alloc requires a buffer number"),s=this.#p(e,1,"/b_alloc requires a frame count"),r=2,n=1,o=this.#e();this.#S(this.#c(e,r))&&(n=Math.max(1,this.#_(e,r,1)),r++),this.#c(e,r)?.type==="b"&&r++,this.#S(this.#c(e,r))&&(o=this.#u(this.#c(e,r)));let a=await this.#r.prepareEmpty({bufnum:t,numFrames:s,numChannels:n,sampleRate:o});return this.#b(a.allocationComplete,`/b_alloc ${t}`),this.#o(t,a)}async#n(e){let t=this.#p(e,0,"/b_allocRead requires a buffer number"),s=this.#m(e,1,"/b_allocRead requires a file path"),r=this.#_(e,2,0),n=this.#_(e,3,0),o=await this.#r.prepareFromFile({bufnum:t,path:s,startFrame:r,numFrames:n});return this.#b(o.allocationComplete,`/b_allocRead ${t}`),this.#o(t,o)}async#s(e){let t=this.#p(e,0,"/b_allocReadChannel requires a buffer number"),s=this.#m(e,1,"/b_allocReadChannel requires a file path"),r=this.#_(e,2,0),n=this.#_(e,3,0),o=[];for(let c=4;c<(e?.length||0)&&this.#S(e[c]);c++)o.push(Math.floor(this.#u(e[c])));let a=await this.#r.prepareFromFile({bufnum:t,path:s,startFrame:r,numFrames:n,channels:o.length>0?o:null});return this.#b(a.allocationComplete,`/b_allocReadChannel ${t}`),this.#o(t,a)}async#l(e){let t=this.#p(e,0,"/b_allocFile requires a buffer number"),s=this.#d(e,1,"/b_allocFile requires audio file data as blob"),r=await this.#r.prepareFromBlob({bufnum:t,blob:s});return this.#b(r.allocationComplete,`/b_allocFile ${t}`),this.#o(t,r)}#o(e,t){return["/b_allocPtr",Math.floor(e),Math.floor(t.ptr),Math.floor(t.numFrames),Math.floor(t.numChannels),t.sampleRate,String(t.uuid)]}#a(e){return e&&e.timeTag!==void 0&&Array.isArray(e.packets)}#c(e,t){if(Array.isArray(e))return e[t]}#u(e){if(e!=null)return typeof e=="object"&&Object.prototype.hasOwnProperty.call(e,"value")?e.value:e}#p(e,t,s){let r=this.#u(this.#c(e,t));if(!Number.isFinite(r))throw new Error(s);return Math.floor(r)}#_(e,t,s=0){let r=this.#u(this.#c(e,t));return Number.isFinite(r)?Math.floor(r):s}#m(e,t,s){let r=this.#u(this.#c(e,t));if(typeof r!="string")throw new Error(s);return r}#d(e,t,s){let r=this.#u(this.#c(e,t));if(!(r instanceof Uint8Array||r instanceof ArrayBuffer))throw new Error(s);return r}#S(e){if(!e)return!1;let t=this.#u(e);return Number.isFinite(t)}#b(e,t){!e||typeof e.catch!="function"||e.catch(s=>{console.error(`[OSCRewriter] ${t} allocation failed:`,s)})}};function N(i){if(!i)return null;if(typeof i=="string")return(i.split("/").filter(Boolean).pop()||i).replace(/\.scsyndef$/i,"");let e=i instanceof ArrayBuffer?new Uint8Array(i):i;if(!(e instanceof Uint8Array)||e.length<11||e[0]!==83||e[1]!==67||e[2]!==103||e[3]!==102)return null;let t=e[10];if(t===0||11+t>e.length)return null;try{return new TextDecoder().decode(e.slice(11,11+t))}catch{return null}}var ee=class{#r=new Map;on(e,t){if(typeof t!="function")throw new Error("Callback must be a function");return this.#r.has(e)||this.#r.set(e,new Set),this.#r.get(e).add(t),()=>this.off(e,t)}off(e,t){let s=this.#r.get(e);return s&&s.delete(t),this}once(e,t){let s=(...r)=>{this.off(e,s),t(...r)};return this.on(e,s)}removeAllListeners(e){return e===void 0?this.#r.clear():this.#r.delete(e),this}hasListeners(e){let t=this.#r.get(e);return t?t.size>0:!1}emit(e,...t){let s=this.#r.get(e);if(s)for(let r of s)try{r(...t)}catch(n){console.error(`[EventEmitter] Error in ${e} listener:`,n)}}async emitAsync(e,...t){let s=this.#r.get(e);if(s)for(let r of s)try{await r(...t)}catch(n){console.error(`[EventEmitter] Error in ${e} listener:`,n)}}clearAllListeners(){this.#r.clear()}};var te=class{#r;#e;#t;#h;#n;#s;#l;#o=null;#a=new Uint32Array(64);#c=new DataView(this.#a.buffer);constructor(e={}){this.#h=e.mode||"sab",this.#r=e.sharedBuffer||null,this.#e=e.ringBufferBase||0,this.#t=e.bufferConstants||null}initSharedViews(e,t,s){if(this.#r=e,this.#e=t,this.#t=s,this.#h==="sab"&&e&&s){this.#n=new Int32Array(e),this.#l=Ze(t,s.CONTROL_START);let r=t+s.METRICS_START;this.#s=new Uint32Array(e,r,s.METRICS_SIZE/4)}}updateSnapshot(e){this.#o=e}getSnapshotBuffer(){return this.#o}getMetricsView(){return this.#s}addMetric(e,t=1){if(!this.#s)return;let r={oscOutMessagesSent:24,oscOutBytesSent:25,preschedulerBypassed:22,bypassNonBundle:38,bypassImmediate:39,bypassNearFuture:40,bypassLate:41}[e];r!==void 0&&Atomics.add(this.#s,r,t)}parseMetricsBuffer(e){return{scsynthProcessCount:e[0],scsynthMessagesProcessed:e[1],scsynthMessagesDropped:e[2],scsynthSchedulerDepth:e[3],scsynthSchedulerPeakDepth:e[4],scsynthSchedulerDropped:e[5],scsynthSequenceGaps:e[6],scsynthSchedulerLates:e[8],scsynthSchedulerMaxLateMs:e[42],scsynthSchedulerLastLateMs:e[43],scsynthSchedulerLastLateTick:e[44],preschedulerPending:e[9],preschedulerPendingPeak:e[10],preschedulerDispatched:e[12],preschedulerRetriesSucceeded:e[16],preschedulerRetriesFailed:e[17],preschedulerBundlesScheduled:e[11],preschedulerEventsCancelled:e[13],preschedulerTotalDispatches:e[21],preschedulerMessagesRetried:e[20],preschedulerRetryQueueSize:e[18],preschedulerRetryQueuePeak:e[19],preschedulerBypassed:e[22],oscInMessagesReceived:e[26],oscInMessagesDropped:e[28],oscInBytesReceived:e[27],debugMessagesReceived:e[30],debugBytesReceived:e[31],oscOutMessagesSent:e[24],oscOutBytesSent:e[25],preschedulerMinHeadroomMs:e[14],preschedulerLates:e[15],preschedulerMaxLateMs:e[23],scsynthWasmErrors:e[7],oscInCorrupted:e[29],ringBufferDirectWriteFails:e[45],inBufferUsedBytes:e[32],outBufferUsedBytes:e[33],debugBufferUsedBytes:e[34],inBufferPeakBytes:e[35],outBufferPeakBytes:e[36],debugBufferPeakBytes:e[37],bypassNonBundle:e[38],bypassImmediate:e[39],bypassNearFuture:e[40],bypassLate:e[41]}}getSABMetrics(){return this.#s?this.parseMetricsBuffer(this.#s):null}getBufferUsage(){if(!this.#n||!this.#t||!this.#l)return null;let e=this.#t,t=this.#l,s=this.#n,r=Atomics.load(s,t.IN_HEAD),n=Atomics.load(s,t.IN_TAIL),o=Atomics.load(s,t.OUT_HEAD),a=Atomics.load(s,t.OUT_TAIL),c=Atomics.load(s,t.DEBUG_HEAD),l=Atomics.load(s,t.DEBUG_TAIL),f=(r-n+e.IN_BUFFER_SIZE)%e.IN_BUFFER_SIZE,u=(o-a+e.OUT_BUFFER_SIZE)%e.OUT_BUFFER_SIZE,d=(c-l+e.DEBUG_BUFFER_SIZE)%e.DEBUG_BUFFER_SIZE;return{inBufferUsed:{bytes:f,percentage:f/e.IN_BUFFER_SIZE*100,capacity:e.IN_BUFFER_SIZE},outBufferUsed:{bytes:u,percentage:u/e.OUT_BUFFER_SIZE*100,capacity:e.OUT_BUFFER_SIZE},debugBufferUsed:{bytes:d,percentage:d/e.DEBUG_BUFFER_SIZE*100,capacity:e.DEBUG_BUFFER_SIZE}}}overlayPreschedulerMetrics(e){if(!this.#o||!e)return;let t=new Uint32Array(this.#o,0,46),s=9,r=13;t.set(e.subarray(s,s+r),s),t[23]=e[23]}gatherMetrics(e={}){let t;if(this.#h==="postMessage")if(e.preschedulerMetrics&&this.overlayPreschedulerMetrics(e.preschedulerMetrics),this.#o){let s=new Uint32Array(this.#o,0,46);t=this.parseMetricsBuffer(s)}else t={};else t=this.getSABMetrics()||{};if(t.inBufferUsedBytes!==void 0&&this.#t){let s=this.#t;t.inBufferUsed={bytes:t.inBufferUsedBytes,percentage:t.inBufferUsedBytes/s.IN_BUFFER_SIZE*100,peakBytes:t.inBufferPeakBytes,peakPercentage:t.inBufferPeakBytes/s.IN_BUFFER_SIZE*100,capacity:s.IN_BUFFER_SIZE},t.outBufferUsed={bytes:t.outBufferUsedBytes,percentage:t.outBufferUsedBytes/s.OUT_BUFFER_SIZE*100,peakBytes:t.outBufferPeakBytes,peakPercentage:t.outBufferPeakBytes/s.OUT_BUFFER_SIZE*100,capacity:s.OUT_BUFFER_SIZE},t.debugBufferUsed={bytes:t.debugBufferUsedBytes,percentage:t.debugBufferUsedBytes/s.DEBUG_BUFFER_SIZE*100,peakBytes:t.debugBufferPeakBytes,peakPercentage:t.debugBufferPeakBytes/s.DEBUG_BUFFER_SIZE*100,capacity:s.DEBUG_BUFFER_SIZE},delete t.inBufferUsedBytes,delete t.outBufferUsedBytes,delete t.debugBufferUsedBytes,delete t.inBufferPeakBytes,delete t.outBufferPeakBytes,delete t.debugBufferPeakBytes}return t.mode=this.#h,this.#t?.scheduler_slot_count!==void 0&&(t.scsynthSchedulerCapacity=this.#t.scheduler_slot_count),e.driftOffsetMs!==void 0&&(t.driftOffsetMs=e.driftOffsetMs),e.ntpStartTime!==void 0&&(t.ntpStartTime=e.ntpStartTime),e.clockOffsetMs!==void 0&&(t.clockOffsetMs=e.clockOffsetMs),e.audioContextState&&(t.audioContextState=e.audioContextState),e.bufferPoolStats&&(t.bufferPoolUsedBytes=e.bufferPoolStats.used.size,t.bufferPoolAvailableBytes=e.bufferPoolStats.available,t.bufferPoolAllocations=e.bufferPoolStats.used.count),e.loadedSynthDefsCount!==void 0&&(t.loadedSynthDefs=e.loadedSynthDefsCount),e.preschedulerCapacity!==void 0&&(t.preschedulerCapacity=e.preschedulerCapacity),this.#h==="postMessage"&&e.transportMetrics&&Object.assign(t,e.transportMetrics),t}updateMergedArray(e={}){let t=this.#a;if(this.#h==="postMessage"){if(e.preschedulerMetrics&&this.overlayPreschedulerMetrics(e.preschedulerMetrics),this.#o){let a=new Uint32Array(this.#o,0,46);t.set(a)}e.transportMetrics&&(e.transportMetrics.oscOutMessagesSent!==void 0&&(t[24]=e.transportMetrics.oscOutMessagesSent),e.transportMetrics.oscOutBytesSent!==void 0&&(t[25]=e.transportMetrics.oscOutBytesSent),e.transportMetrics.preschedulerBypassed!==void 0&&(t[22]=e.transportMetrics.preschedulerBypassed),e.transportMetrics.bypassNonBundle!==void 0&&(t[38]=e.transportMetrics.bypassNonBundle),e.transportMetrics.bypassImmediate!==void 0&&(t[39]=e.transportMetrics.bypassImmediate),e.transportMetrics.bypassNearFuture!==void 0&&(t[40]=e.transportMetrics.bypassNearFuture),e.transportMetrics.bypassLate!==void 0&&(t[41]=e.transportMetrics.bypassLate))}else this.#s&&t.set(this.#s);let s=this.#c;s.setInt32(46*4,e.driftOffsetMs??0,!0),s.setInt32(47*4,e.clockOffsetMs??0,!0);let r=e.audioContextState||"unknown",n={unknown:0,running:1,suspended:2,closed:3,interrupted:4};t[48]=n[r]??0,e.bufferPoolStats&&(t[49]=e.bufferPoolStats.used?.size??0,t[50]=e.bufferPoolStats.available??0,t[51]=e.bufferPoolStats.used?.count??0),t[52]=e.loadedSynthDefsCount??0;let o=this.#t;t[53]=o?.scheduler_slot_count??0,t[54]=e.preschedulerCapacity??0,t[55]=o?.IN_BUFFER_SIZE??0,t[56]=o?.OUT_BUFFER_SIZE??0,t[57]=o?.DEBUG_BUFFER_SIZE??0,t[58]=this.#h==="sab"?0:1}getMergedArray(){return this.#a}get bufferConstants(){return this.#t}get ringBufferBase(){return this.#e}get sharedBuffer(){return this.#r}};function se(i){return i/1e3+2208988800}function Me(i,e){return i-e}function ht(i,e){let t=i-e;return Math.round(t*1e3)}var re=class{#r;#e;#t;#h;#n;#s;#l;#o;#a;#c=0;#u=0;#p=null;constructor(e={}){this.#r=e.mode||"sab",this.#e=e.audioContext,this.#t=e.workletPort||null}initSharedViews(e,t,s){this.#n=t,this.#h=s,this.#r==="sab"&&e&&s&&(this.#s=new Float64Array(e,t+s.NTP_START_TIME_START,1),this.#l=new Int32Array(e,t+s.DRIFT_OFFSET_START,1),this.#o=new Int32Array(e,t+s.GLOBAL_OFFSET_START,1))}setWorkletPort(e){this.#t=e}updateAudioContext(e){this.#e=e}async initialize(){if(!this.#e)return;let e;for(;e=this.#e.getOutputTimestamp(),!(e.contextTime>0);)await new Promise(o=>setTimeout(o,50));e=this.#e.getOutputTimestamp();let t=performance.timeOrigin+e.performanceTime,s=se(t),r=e.contextTime,n=Me(s,r);this.#r==="sab"&&this.#s?this.#s[0]=n:this.#t&&this.#t.postMessage({type:"setNTPStartTime",ntpStartTime:n}),this.#a=n,await new Promise(o=>setTimeout(o,500)),this.updateDriftOffset()}updateDriftOffset(){if(!this.#e||this.#a===void 0)return;let e=this.#e.getOutputTimestamp(),t=performance.timeOrigin+e.performanceTime,r=se(t)-this.#a,n=ht(r,e.contextTime);this.#c=n,this.#r==="sab"&&this.#l?Atomics.store(this.#l,0,n):this.#t&&this.#t.postMessage({type:"setDriftOffset",driftOffsetMs:n})}resync(){if(!this.#e)return;let e=this.#e.getOutputTimestamp();if(!e||e.contextTime<=0)return;let t=performance.timeOrigin+e.performanceTime,s=se(t),r=Me(s,e.contextTime);this.#r==="sab"&&this.#s?this.#s[0]=r:this.#t&&this.#t.postMessage({type:"setNTPStartTime",ntpStartTime:r}),this.#a=r,this.updateDriftOffset()}startDriftTimer(){this.stopDriftTimer(),this.#p=setInterval(()=>{this.updateDriftOffset()},1e3)}stopDriftTimer(){this.#p&&(clearInterval(this.#p),this.#p=null)}getDriftOffset(){return this.#l?Atomics.load(this.#l,0):this.#c}getNTPStartTime(){return this.#s?this.#s[0]:this.#a??0}getClockOffset(){return this.#o?Atomics.load(this.#o,0):this.#u}setClockOffset(e){let t=Math.round(e*1e3);this.#u=t,this.#r==="sab"&&this.#o?Atomics.store(this.#o,0,t):this.#t&&this.#t.postMessage({type:"setClockOffset",clockOffsetMs:t})}calculateBundleWait(e){if(e.length<16||String.fromCharCode.apply(null,e.slice(0,8))!=="#bundle\0")return null;let s=this.getNTPStartTime();if(s===0)return console.warn("[NTPTiming] NTP start time not yet initialized"),null;let n=this.getDriftOffset()/1e3,a=this.getClockOffset()/1e3,c=s+n+a,l=new DataView(e.buffer,e.byteOffset),f=l.getUint32(8,!1),u=l.getUint32(12,!1);if(f===0&&(u===0||u===1))return null;let p=f+u/4294967296-c,m=this.#e?.currentTime??0;return{audioTimeS:p,currentTimeS:m}}reset(){this.stopDriftTimer(),this.#a=void 0,this.#c=0,this.#u=0,this.#s=null,this.#l=null,this.#o=null}};var ie=class{#r;#e;#t;constructor(e={}){this.#r=e.sharedBuffer||null,this.#e=e.bufferConstants||null,this.#t=e.ringBufferBase||0}update(e,t,s){this.#r=e,this.#t=t,this.#e=s}isAvailable(){return!!(this.#r&&this.#e)}start(){if(!this.isAvailable())throw new Error("AudioCapture not initialized");let e=this.#e,t=this.#t+e.AUDIO_CAPTURE_START,s=new Uint32Array(this.#r,t,4);Atomics.store(s,1,0),Atomics.store(s,0,1)}stop(){if(!this.isAvailable())throw new Error("AudioCapture not initialized");let e=this.#e,t=this.#t+e.AUDIO_CAPTURE_START,s=new Uint32Array(this.#r,t,4);Atomics.store(s,0,0);let r=Atomics.load(s,1),n=s[2],o=s[3],a=t+e.AUDIO_CAPTURE_HEADER_SIZE,c=new Float32Array(this.#r,a,r*o),l=new Float32Array(r),f=o>1?new Float32Array(r):null;for(let u=0;u<r;u++)l[u]=c[u*o],f&&(f[u]=c[u*o+1]);return{sampleRate:n,channels:o,frames:r,left:l,right:f}}isEnabled(){if(!this.isAvailable())return!1;let e=this.#e,t=this.#t+e.AUDIO_CAPTURE_START,s=new Uint32Array(this.#r,t,1);return Atomics.load(s,0)===1}getFrameCount(){if(!this.isAvailable())return 0;let e=this.#e,t=this.#t+e.AUDIO_CAPTURE_START,s=new Uint32Array(this.#r,t,2);return Atomics.load(s,1)}getMaxDuration(){if(!this.#e)return 0;let e=this.#e;return e.AUDIO_CAPTURE_FRAMES/(e.AUDIO_CAPTURE_SAMPLE_RATE||48e3)}};function dt(i,e,t){let s=t,r=new Uint32Array(i,e,3),n=r[0],o=r[1],a=r[2],c=e+s.NODE_TREE_HEADER_SIZE,l=s.NODE_TREE_MIRROR_MAX_NODES,f=s.NODE_TREE_ENTRY_SIZE,u=s.NODE_TREE_DEF_NAME_SIZE,d=new DataView(i,c,l*f),p=new TextDecoder("utf-8"),m=[],g=0;for(let y=0;y<l&&g<n;y++){let S=y*f,_=d.getInt32(S,!0);if(_===-1)continue;g++;let h=c+S+24,T=new Uint8Array(i,h,u),A=new Uint8Array(u);A.set(T);let B=A.indexOf(0);B===-1&&(B=u);let de=p.decode(A.subarray(0,B));m.push({id:_,parentId:d.getInt32(S+4,!0),isGroup:d.getInt32(S+8,!0)===1,prevId:d.getInt32(S+12,!0),nextId:d.getInt32(S+16,!0),headId:d.getInt32(S+20,!0),defName:de})}return{nodeCount:n,version:o,droppedCount:a,nodes:m}}var wt={};It(wt,{NTP_EPOCH_OFFSET:()=>ae,TWO_POW_32:()=>W,clearCache:()=>Js,copyEncoded:()=>q,decodeBundle:()=>At,decodeMessage:()=>Tt,decodePacket:()=>V,encodeBundle:()=>le,encodeBundleIntoBuffer:()=>js,encodeMessage:()=>ce,encodeMessageIntoBuffer:()=>Qs,encodeSingleBundle:()=>Ne,getBundleTimeTag:()=>he,getCacheStats:()=>er,isBundle:()=>Bt});var ke=new Uint8Array(2097152),pt=new DataView(ke.buffer),E=ke,b=pt,$=new Map,mt=1e3,Xs=new TextDecoder,Ks=new TextEncoder,ae=2208988800,W=4294967296,Fe=new Uint8Array([35,98,117,110,100,108,101,0]),yt=44,Oe=105,Ue=102,Re=115,Ie=98,De=84,Le=70,Et=104,St=100,gt=116;function ne(i,e){let t=i.length+4;t+=e.length+4;for(let s of e)if(s instanceof Uint8Array)t+=4+s.length+3;else if(s instanceof ArrayBuffer)t+=4+s.byteLength+3;else if(typeof s=="string")t+=s.length*3+4;else if(s&&s.type==="string")t+=s.value.length*3+4;else if(s&&s.type==="blob"){let r=s.value,n=r instanceof Uint8Array?r.length:r.byteLength;t+=4+n+3}else t+=8;return t}function _t(i){let e=16;for(let t of i)e+=4,Array.isArray(t)?e+=ne(t[0],t.slice(1)):t.packets!==void 0?e+=_t(t.packets):e+=ne(t.address,t.args||[]);return e}function xe(i){if(i<=2097152){E=ke,b=pt;return}E=new Uint8Array(i),b=new DataView(E.buffer)}function ce(i,e=[]){let t=ne(i,e);xe(t);let s=0;s=ve(i,s),s=He(e,s);for(let r=0;r<e.length;r++)s=ue(e[r],s);return E.subarray(0,s)}function le(i,e){let t=_t(e);xe(t);let s=0;E.set(Fe,s),s+=8,s=fe(i,s);for(let r=0;r<e.length;r++){let n=e[r],o=s;s+=4;let a=s;Array.isArray(n)?s=oe(n[0],n.slice(1),s):n.packets!==void 0?s=bt(n.timeTag,n.packets,s):s=oe(n.address,n.args||[],s);let c=s-a;b.setUint32(o,c,!1)}return E.subarray(0,s)}function Ne(i,e,t=[]){let s=20+ne(e,t);xe(s);let r=0;E.set(Fe,r),r+=8,r=fe(i,r);let n=r;r+=4;let o=r;r=ve(e,r),r=He(t,r);for(let a=0;a<t.length;a++)r=ue(t[a],r);return b.setUint32(n,r-o,!1),E.subarray(0,r)}function oe(i,e,t){t=ve(i,t),t=He(e,t);for(let s=0;s<e.length;s++)t=ue(e[s],t);return t}function bt(i,e,t){E.set(Fe,t),t+=8,t=fe(i,t);for(let s=0;s<e.length;s++){let r=e[s],n=t;t+=4;let o=t;Array.isArray(r)?t=oe(r[0],r.slice(1),t):r.packets!==void 0?t=bt(r.timeTag,r.packets,t):t=oe(r.address,r.args||[],t),b.setUint32(n,t-o,!1)}return t}function ve(i,e){let t=$.get(i);if(t)return E.set(t,e),e+t.length;let s=e;if(e=Pe(i,e),$.size<mt){let r=E.slice(s,e);$.set(i,r)}return e}function Pe(i,e){let t=!1;for(let s=0;s<i.length;s++)if(i.charCodeAt(s)>=128){t=!0;break}if(t){let s=Ks.encodeInto(i,E.subarray(e));e+=s.written}else for(let s=0;s<i.length;s++)E[e++]=i.charCodeAt(s);for(E[e++]=0;e&3;)E[e++]=0;return e}function He(i,e){E[e++]=yt;for(let t=0;t<i.length;t++){let s=i[t],r=typeof s;if(r==="number")E[e++]=Number.isInteger(s)?Oe:Ue;else if(r==="string")E[e++]=Re;else if(r==="boolean")E[e++]=s?De:Le;else if(s instanceof Uint8Array||s instanceof ArrayBuffer)E[e++]=Ie;else if(s&&s.type==="int")E[e++]=Oe;else if(s&&s.type==="float")E[e++]=Ue;else if(s&&s.type==="string")E[e++]=Re;else if(s&&s.type==="blob")E[e++]=Ie;else if(s&&s.type==="bool")E[e++]=s.value?De:Le;else if(s&&s.type==="int64")E[e++]=Et;else if(s&&s.type==="double")E[e++]=St;else if(s&&s.type==="timetag")E[e++]=gt;else throw s==null?new Error(`OSC argument at index ${t} is ${s}`):new Error(`Unknown OSC argument type at index ${t}: ${r}`)}for(E[e++]=0;e&3;)E[e++]=0;return e}function ue(i,e){let t=typeof i;if(t==="number")return Number.isInteger(i)?(b.setInt32(e,i,!1),e+4):(b.setFloat32(e,i,!1),e+4);if(t==="string")return Pe(i,e);if(t==="boolean")return e;if(i instanceof Uint8Array){let s=i.length;for(b.setUint32(e,s,!1),e+=4,E.set(i,e),e+=s;e&3;)E[e++]=0;return e}if(i instanceof ArrayBuffer)return ue(new Uint8Array(i),e);if(i&&i.type==="int")return b.setInt32(e,i.value,!1),e+4;if(i&&i.type==="float")return b.setFloat32(e,i.value,!1),e+4;if(i&&i.type==="string")return Pe(i.value,e);if(i&&i.type==="blob"){let s=i.value instanceof Uint8Array?i.value:new Uint8Array(i.value),r=s.length;for(b.setUint32(e,r,!1),e+=4,E.set(s,e),e+=r;e&3;)E[e++]=0;return e}return i&&i.type==="bool"?e:i&&i.type==="int64"?(b.setBigInt64(e,BigInt(i.value),!1),e+8):i&&i.type==="double"?(b.setFloat64(e,i.value,!1),e+8):i&&i.type==="timetag"?fe(i.value,e):e}function fe(i,e){if(i===1||i===null||i===void 0)return b.setUint32(e,0,!1),b.setUint32(e+4,1,!1),e+8;if(Array.isArray(i)){if(i.length!==2)throw new Error(`TimeTag array must have exactly 2 elements [seconds, fraction], got ${i.length}`);return b.setUint32(e,i[0]>>>0,!1),b.setUint32(e+4,i[1]>>>0,!1),e+8}if(typeof i!="number")throw new TypeError(`TimeTag must be a number, array, null, or undefined, got ${typeof i}`);i>1&&i<ae&&console.warn(`TimeTag ${i} looks like a Unix timestamp (< NTP_EPOCH_OFFSET). Did you mean to add NTP_EPOCH_OFFSET (2208988800)?`);let t=i>>>0,s=(i-Math.floor(i))*W>>>0;return b.setUint32(e,t,!1),b.setUint32(e+4,s,!1),e+8}function V(i){return i instanceof Uint8Array||(i=new Uint8Array(i)),i[0]===35&&i[1]===98?At(i):Tt(i)}function Tt(i){i instanceof Uint8Array||(i=new Uint8Array(i));let e=new DataView(i.buffer,i.byteOffset,i.byteLength),t=0,[s,r]=Ce(i,t);if(t=r,t>=i.length||i[t]!==yt)return[s];let[n,o]=Ce(i,t);t=o;let a=[s];for(let c=1;c<n.length;c++)switch(n.charCodeAt(c)){case Oe:a.push(e.getInt32(t,!1)),t+=4;break;case Ue:a.push(e.getFloat32(t,!1)),t+=4;break;case Re:let[f,u]=Ce(i,t);a.push(f),t=u;break;case Ie:let d=e.getUint32(t,!1);t+=4,a.push(i.slice(t,t+d)),t+=d,t=t+3&-4;break;case Et:a.push(e.getBigInt64(t,!1)),t+=8;break;case St:a.push(e.getFloat64(t,!1)),t+=8;break;case De:a.push(!0);break;case Le:a.push(!1);break;case gt:let p=e.getUint32(t,!1),m=e.getUint32(t+4,!1);a.push(p+m/W),t+=8;break}return a}function At(i){i instanceof Uint8Array||(i=new Uint8Array(i));let e=new DataView(i.buffer,i.byteOffset,i.byteLength),t=8,s=e.getUint32(t,!1),r=e.getUint32(t+4,!1),n=s+r/W;t+=8;let o=[];for(;t<i.length;){let a=e.getUint32(t,!1);if(t+=4,a>0&&t+a<=i.length){let c=i.subarray(t,t+a);o.push(V(c))}t+=a}return{timeTag:n,packets:o}}function Ce(i,e){let t=e;for(;t<i.length&&i[t]!==0;)t++;let s=Xs.decode(i.subarray(e,t));return t++,t=t+3&-4,[s,t]}function q(i){return i.slice()}function Qs(i,e,t,s){let r=ce(i,e);return t.set(r,s),r.length}function js(i,e,t,s){let r=le(i,e);return t.set(r,s),r.length}function Js(){$.clear()}function er(){return{stringCacheSize:$.size,maxSize:mt}}function Bt(i){return!i||i.length<8?!1:i[0]===35&&i[1]===98}function he(i){if(!Bt(i))return null;let e=new DataView(i.buffer,i.byteOffset,i.byteLength),t=e.getUint32(8,!1),s=e.getUint32(12,!1);return t+s/W}var Mt={totalPages:1280,ringBufferReserved:3145728,bufferPoolOffset:19922944,bufferPoolSize:63963136,get totalMemory(){return this.bufferPoolOffset+this.bufferPoolSize},get wasmHeapSize(){return this.bufferPoolOffset-this.ringBufferReserved}};var Ct={numBuffers:1024,maxNodes:1024,maxGraphDefs:1024,maxWireBufs:64,numAudioBusChannels:128,numInputBusChannels:2,numOutputBusChannels:2,numControlBusChannels:4096,bufLength:128,realTimeMemorySize:8192,numRGens:64,realTime:!1,memoryLocking:!1,loadGraphDefs:0,preferredSampleRate:0,verbosity:0};var ir=new Set(["/b_alloc","/b_allocRead","/b_allocReadChannel","/b_allocFile"]),Ot=class i{static osc={encodeMessage:(e,t)=>q(ce(e,t)),encodeBundle:(e,t)=>q(le(e,t)),decode:e=>V(e),encodeSingleBundle:(e,t,s)=>q(Ne(e,t,s)),readTimetag:e=>me(e),ntpNow:()=>w(),NTP_EPOCH_OFFSET:ae};static#r=null;static getMetricsSchema(){return this.#r??={metrics:{scsynthProcessCount:{offset:0,type:"counter",unit:"count",description:"Audio process() calls"},scsynthMessagesProcessed:{offset:1,type:"counter",unit:"count",description:"OSC messages processed by scsynth"},scsynthMessagesDropped:{offset:2,type:"counter",unit:"count",description:"Messages dropped (ring buffer full)"},scsynthSchedulerDepth:{offset:3,type:"gauge",unit:"count",description:"Current scheduler queue depth"},scsynthSchedulerPeakDepth:{offset:4,type:"gauge",unit:"count",description:"Peak scheduler queue depth (high water mark)"},scsynthSchedulerDropped:{offset:5,type:"counter",unit:"count",description:"Scheduled events dropped"},scsynthSequenceGaps:{offset:6,type:"counter",unit:"count",description:"Messages lost in transit from JS to scsynth"},scsynthWasmErrors:{offset:7,type:"counter",unit:"count",description:"WASM execution errors in audio worklet"},scsynthSchedulerLates:{offset:8,type:"counter",unit:"count",description:"Bundles executed after their scheduled time"},preschedulerPending:{offset:9,type:"gauge",unit:"count",description:"Events waiting to be scheduled"},preschedulerPendingPeak:{offset:10,type:"gauge",unit:"count",description:"Peak pending events"},preschedulerBundlesScheduled:{offset:11,type:"counter",unit:"count",description:"Bundles scheduled"},preschedulerDispatched:{offset:12,type:"counter",unit:"count",description:"Events sent to worklet"},preschedulerEventsCancelled:{offset:13,type:"counter",unit:"count",description:"Events cancelled"},preschedulerMinHeadroomMs:{offset:14,type:"gauge",unit:"ms",description:"Smallest time gap between JS prescheduler dispatch and scsynth scheduler execution"},preschedulerLates:{offset:15,type:"counter",unit:"count",description:"Bundles dispatched after their scheduled execution time"},preschedulerRetriesSucceeded:{offset:16,type:"counter",unit:"count",description:"Retries that succeeded"},preschedulerRetriesFailed:{offset:17,type:"counter",unit:"count",description:"Retries that failed"},preschedulerRetryQueueSize:{offset:18,type:"gauge",unit:"count",description:"Current retry queue size"},preschedulerRetryQueuePeak:{offset:19,type:"gauge",unit:"count",description:"Peak retry queue size"},preschedulerMessagesRetried:{offset:20,type:"counter",unit:"count",description:"Messages that needed retry"},preschedulerTotalDispatches:{offset:21,type:"counter",unit:"count",description:"Total dispatch attempts"},preschedulerBypassed:{offset:22,type:"counter",unit:"count",description:"Messages sent directly from JS to scsynth, bypassing prescheduler (aggregate)"},preschedulerMaxLateMs:{offset:23,type:"gauge",unit:"ms",description:"Maximum lateness at prescheduler (ms)"},oscOutMessagesSent:{offset:24,type:"counter",unit:"count",description:"OSC messages sent from JS to scsynth"},oscOutBytesSent:{offset:25,type:"counter",unit:"bytes",description:"Total bytes sent from JS to scsynth"},oscInMessagesReceived:{offset:26,type:"counter",unit:"count",description:"OSC replies received from scsynth to JS"},oscInBytesReceived:{offset:27,type:"counter",unit:"bytes",description:"Total bytes received from scsynth to JS"},oscInMessagesDropped:{offset:28,type:"counter",unit:"count",description:"Replies lost in transit from scsynth to JS"},oscInCorrupted:{offset:29,type:"counter",unit:"count",description:"Corrupted messages detected from scsynth to JS"},debugMessagesReceived:{offset:30,type:"counter",unit:"count",description:"Debug messages from scsynth"},debugBytesReceived:{offset:31,type:"counter",unit:"bytes",description:"Debug bytes received"},inBufferUsedBytes:{offset:32,type:"gauge",unit:"bytes",description:"Bytes used in IN ring buffer"},outBufferUsedBytes:{offset:33,type:"gauge",unit:"bytes",description:"Bytes used in OUT ring buffer"},debugBufferUsedBytes:{offset:34,type:"gauge",unit:"bytes",description:"Bytes used in DEBUG ring buffer"},inBufferPeakBytes:{offset:35,type:"gauge",unit:"bytes",description:"Peak bytes used in IN ring buffer"},outBufferPeakBytes:{offset:36,type:"gauge",unit:"bytes",description:"Peak bytes used in OUT ring buffer"},debugBufferPeakBytes:{offset:37,type:"gauge",unit:"bytes",description:"Peak bytes used in DEBUG ring buffer"},bypassNonBundle:{offset:38,type:"counter",unit:"count",description:"Plain OSC messages (not bundles) that bypassed prescheduler"},bypassImmediate:{offset:39,type:"counter",unit:"count",description:"Bundles with timetag 0 or 1 that bypassed prescheduler"},bypassNearFuture:{offset:40,type:"counter",unit:"count",description:"Bundles within bypass lookahead threshold that bypassed prescheduler"},bypassLate:{offset:41,type:"counter",unit:"count",description:"Timestamped OSC bundles arriving late into SuperSonic bypassing prescheduler"},scsynthSchedulerMaxLateMs:{offset:42,type:"gauge",unit:"ms",description:"Maximum lateness observed in scsynth scheduler (ms)"},scsynthSchedulerLastLateMs:{offset:43,type:"gauge",unit:"ms",description:"Most recent late magnitude in scsynth scheduler (ms)"},scsynthSchedulerLastLateTick:{offset:44,type:"gauge",unit:"count",description:"Process count when last scsynth late occurred"},ringBufferDirectWriteFails:{offset:45,type:"counter",unit:"count",description:"SAB mode only: optimistic direct writes attempted but failed due to ring buffer lock not being available (delivered via prescheduler instead)"},driftOffsetMs:{offset:46,type:"gauge",unit:"ms",signed:!0,description:"Clock drift between AudioContext and wall clock"},clockOffsetMs:{offset:47,type:"gauge",unit:"ms",signed:!0,description:"Clock offset for multi-system sync"},audioContextState:{offset:48,type:"enum",values:["unknown","running","suspended","closed","interrupted"],description:"AudioContext state"},bufferPoolUsedBytes:{offset:49,type:"gauge",unit:"bytes",description:"Buffer pool bytes used"},bufferPoolAvailableBytes:{offset:50,type:"gauge",unit:"bytes",description:"Buffer pool bytes available"},bufferPoolAllocations:{offset:51,type:"counter",unit:"count",description:"Total buffer allocations"},loadedSynthDefs:{offset:52,type:"gauge",unit:"count",description:"Number of loaded synthdefs"},scsynthSchedulerCapacity:{offset:53,type:"constant",unit:"count",description:"Maximum scheduler queue size"},preschedulerCapacity:{offset:54,type:"constant",unit:"count",description:"Maximum pending events in prescheduler"},inBufferCapacity:{offset:55,type:"constant",unit:"bytes",description:"IN ring buffer capacity"},outBufferCapacity:{offset:56,type:"constant",unit:"bytes",description:"OUT ring buffer capacity"},debugBufferCapacity:{offset:57,type:"constant",unit:"bytes",description:"DEBUG ring buffer capacity"},mode:{offset:58,type:"enum",values:["sab","postMessage"],description:"Transport mode"}},layout:{panels:[{title:"OSC Out",rows:[{label:"sent",cells:[{key:"oscOutMessagesSent"}]},{label:"bytes",cells:[{key:"oscOutBytesSent",kind:"muted",format:"bytes"}]},{label:"bypass",cells:[{key:"preschedulerBypassed",kind:"green"}]},{label:"lost",cells:[{key:"scsynthSequenceGaps",kind:"error"}]}]},{title:"Bypass",rows:[{label:"msg",cells:[{key:"bypassNonBundle",kind:"muted"}]},{label:"imm",cells:[{key:"bypassImmediate",kind:"muted"}]},{label:"near",cells:[{key:"bypassNearFuture",kind:"muted"}]},{label:"late",cells:[{key:"bypassLate",kind:"muted"}]}]},{title:"OSC In",rows:[{label:"received",cells:[{key:"oscInMessagesReceived"}]},{label:"bytes",cells:[{key:"oscInBytesReceived",kind:"muted",format:"bytes"}]},{label:"dropped",cells:[{key:"oscInMessagesDropped",kind:"error"}]},{label:"corrupted",cells:[{key:"oscInCorrupted",kind:"error"}]}]},{title:"Presched Flow",rows:[{label:"pending",cells:[{key:"preschedulerPending"},{sep:" | "},{key:"preschedulerPendingPeak",kind:"muted"}]},{label:"scheduled",cells:[{key:"preschedulerBundlesScheduled"}]},{label:"dispatched",cells:[{key:"preschedulerDispatched",kind:"dim"}]},{label:"min slack",cells:[{key:"preschedulerMinHeadroomMs",kind:"dim",format:"headroom"},{text:" ms",kind:"muted"}]}]},{title:"Presched Health",rows:[{label:"lates",cells:[{key:"preschedulerLates",kind:"error"},{sep:" ("},{key:"preschedulerMaxLateMs",kind:"dim"},{text:"ms max)",kind:"muted"}]},{label:"cancelled",cells:[{key:"preschedulerEventsCancelled",kind:"error"}]},{label:"retried",cells:[{key:"preschedulerMessagesRetried",kind:"dim"},{sep:" | "},{key:"preschedulerRetriesSucceeded",kind:"green"},{sep:" | "},{key:"preschedulerRetriesFailed",kind:"error"}]},{label:"retry queue",cells:[{key:"preschedulerRetryQueueSize"},{sep:" | "},{key:"preschedulerRetryQueuePeak",kind:"muted"}]}]},{title:"scsynth Scheduler",rows:[{label:"queue",cells:[{key:"scsynthSchedulerDepth"},{sep:" | "},{key:"scsynthSchedulerPeakDepth",kind:"muted"}]},{label:"dropped",cells:[{key:"scsynthSchedulerDropped",kind:"error"}]},{label:"lates",cells:[{key:"scsynthSchedulerLates",kind:"error"}]},{label:"max | last",cells:[{key:"scsynthSchedulerMaxLateMs",kind:"error"},{sep:" | "},{key:"scsynthSchedulerLastLateMs",kind:"dim"},{text:" ms",kind:"muted"}]}]},{title:"scsynth",rows:[{label:"processed",cells:[{key:"scsynthMessagesProcessed"}]},{label:"dropped",cells:[{key:"scsynthMessagesDropped",kind:"error"}]},{label:"synthdefs",cells:[{key:"loadedSynthDefs"}]},{label:"clock drift",cells:[{key:"driftOffsetMs",format:"signed"},{text:"ms",kind:"muted"}]}]},{title:"Ring Buffer Level",class:"wide",rows:[{type:"bar",label:"in",usedKey:"inBufferUsedBytes",peakKey:"inBufferPeakBytes",capacityKey:"inBufferCapacity",color:"blue"},{type:"bar",label:"out",usedKey:"outBufferUsedBytes",peakKey:"outBufferPeakBytes",capacityKey:"outBufferCapacity",color:"green"},{type:"bar",label:"dbg",usedKey:"debugBufferUsedBytes",peakKey:"debugBufferPeakBytes",capacityKey:"debugBufferCapacity",color:"purple"},{label:"direct write fails",cells:[{key:"ringBufferDirectWriteFails",kind:"error"}]}]},{title:"AudioWorklet",rows:[{label:"audio",cells:[{key:"audioContextState",kind:"green",format:"enum"}]},{label:"ticks",cells:[{key:"scsynthProcessCount",kind:"dim"}]},{label:"WASM errors",cells:[{key:"scsynthWasmErrors",kind:"error"}]},{label:"debug",cells:[{key:"debugMessagesReceived",kind:"muted"},{text:" ("},{key:"debugBytesReceived",kind:"muted",format:"bytes"},{text:")"}]}]},{title:"Audio Buffers",rows:[{label:"used",cells:[{key:"bufferPoolUsedBytes",format:"bytes"}]},{label:"free",cells:[{key:"bufferPoolAvailableBytes",kind:"green",format:"bytes"}]},{label:"allocs",cells:[{key:"bufferPoolAllocations",kind:"dim"}]}]}]},sentinels:{HEADROOM_UNSET:4294967295}}}static getTreeSchema(){return{nodeCount:{type:"number",description:"Total nodes in tree"},version:{type:"number",description:"Increments on any tree change, useful for detecting updates"},droppedCount:{type:"number",description:"Nodes that exceeded mirror capacity (tree may be incomplete)"},root:{type:"object",description:"Root node of the tree (always a group with id 0)",schema:{id:{type:"number",description:"Unique node ID"},type:{type:"string",values:["group","synth"],description:"Node type"},defName:{type:"string",description:"Synthdef name (synths only, empty for groups)"},children:{type:"array",description:"Child nodes (recursive)",itemSchema:"(self)"}}}}}static getRawTreeSchema(){return{nodeCount:{type:"number",description:"Total nodes in tree"},version:{type:"number",description:"Increments on any tree change, useful for detecting updates"},droppedCount:{type:"number",description:"Nodes that exceeded mirror capacity (tree may be incomplete)"},nodes:{type:"array",description:"Flat array of all nodes with internal linkage pointers",itemSchema:{id:{type:"number",description:"Unique node ID"},parentId:{type:"number",description:"Parent node ID (-1 for root)"},isGroup:{type:"boolean",description:"True if group, false if synth"},prevId:{type:"number",description:"Previous sibling node ID (-1 if none)"},nextId:{type:"number",description:"Next sibling node ID (-1 if none)"},headId:{type:"number",description:"First child node ID (groups only, -1 if empty)"},defName:{type:"string",description:"Synthdef name (synths only, empty for groups)"}}}}}#e;#t;#h=null;#n;#s;#l;#o;#a;#c;#u;#p;#_;#m;#d;#S;#b;#g;#i;#f;#y;#E;#A;#w;#M=null;#B=null;#H=0;#C=[];#U=null;#O=Promise.resolve();#z(e){let t=(s,r,{min:n,max:o,allowZero:a=!0}={})=>{if(typeof r!="number"||!Number.isFinite(r))throw new Error(`scsynthOptions.${s} must be a finite number, got: ${r}`);if(!a&&r===0)throw new Error(`scsynthOptions.${s} must be non-zero, got: ${r}`);if(n!==void 0&&r<n)throw new Error(`scsynthOptions.${s} must be >= ${n}, got: ${r}`);if(o!==void 0&&r>o)throw new Error(`scsynthOptions.${s} must be <= ${o}, got: ${r}`)};if(t("numBuffers",e.numBuffers,{min:1,max:65535}),t("maxNodes",e.maxNodes,{min:1}),t("maxGraphDefs",e.maxGraphDefs,{min:1}),t("maxWireBufs",e.maxWireBufs,{min:1}),t("numAudioBusChannels",e.numAudioBusChannels,{min:1}),t("numInputBusChannels",e.numInputBusChannels,{min:0}),t("numOutputBusChannels",e.numOutputBusChannels,{min:1,max:128}),t("numControlBusChannels",e.numControlBusChannels,{min:1}),e.bufLength!==128)throw new Error(`scsynthOptions.bufLength must be 128 (WebAudio API constraint), got: ${e.bufLength}`);if(t("realTimeMemorySize",e.realTimeMemorySize,{min:1}),t("numRGens",e.numRGens,{min:1}),typeof e.realTime!="boolean")throw new Error(`scsynthOptions.realTime must be a boolean, got: ${typeof e.realTime}`);if(typeof e.memoryLocking!="boolean")throw new Error(`scsynthOptions.memoryLocking must be a boolean, got: ${typeof e.memoryLocking}`);if(e.loadGraphDefs!==0&&e.loadGraphDefs!==1)throw new Error(`scsynthOptions.loadGraphDefs must be 0 or 1, got: ${e.loadGraphDefs}`);if(t("preferredSampleRate",e.preferredSampleRate,{min:0,max:384e3}),e.preferredSampleRate!==0&&e.preferredSampleRate<8e3)throw new Error(`scsynthOptions.preferredSampleRate must be 0 (auto) or >= 8000, got: ${e.preferredSampleRate}`);t("verbosity",e.verbosity,{min:0,max:4})}constructor(e={}){this.#m=!1,this.#d=!1,this.#S=null,this.#b={},this.#g=null,this.#f=new ee,this.#y=new te({mode:e.mode||"postMessage"}),this.#A=new ie({}),this.#e=null,this.#t=null,this.#n=null,this.#l=null,this.loadedSynthDefs=new Map;let t=e.baseURL||null,s=e.coreBaseURL||t,r=e.workerBaseURL||(t?`${t}workers/`:null),n=e.wasmBaseURL||(s?`${s}wasm/`:null);if(!r||!n)throw new Error(`SuperSonic requires explicit URL configuration.
|
|
5
|
+
Or install: npm install supersonic-scsynth-samples`);return this.#e+e}#i(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#f(e,t,s){let r=null,n=null,o=!1,a=await this.#M(e),c=!1;try{await this.#O(e);let{ptr:l,sizeBytes:u,numFrames:f,numChannels:h,sampleRate:S,source:m,...g}=await s();r=l;let{uuid:p,allocationComplete:y}=this.#w(e,t);n=p,this.#R(e,r,u,p,y,{numFrames:f,numChannels:h,sampleRate:S,source:m}),o=!0;let _=this.#U(e,p,y);return a(),c=!0,{ptr:r,uuid:p,allocationComplete:_,numFrames:f,numChannels:h,sampleRate:S,...g}}catch(l){throw o&&n?this.#C(e,n,!1):r&&this.#s.free(r),l}finally{c||a()}}async prepareFromBlob(e){let{bufnum:t,blob:s,startFrame:r=0,numFrames:n=0,channels:o=null}=e;if(this.#i(t),!s||!(s instanceof ArrayBuffer||ArrayBuffer.isView(s)))throw new Error("/b_allocFile requires audio data as ArrayBuffer or typed array");let a=await this.#d({source:s,startFrame:r,numFrames:n,channels:o});return this.#S(t,3e4,a,null)}async prepareFromFile(e){let{bufnum:t,path:s,startFrame:r=0,numFrames:n=0,channels:o=null}=e;this.#i(t);let a=await this.#d({source:s,startFrame:r,numFrames:n,channels:o});return this.#S(t,6e4,a,a.sourceInfo)}async prepareEmpty(e){let{bufnum:t,numFrames:s,numChannels:r=1,sampleRate:n=null}=e;if(this.#i(t),!Number.isFinite(s)||s<=0)throw new Error(`/b_alloc requires a positive number of frames (got ${s})`);if(!Number.isFinite(r)||r<=0)throw new Error(`/b_alloc requires a positive channel count (got ${r})`);let o=Math.floor(s),a=Math.floor(r),c=o*a+(this.GUARD_BEFORE+this.GUARD_AFTER)*a,u={interleaved:new Float32Array(c),numFrames:o,numChannels:a,sampleRate:n||this.#h.sampleRate};return this.#S(t,5e3,u,null)}#y(e,t){return!e||e.length===0?Array.from({length:t},(s,r)=>r):(e.forEach(s=>{if(!Number.isInteger(s)||s<0||s>=t)throw new Error(`Channel ${s} is out of range (file has ${t} channels)`)}),e)}#E(e){let t=e*4,s=this.#s.malloc(t);if(s===0){let r=this.#s.stats(),n=((r.available||0)/(1024*1024)).toFixed(2),o=((r.total||0)/(1024*1024)).toFixed(2),a=(t/(1024*1024)).toFixed(2);throw new Error(`Buffer pool allocation failed: requested ${a}MB, available ${n}MB of ${o}MB total`)}return s}async#A(e,t){if(this.#r==="sab")new Float32Array(this.#n,e,t.length).set(t);else{let s=crypto.randomUUID(),r=new Promise((o,a)=>{let c=setTimeout(()=>{a(new Error("Buffer copy to WASM memory timed out"))},1e4),l=u=>{let f=u.data;f.type==="bufferCopied"&&f.copyId===s&&(this.#p.removeEventListener("message",l),clearTimeout(c),f.success?o():a(new Error(f.error||"Buffer copy failed")))};this.#p.addEventListener("message",l)}),n=t.buffer.slice(t.byteOffset,t.byteOffset+t.byteLength);this.#p.postMessage({type:"copyBufferData",copyId:s,ptr:e,data:n},[n]),await r}}#B(e,t,s){return new Promise((r,n)=>{let o=setTimeout(()=>{this.#c.delete(e),n(new Error(`Buffer ${t} allocation timeout (${s}ms)`))},s);this.#c.set(e,{resolve:r,reject:n,timeout:o})})}#w(e,t){let s=crypto.randomUUID(),r=this.#B(s,e,t);return{uuid:s,allocationComplete:r}}async#M(e){let t=this.#u.get(e)||Promise.resolve(),s,r=new Promise(n=>{s=n});return this.#u.set(e,t.then(()=>r)),await t,()=>{s&&(s(),s=null),this.#u.get(e)===r&&this.#u.delete(e)}}#R(e,t,s,r,n,o={}){let a=this.#o.get(e),c={ptr:t,size:s,numFrames:o.numFrames||0,numChannels:o.numChannels||1,sampleRate:o.sampleRate||48e3,pendingToken:r,pendingPromise:n,previousAllocation:a?{ptr:a.ptr,size:a.size}:null,source:o.source||null};return this.#o.set(e,c),c}async#O(e){let t=this.#o.get(e);if(t&&t.pendingToken&&t.pendingPromise)try{await t.pendingPromise}catch{}}#U(e,t,s){return!s||typeof s.then!="function"?(this.#C(e,t,!0),Promise.resolve()):s.then(r=>(this.#C(e,t,!0),r)).catch(r=>{throw this.#C(e,t,!1),r})}#C(e,t,s){let r=this.#o.get(e);if(!r||r.pendingToken!==t)return;let n=r.previousAllocation;if(s){r.pendingToken=null,r.pendingPromise=null,r.previousAllocation=null,n?.ptr&&this.#s.free(n.ptr);return}r.ptr&&this.#s.free(r.ptr),r.pendingPromise=null,n?.ptr?this.#o.set(e,{ptr:n.ptr,size:n.size,pendingToken:null,previousAllocation:null}):this.#o.delete(e)}handleBufferFreed(e){let t=e[0],s=e[1],r=this.#o.get(t);if(!r){typeof s=="number"&&s!==0&&this.#s.free(s);return}if(typeof s=="number"&&s===r.ptr){this.#s.free(r.ptr),this.#o.delete(t);return}if(typeof s=="number"&&r.previousAllocation&&r.previousAllocation.ptr===s){this.#s.free(s),r.previousAllocation=null;return}this.#s.free(r.ptr),this.#o.delete(t)}handleBufferAllocated(e){let t=e[0],s=e[1],r=this.#c.get(t);r&&(clearTimeout(r.timeout),r.resolve({bufnum:s}),this.#c.delete(t))}allocate(e){let t=e*4,s=this.#s.malloc(t);if(s===0){let r=this.#s.stats(),n=((r.available||0)/(1024*1024)).toFixed(2),o=((r.total||0)/(1024*1024)).toFixed(2),a=(t/(1024*1024)).toFixed(2);console.error(`[BufferManager] Allocation failed: requested ${a}MB, available ${n}MB of ${o}MB total`)}return s}free(e){return this.#s.free(e)}getView(e,t){return new Float32Array(this.#n,e,t)}getStats(){return this.#s?this.#s.stats():{total:0,available:0,used:0,allocations:0}}async sampleInfo({source:e,startFrame:t=0,numFrames:s=0,channels:r=null}){let n=await this.#d({source:e,startFrame:t,numFrames:s,channels:r});return{hash:await this.#_(n.interleaved),source:n.sourceInfo?.path||null,numFrames:n.numFrames,numChannels:n.numChannels,sampleRate:n.sampleRate,duration:n.sampleRate>0?n.numFrames/n.sampleRate:0}}getAllocatedBuffers(){let e=[];for(let[t,s]of this.#o.entries())!s||!s.ptr||e.push({bufnum:t,ptr:s.ptr,numFrames:s.numFrames,numChannels:s.numChannels,sampleRate:s.sampleRate,source:s.source||null,hash:s.hash||null});return e}updateAudioContext(e){if(!e)throw new Error("BufferManager.updateAudioContext requires audioContext");this.#h=e}getDiagnostics(){let e=this.#s.stats(),t=0,s=0;for(let r of this.#o.values())r&&(t+=r.size||0,r.pendingToken&&s++);return{active:this.#o.size,pending:s,bytesActive:t,pool:{total:this.#l,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.#c.entries())clearTimeout(t.timeout),t.reject(new Error("BufferManager destroyed"));this.#c.clear();for(let[e,t]of this.#o.entries())t.ptr&&this.#s.free(t.ptr);this.#o.clear(),this.#u.clear()}};var K=class{#r;#e;#t;constructor(e={}){let{onLoadingEvent:t=null,maxRetries:s=3,baseDelay:r=1e3}=e;this.#r=t,this.#e=s,this.#t=r}async fetch(e,{type:t,name:s}){let r=this.#h(e),n=this.#n(e),o=await r;this.#r?.("loading:start",{type:t,name:s,...o!=null&&{size:o}});let c=await(await n).arrayBuffer();return this.#r?.("loading:complete",{type:t,name:s,size:c.byteLength}),c}async#h(e){try{let t=await fetch(e,{method:"HEAD"});if(t.ok){let s=t.headers.get("Content-Length");return s?parseInt(s,10):null}return null}catch{return null}}async#n(e){let t;for(let s=0;s<=this.#e;s++)try{let r=await fetch(e);if(r.status>=400&&r.status<500)throw new Error(`Failed to fetch ${e}: ${r.status} ${r.statusText}`);if(!r.ok)throw new Error(`Server error fetching ${e}: ${r.status} ${r.statusText}`);return r}catch(r){if(t=r,r.message.includes("Failed to fetch")&&r.message.includes("4"))throw r;if(s<this.#e){let n=this.#t*Math.pow(2,s);await this.#s(n)}}throw t}#s(e){return new Promise(t=>setTimeout(t,e))}};var Q=class{#r;#e;constructor({bufferManager:e,getDefaultSampleRate:t}){if(!e)throw new Error("OSCRewriter requires bufferManager");if(typeof t!="function")throw new Error("OSCRewriter requires getDefaultSampleRate callback");this.#r=e,this.#e=t}async rewritePacket(e){if(Array.isArray(e)){let{message:t,changed:s}=await this.#t(e);return{packet:t,changed:s}}if(this.#o(e)){let t=await Promise.all(e.packets.map(n=>this.rewritePacket(n)));if(!t.some(n=>n.changed))return{packet:e,changed:!1};let r=t.map(n=>n.packet);return{packet:{timeTag:e.timeTag,packets:r},changed:!0}}return{packet:e,changed:!1}}async#t(e){let t=e[0],s=e.slice(1);switch(t){case"/b_alloc":return{message:await this.#h(s),changed:!0};case"/b_allocRead":return{message:await this.#n(s),changed:!0};case"/b_allocReadChannel":return{message:await this.#s(s),changed:!0};case"/b_allocFile":return{message:await this.#l(s),changed:!0};default:return{message:e,changed:!1}}}async#h(e){let t=this.#p(e,0,"/b_alloc requires a buffer number"),s=this.#p(e,1,"/b_alloc requires a frame count"),r=2,n=1,o=this.#e();this.#S(this.#c(e,r))&&(n=Math.max(1,this.#_(e,r,1)),r++),this.#c(e,r)?.type==="b"&&r++,this.#S(this.#c(e,r))&&(o=this.#u(this.#c(e,r)));let a=await this.#r.prepareEmpty({bufnum:t,numFrames:s,numChannels:n,sampleRate:o});return this.#b(a.allocationComplete,`/b_alloc ${t}`),this.#a(t,a)}async#n(e){let t=this.#p(e,0,"/b_allocRead requires a buffer number"),s=this.#d(e,1,"/b_allocRead requires a file path"),r=this.#_(e,2,0),n=this.#_(e,3,0),o=await this.#r.prepareFromFile({bufnum:t,path:s,startFrame:r,numFrames:n});return this.#b(o.allocationComplete,`/b_allocRead ${t}`),this.#a(t,o)}async#s(e){let t=this.#p(e,0,"/b_allocReadChannel requires a buffer number"),s=this.#d(e,1,"/b_allocReadChannel requires a file path"),r=this.#_(e,2,0),n=this.#_(e,3,0),o=[];for(let c=4;c<(e?.length||0)&&this.#S(e[c]);c++)o.push(Math.floor(this.#u(e[c])));let a=await this.#r.prepareFromFile({bufnum:t,path:s,startFrame:r,numFrames:n,channels:o.length>0?o:null});return this.#b(a.allocationComplete,`/b_allocReadChannel ${t}`),this.#a(t,a)}async#l(e){let t=this.#p(e,0,"/b_allocFile requires a buffer number"),s=this.#m(e,1,"/b_allocFile requires audio file data as blob"),r=await this.#r.prepareFromBlob({bufnum:t,blob:s});return this.#b(r.allocationComplete,`/b_allocFile ${t}`),this.#a(t,r)}#a(e,t){return["/b_allocPtr",Math.floor(e),Math.floor(t.ptr),Math.floor(t.numFrames),Math.floor(t.numChannels),t.sampleRate,String(t.uuid)]}#o(e){return e&&e.timeTag!==void 0&&Array.isArray(e.packets)}#c(e,t){if(Array.isArray(e))return e[t]}#u(e){if(e!=null)return typeof e=="object"&&Object.prototype.hasOwnProperty.call(e,"value")?e.value:e}#p(e,t,s){let r=this.#u(this.#c(e,t));if(!Number.isFinite(r))throw new Error(s);return Math.floor(r)}#_(e,t,s=0){let r=this.#u(this.#c(e,t));return Number.isFinite(r)?Math.floor(r):s}#d(e,t,s){let r=this.#u(this.#c(e,t));if(typeof r!="string")throw new Error(s);return r}#m(e,t,s){let r=this.#u(this.#c(e,t));if(!(r instanceof Uint8Array||r instanceof ArrayBuffer))throw new Error(s);return r}#S(e){if(!e)return!1;let t=this.#u(e);return Number.isFinite(t)}#b(e,t){!e||typeof e.catch!="function"||e.catch(s=>{console.error(`[OSCRewriter] ${t} allocation failed:`,s)})}};function F(i){if(!i)return null;if(typeof i=="string")return(i.split("/").filter(Boolean).pop()||i).replace(/\.scsyndef$/i,"");let e=i instanceof ArrayBuffer?new Uint8Array(i):i;if(!(e instanceof Uint8Array)||e.length<11||e[0]!==83||e[1]!==67||e[2]!==103||e[3]!==102)return null;let t=e[10];if(t===0||11+t>e.length)return null;try{return new TextDecoder().decode(e.slice(11,11+t))}catch{return null}}var j=class{#r=new Map;on(e,t){if(typeof t!="function")throw new Error("Callback must be a function");return this.#r.has(e)||this.#r.set(e,new Set),this.#r.get(e).add(t),()=>this.off(e,t)}off(e,t){let s=this.#r.get(e);return s&&s.delete(t),this}once(e,t){let s=(...r)=>{this.off(e,s),t(...r)};return this.on(e,s)}removeAllListeners(e){return e===void 0?this.#r.clear():this.#r.delete(e),this}hasListeners(e){let t=this.#r.get(e);return t?t.size>0:!1}emit(e,...t){let s=this.#r.get(e);if(s)for(let r of s)try{r(...t)}catch(n){console.error(`[EventEmitter] Error in ${e} listener:`,n)}}async emitAsync(e,...t){let s=this.#r.get(e);if(s)for(let r of s)try{await r(...t)}catch(n){console.error(`[EventEmitter] Error in ${e} listener:`,n)}}clearAllListeners(){this.#r.clear()}};var J=class{#r;#e;#t;#h;#n;#s;#l;#a=null;#o=new Uint32Array(64);#c=new DataView(this.#o.buffer);constructor(e={}){this.#h=e.mode||"sab",this.#r=e.sharedBuffer||null,this.#e=e.ringBufferBase||0,this.#t=e.bufferConstants||null}initSharedViews(e,t,s){if(this.#r=e,this.#e=t,this.#t=s,this.#h==="sab"&&e&&s){this.#n=new Int32Array(e),this.#l=qe(t,s.CONTROL_START);let r=t+s.METRICS_START;this.#s=new Uint32Array(e,r,s.METRICS_SIZE/4)}}updateSnapshot(e){this.#a=e}getSnapshotBuffer(){return this.#a}getMetricsView(){return this.#s}addMetric(e,t=1){if(!this.#s)return;let r={oscOutMessagesSent:24,oscOutBytesSent:25,preschedulerBypassed:22,bypassNonBundle:38,bypassImmediate:39,bypassNearFuture:40,bypassLate:41}[e];r!==void 0&&Atomics.add(this.#s,r,t)}parseMetricsBuffer(e){return{scsynthProcessCount:e[0],scsynthMessagesProcessed:e[1],scsynthMessagesDropped:e[2],scsynthSchedulerDepth:e[3],scsynthSchedulerPeakDepth:e[4],scsynthSchedulerDropped:e[5],scsynthSequenceGaps:e[6],scsynthSchedulerLates:e[8],scsynthSchedulerMaxLateMs:e[42],scsynthSchedulerLastLateMs:e[43],scsynthSchedulerLastLateTick:e[44],preschedulerPending:e[9],preschedulerPendingPeak:e[10],preschedulerDispatched:e[12],preschedulerRetriesSucceeded:e[16],preschedulerRetriesFailed:e[17],preschedulerBundlesScheduled:e[11],preschedulerEventsCancelled:e[13],preschedulerTotalDispatches:e[21],preschedulerMessagesRetried:e[20],preschedulerRetryQueueSize:e[18],preschedulerRetryQueuePeak:e[19],preschedulerBypassed:e[22],oscInMessagesReceived:e[26],oscInMessagesDropped:e[28],oscInBytesReceived:e[27],debugMessagesReceived:e[30],debugBytesReceived:e[31],oscOutMessagesSent:e[24],oscOutBytesSent:e[25],preschedulerMinHeadroomMs:e[14],preschedulerLates:e[15],preschedulerMaxLateMs:e[23],scsynthWasmErrors:e[7],oscInCorrupted:e[29],ringBufferDirectWriteFails:e[45],inBufferUsedBytes:e[32],outBufferUsedBytes:e[33],debugBufferUsedBytes:e[34],inBufferPeakBytes:e[35],outBufferPeakBytes:e[36],debugBufferPeakBytes:e[37],bypassNonBundle:e[38],bypassImmediate:e[39],bypassNearFuture:e[40],bypassLate:e[41]}}getSABMetrics(){return this.#s?this.parseMetricsBuffer(this.#s):null}getBufferUsage(){if(!this.#n||!this.#t||!this.#l)return null;let e=this.#t,t=this.#l,s=this.#n,r=Atomics.load(s,t.IN_HEAD),n=Atomics.load(s,t.IN_TAIL),o=Atomics.load(s,t.OUT_HEAD),a=Atomics.load(s,t.OUT_TAIL),c=Atomics.load(s,t.DEBUG_HEAD),l=Atomics.load(s,t.DEBUG_TAIL),u=(r-n+e.IN_BUFFER_SIZE)%e.IN_BUFFER_SIZE,f=(o-a+e.OUT_BUFFER_SIZE)%e.OUT_BUFFER_SIZE,h=(c-l+e.DEBUG_BUFFER_SIZE)%e.DEBUG_BUFFER_SIZE;return{inBufferUsed:{bytes:u,percentage:u/e.IN_BUFFER_SIZE*100,capacity:e.IN_BUFFER_SIZE},outBufferUsed:{bytes:f,percentage:f/e.OUT_BUFFER_SIZE*100,capacity:e.OUT_BUFFER_SIZE},debugBufferUsed:{bytes:h,percentage:h/e.DEBUG_BUFFER_SIZE*100,capacity:e.DEBUG_BUFFER_SIZE}}}overlayPreschedulerMetrics(e){if(!this.#a||!e)return;let t=new Uint32Array(this.#a,0,46),s=9,r=13;t.set(e.subarray(s,s+r),s),t[23]=e[23]}gatherMetrics(e={}){let t;if(this.#h==="postMessage")if(e.preschedulerMetrics&&this.overlayPreschedulerMetrics(e.preschedulerMetrics),this.#a){let s=new Uint32Array(this.#a,0,46);t=this.parseMetricsBuffer(s)}else t={};else t=this.getSABMetrics()||{};if(t.inBufferUsedBytes!==void 0&&this.#t){let s=this.#t;t.inBufferUsed={bytes:t.inBufferUsedBytes,percentage:t.inBufferUsedBytes/s.IN_BUFFER_SIZE*100,peakBytes:t.inBufferPeakBytes,peakPercentage:t.inBufferPeakBytes/s.IN_BUFFER_SIZE*100,capacity:s.IN_BUFFER_SIZE},t.outBufferUsed={bytes:t.outBufferUsedBytes,percentage:t.outBufferUsedBytes/s.OUT_BUFFER_SIZE*100,peakBytes:t.outBufferPeakBytes,peakPercentage:t.outBufferPeakBytes/s.OUT_BUFFER_SIZE*100,capacity:s.OUT_BUFFER_SIZE},t.debugBufferUsed={bytes:t.debugBufferUsedBytes,percentage:t.debugBufferUsedBytes/s.DEBUG_BUFFER_SIZE*100,peakBytes:t.debugBufferPeakBytes,peakPercentage:t.debugBufferPeakBytes/s.DEBUG_BUFFER_SIZE*100,capacity:s.DEBUG_BUFFER_SIZE},delete t.inBufferUsedBytes,delete t.outBufferUsedBytes,delete t.debugBufferUsedBytes,delete t.inBufferPeakBytes,delete t.outBufferPeakBytes,delete t.debugBufferPeakBytes}return t.mode=this.#h,this.#t?.scheduler_slot_count!==void 0&&(t.scsynthSchedulerCapacity=this.#t.scheduler_slot_count),e.driftOffsetMs!==void 0&&(t.driftOffsetMs=e.driftOffsetMs),e.ntpStartTime!==void 0&&(t.ntpStartTime=e.ntpStartTime),e.clockOffsetMs!==void 0&&(t.clockOffsetMs=e.clockOffsetMs),e.audioContextState&&(t.audioContextState=e.audioContextState),e.bufferPoolStats&&(t.bufferPoolUsedBytes=e.bufferPoolStats.used.size,t.bufferPoolAvailableBytes=e.bufferPoolStats.available,t.bufferPoolAllocations=e.bufferPoolStats.used.count),e.loadedSynthDefsCount!==void 0&&(t.loadedSynthDefs=e.loadedSynthDefsCount),e.preschedulerCapacity!==void 0&&(t.preschedulerCapacity=e.preschedulerCapacity),this.#h==="postMessage"&&e.transportMetrics&&Object.assign(t,e.transportMetrics),t}updateMergedArray(e={}){let t=this.#o;if(this.#h==="postMessage"){if(e.preschedulerMetrics&&this.overlayPreschedulerMetrics(e.preschedulerMetrics),this.#a){let a=new Uint32Array(this.#a,0,46);t.set(a)}e.transportMetrics&&(e.transportMetrics.oscOutMessagesSent!==void 0&&(t[24]=e.transportMetrics.oscOutMessagesSent),e.transportMetrics.oscOutBytesSent!==void 0&&(t[25]=e.transportMetrics.oscOutBytesSent),e.transportMetrics.preschedulerBypassed!==void 0&&(t[22]=e.transportMetrics.preschedulerBypassed),e.transportMetrics.bypassNonBundle!==void 0&&(t[38]=e.transportMetrics.bypassNonBundle),e.transportMetrics.bypassImmediate!==void 0&&(t[39]=e.transportMetrics.bypassImmediate),e.transportMetrics.bypassNearFuture!==void 0&&(t[40]=e.transportMetrics.bypassNearFuture),e.transportMetrics.bypassLate!==void 0&&(t[41]=e.transportMetrics.bypassLate))}else this.#s&&t.set(this.#s);let s=this.#c;s.setInt32(46*4,e.driftOffsetMs??0,!0),s.setInt32(47*4,e.clockOffsetMs??0,!0);let r=e.audioContextState||"unknown",n={unknown:0,running:1,suspended:2,closed:3,interrupted:4};t[48]=n[r]??0,e.bufferPoolStats&&(t[49]=e.bufferPoolStats.used?.size??0,t[50]=e.bufferPoolStats.available??0,t[51]=e.bufferPoolStats.used?.count??0),t[52]=e.loadedSynthDefsCount??0;let o=this.#t;t[53]=o?.scheduler_slot_count??0,t[54]=e.preschedulerCapacity??0,t[55]=o?.IN_BUFFER_SIZE??0,t[56]=o?.OUT_BUFFER_SIZE??0,t[57]=o?.DEBUG_BUFFER_SIZE??0,t[58]=this.#h==="sab"?0:1}getMergedArray(){return this.#o}get bufferConstants(){return this.#t}get ringBufferBase(){return this.#e}get sharedBuffer(){return this.#r}};function ee(i){return i/1e3+2208988800}function we(i,e){return i-e}function ft(i,e){let t=i-e;return Math.round(t*1e3)}var te=class{#r;#e;#t;#h;#n;#s;#l;#a;#o;#c=0;#u=0;#p=null;constructor(e={}){this.#r=e.mode||"sab",this.#e=e.audioContext,this.#t=e.workletPort||null}initSharedViews(e,t,s){this.#n=t,this.#h=s,this.#r==="sab"&&e&&s&&(this.#s=new Float64Array(e,t+s.NTP_START_TIME_START,1),this.#l=new Int32Array(e,t+s.DRIFT_OFFSET_START,1),this.#a=new Int32Array(e,t+s.GLOBAL_OFFSET_START,1))}setWorkletPort(e){this.#t=e}updateAudioContext(e){this.#e=e}async initialize(){if(!this.#e)return;let e;for(;e=this.#e.getOutputTimestamp(),!(e.contextTime>0);)await new Promise(o=>setTimeout(o,50));e=this.#e.getOutputTimestamp();let t=performance.timeOrigin+e.performanceTime,s=ee(t),r=e.contextTime,n=we(s,r);this.#r==="sab"&&this.#s?this.#s[0]=n:this.#t&&this.#t.postMessage({type:"setNTPStartTime",ntpStartTime:n}),this.#o=n,await new Promise(o=>setTimeout(o,500)),this.updateDriftOffset()}updateDriftOffset(){if(!this.#e||this.#o===void 0)return;let e=this.#e.getOutputTimestamp(),t=performance.timeOrigin+e.performanceTime,r=ee(t)-this.#o,n=ft(r,e.contextTime);this.#c=n,this.#r==="sab"&&this.#l?Atomics.store(this.#l,0,n):this.#t&&this.#t.postMessage({type:"setDriftOffset",driftOffsetMs:n})}resync(){if(!this.#e)return;let e=this.#e.getOutputTimestamp();if(!e||e.contextTime<=0)return;let t=performance.timeOrigin+e.performanceTime,s=ee(t),r=we(s,e.contextTime);this.#r==="sab"&&this.#s?this.#s[0]=r:this.#t&&this.#t.postMessage({type:"setNTPStartTime",ntpStartTime:r}),this.#o=r,this.updateDriftOffset()}startDriftTimer(){this.stopDriftTimer(),this.#p=setInterval(()=>{this.updateDriftOffset()},1e3)}stopDriftTimer(){this.#p&&(clearInterval(this.#p),this.#p=null)}getDriftOffset(){return this.#l?Atomics.load(this.#l,0):this.#c}getNTPStartTime(){return this.#s?this.#s[0]:this.#o??0}getClockOffset(){return this.#a?Atomics.load(this.#a,0):this.#u}setClockOffset(e){let t=Math.round(e*1e3);this.#u=t,this.#r==="sab"&&this.#a?Atomics.store(this.#a,0,t):this.#t&&this.#t.postMessage({type:"setClockOffset",clockOffsetMs:t})}calculateBundleWait(e){if(e.length<16||String.fromCharCode.apply(null,e.slice(0,8))!=="#bundle\0")return null;let s=this.getNTPStartTime();if(s===0)return console.warn("[NTPTiming] NTP start time not yet initialized"),null;let n=this.getDriftOffset()/1e3,a=this.getClockOffset()/1e3,c=s+n+a,l=new DataView(e.buffer,e.byteOffset),u=l.getUint32(8,!1),f=l.getUint32(12,!1);if(u===0&&(f===0||f===1))return null;let S=u+f/4294967296-c,m=this.#e?.currentTime??0;return{audioTimeS:S,currentTimeS:m}}reset(){this.stopDriftTimer(),this.#o=void 0,this.#c=0,this.#u=0,this.#s=null,this.#l=null,this.#a=null}};var se=class{#r;#e;#t;constructor(e={}){this.#r=e.sharedBuffer||null,this.#e=e.bufferConstants||null,this.#t=e.ringBufferBase||0}update(e,t,s){this.#r=e,this.#t=t,this.#e=s}isAvailable(){return!!(this.#r&&this.#e)}start(){if(!this.isAvailable())throw new Error("AudioCapture not initialized");let e=this.#e,t=this.#t+e.AUDIO_CAPTURE_START,s=new Uint32Array(this.#r,t,4);Atomics.store(s,1,0),Atomics.store(s,0,1)}stop(){if(!this.isAvailable())throw new Error("AudioCapture not initialized");let e=this.#e,t=this.#t+e.AUDIO_CAPTURE_START,s=new Uint32Array(this.#r,t,4);Atomics.store(s,0,0);let r=Atomics.load(s,1),n=s[2],o=s[3],a=t+e.AUDIO_CAPTURE_HEADER_SIZE,c=new Float32Array(this.#r,a,r*o),l=new Float32Array(r),u=o>1?new Float32Array(r):null;for(let f=0;f<r;f++)l[f]=c[f*o],u&&(u[f]=c[f*o+1]);return{sampleRate:n,channels:o,frames:r,left:l,right:u}}isEnabled(){if(!this.isAvailable())return!1;let e=this.#e,t=this.#t+e.AUDIO_CAPTURE_START,s=new Uint32Array(this.#r,t,1);return Atomics.load(s,0)===1}getFrameCount(){if(!this.isAvailable())return 0;let e=this.#e,t=this.#t+e.AUDIO_CAPTURE_START,s=new Uint32Array(this.#r,t,2);return Atomics.load(s,1)}getMaxDuration(){if(!this.#e)return 0;let e=this.#e;return e.AUDIO_CAPTURE_FRAMES/(e.AUDIO_CAPTURE_SAMPLE_RATE||48e3)}};function ht(i,e,t){let s=t,r=new Uint32Array(i,e,3),n=r[0],o=r[1],a=r[2],c=e+s.NODE_TREE_HEADER_SIZE,l=s.NODE_TREE_MIRROR_MAX_NODES,u=s.NODE_TREE_ENTRY_SIZE,f=s.NODE_TREE_DEF_NAME_SIZE,h=new DataView(i,c,l*u),S=new TextDecoder("utf-8"),m=[],g=0;for(let p=0;p<l&&g<n;p++){let y=p*u,_=h.getInt32(y,!0);if(_===-1)continue;g++;let d=c+y+24,w=new Uint8Array(i,d,f),fe=new Uint8Array(f);fe.set(w);let he=fe.indexOf(0);he===-1&&(he=f);let Ot=S.decode(fe.subarray(0,he));m.push({id:_,parentId:h.getInt32(y+4,!0),isGroup:h.getInt32(y+8,!0)===1,prevId:h.getInt32(y+12,!0),nextId:h.getInt32(y+16,!0),headId:h.getInt32(y+20,!0),defName:Ot})}return{nodeCount:n,version:o,droppedCount:a,nodes:m}}var Bt={};Rt(Bt,{NTP_EPOCH_OFFSET:()=>ne,TWO_POW_32:()=>G,clearCache:()=>js,copyEncoded:()=>W,decodeBundle:()=>Tt,decodeMessage:()=>bt,decodePacket:()=>$,encodeBundle:()=>ae,encodeBundleIntoBuffer:()=>Qs,encodeMessage:()=>oe,encodeMessageIntoBuffer:()=>Ks,encodeSingleBundle:()=>xe,getBundleTimeTag:()=>ue,getCacheStats:()=>Js,isBundle:()=>At});var Pe=new Uint8Array(2097152),dt=new DataView(Pe.buffer),E=Pe,b=dt,Y=new Map,pt=1e3,Zs=new TextDecoder,Xs=new TextEncoder,ne=2208988800,G=4294967296,ke=new Uint8Array([35,98,117,110,100,108,101,0]),mt=44,Ce=105,Oe=102,Ue=115,Re=98,Ie=84,De=70,yt=104,Et=100,St=116;function re(i,e){let t=i.length+4;t+=e.length+4;for(let s of e)if(s instanceof Uint8Array)t+=4+s.length+3;else if(s instanceof ArrayBuffer)t+=4+s.byteLength+3;else if(typeof s=="string")t+=s.length*3+4;else if(s&&s.type==="string")t+=s.value.length*3+4;else if(s&&s.type==="blob"){let r=s.value,n=r instanceof Uint8Array?r.length:r.byteLength;t+=4+n+3}else t+=8;return t}function gt(i){let e=16;for(let t of i)e+=4,Array.isArray(t)?e+=re(t[0],t.slice(1)):t.packets!==void 0?e+=gt(t.packets):e+=re(t.address,t.args||[]);return e}function Fe(i){if(i<=2097152){E=Pe,b=dt;return}E=new Uint8Array(i),b=new DataView(E.buffer)}function oe(i,e=[]){let t=re(i,e);Fe(t);let s=0;s=Ne(i,s),s=ve(e,s);for(let r=0;r<e.length;r++)s=ce(e[r],s);return E.subarray(0,s)}function ae(i,e){let t=gt(e);Fe(t);let s=0;E.set(ke,s),s+=8,s=le(i,s);for(let r=0;r<e.length;r++){let n=e[r],o=s;s+=4;let a=s;Array.isArray(n)?s=ie(n[0],n.slice(1),s):n.packets!==void 0?s=_t(n.timeTag,n.packets,s):s=ie(n.address,n.args||[],s);let c=s-a;b.setUint32(o,c,!1)}return E.subarray(0,s)}function xe(i,e,t=[]){let s=20+re(e,t);Fe(s);let r=0;E.set(ke,r),r+=8,r=le(i,r);let n=r;r+=4;let o=r;r=Ne(e,r),r=ve(t,r);for(let a=0;a<t.length;a++)r=ce(t[a],r);return b.setUint32(n,r-o,!1),E.subarray(0,r)}function ie(i,e,t){t=Ne(i,t),t=ve(e,t);for(let s=0;s<e.length;s++)t=ce(e[s],t);return t}function _t(i,e,t){E.set(ke,t),t+=8,t=le(i,t);for(let s=0;s<e.length;s++){let r=e[s],n=t;t+=4;let o=t;Array.isArray(r)?t=ie(r[0],r.slice(1),t):r.packets!==void 0?t=_t(r.timeTag,r.packets,t):t=ie(r.address,r.args||[],t),b.setUint32(n,t-o,!1)}return t}function Ne(i,e){let t=Y.get(i);if(t)return E.set(t,e),e+t.length;let s=e;if(e=Le(i,e),Y.size<pt){let r=E.slice(s,e);Y.set(i,r)}return e}function Le(i,e){let t=!1;for(let s=0;s<i.length;s++)if(i.charCodeAt(s)>=128){t=!0;break}if(t){let s=Xs.encodeInto(i,E.subarray(e));e+=s.written}else for(let s=0;s<i.length;s++)E[e++]=i.charCodeAt(s);for(E[e++]=0;e&3;)E[e++]=0;return e}function ve(i,e){E[e++]=mt;for(let t=0;t<i.length;t++){let s=i[t],r=typeof s;if(r==="number")E[e++]=Number.isInteger(s)?Ce:Oe;else if(r==="string")E[e++]=Ue;else if(r==="boolean")E[e++]=s?Ie:De;else if(s instanceof Uint8Array||s instanceof ArrayBuffer)E[e++]=Re;else if(s&&s.type==="int")E[e++]=Ce;else if(s&&s.type==="float")E[e++]=Oe;else if(s&&s.type==="string")E[e++]=Ue;else if(s&&s.type==="blob")E[e++]=Re;else if(s&&s.type==="bool")E[e++]=s.value?Ie:De;else if(s&&s.type==="int64")E[e++]=yt;else if(s&&s.type==="double")E[e++]=Et;else if(s&&s.type==="timetag")E[e++]=St;else throw s==null?new Error(`OSC argument at index ${t} is ${s}`):new Error(`Unknown OSC argument type at index ${t}: ${r}`)}for(E[e++]=0;e&3;)E[e++]=0;return e}function ce(i,e){let t=typeof i;if(t==="number")return Number.isInteger(i)?(b.setInt32(e,i,!1),e+4):(b.setFloat32(e,i,!1),e+4);if(t==="string")return Le(i,e);if(t==="boolean")return e;if(i instanceof Uint8Array){let s=i.length;for(b.setUint32(e,s,!1),e+=4,E.set(i,e),e+=s;e&3;)E[e++]=0;return e}if(i instanceof ArrayBuffer)return ce(new Uint8Array(i),e);if(i&&i.type==="int")return b.setInt32(e,i.value,!1),e+4;if(i&&i.type==="float")return b.setFloat32(e,i.value,!1),e+4;if(i&&i.type==="string")return Le(i.value,e);if(i&&i.type==="blob"){let s=i.value instanceof Uint8Array?i.value:new Uint8Array(i.value),r=s.length;for(b.setUint32(e,r,!1),e+=4,E.set(s,e),e+=r;e&3;)E[e++]=0;return e}return i&&i.type==="bool"?e:i&&i.type==="int64"?(b.setBigInt64(e,BigInt(i.value),!1),e+8):i&&i.type==="double"?(b.setFloat64(e,i.value,!1),e+8):i&&i.type==="timetag"?le(i.value,e):e}function le(i,e){if(i===1||i===null||i===void 0)return b.setUint32(e,0,!1),b.setUint32(e+4,1,!1),e+8;if(Array.isArray(i)){if(i.length!==2)throw new Error(`TimeTag array must have exactly 2 elements [seconds, fraction], got ${i.length}`);return b.setUint32(e,i[0]>>>0,!1),b.setUint32(e+4,i[1]>>>0,!1),e+8}if(typeof i!="number")throw new TypeError(`TimeTag must be a number, array, null, or undefined, got ${typeof i}`);i>1&&i<ne&&console.warn(`TimeTag ${i} looks like a Unix timestamp (< NTP_EPOCH_OFFSET). Did you mean to add NTP_EPOCH_OFFSET (2208988800)?`);let t=i>>>0,s=(i-Math.floor(i))*G>>>0;return b.setUint32(e,t,!1),b.setUint32(e+4,s,!1),e+8}function $(i){return i instanceof Uint8Array||(i=new Uint8Array(i)),i[0]===35&&i[1]===98?Tt(i):bt(i)}function bt(i){i instanceof Uint8Array||(i=new Uint8Array(i));let e=new DataView(i.buffer,i.byteOffset,i.byteLength),t=0,[s,r]=Me(i,t);if(t=r,t>=i.length||i[t]!==mt)return[s];let[n,o]=Me(i,t);t=o;let a=[s];for(let c=1;c<n.length;c++)switch(n.charCodeAt(c)){case Ce:a.push(e.getInt32(t,!1)),t+=4;break;case Oe:a.push(e.getFloat32(t,!1)),t+=4;break;case Ue:let[u,f]=Me(i,t);a.push(u),t=f;break;case Re:let h=e.getUint32(t,!1);t+=4,a.push(i.slice(t,t+h)),t+=h,t=t+3&-4;break;case yt:a.push(e.getBigInt64(t,!1)),t+=8;break;case Et:a.push(e.getFloat64(t,!1)),t+=8;break;case Ie:a.push(!0);break;case De:a.push(!1);break;case St:let S=e.getUint32(t,!1),m=e.getUint32(t+4,!1);a.push(S+m/G),t+=8;break}return a}function Tt(i){i instanceof Uint8Array||(i=new Uint8Array(i));let e=new DataView(i.buffer,i.byteOffset,i.byteLength),t=8,s=e.getUint32(t,!1),r=e.getUint32(t+4,!1),n=s+r/G;t+=8;let o=[];for(;t<i.length;){let a=e.getUint32(t,!1);if(t+=4,a>0&&t+a<=i.length){let c=i.subarray(t,t+a);o.push($(c))}t+=a}return{timeTag:n,packets:o}}function Me(i,e){let t=e;for(;t<i.length&&i[t]!==0;)t++;let s=Zs.decode(i.subarray(e,t));return t++,t=t+3&-4,[s,t]}function W(i){return i.slice()}function Ks(i,e,t,s){let r=oe(i,e);return t.set(r,s),r.length}function Qs(i,e,t,s){let r=ae(i,e);return t.set(r,s),r.length}function js(){Y.clear()}function Js(){return{stringCacheSize:Y.size,maxSize:pt}}function At(i){return!i||i.length<8?!1:i[0]===35&&i[1]===98}function ue(i){if(!At(i))return null;let e=new DataView(i.buffer,i.byteOffset,i.byteLength),t=e.getUint32(8,!1),s=e.getUint32(12,!1);return t+s/G}var wt={totalPages:1280,ringBufferReserved:3145728,bufferPoolOffset:19922944,bufferPoolSize:63963136,get totalMemory(){return this.bufferPoolOffset+this.bufferPoolSize},get wasmHeapSize(){return this.bufferPoolOffset-this.ringBufferReserved}};var Mt={numBuffers:1024,maxNodes:1024,maxGraphDefs:1024,maxWireBufs:64,numAudioBusChannels:128,numInputBusChannels:2,numOutputBusChannels:2,numControlBusChannels:4096,bufLength:128,realTimeMemorySize:8192,numRGens:64,realTime:!1,memoryLocking:!1,loadGraphDefs:0,preferredSampleRate:0,verbosity:0};var rr=new Set(["/b_alloc","/b_allocRead","/b_allocReadChannel","/b_allocFile"]),Ct=class i{static osc={encodeMessage:(e,t)=>W(oe(e,t)),encodeBundle:(e,t)=>W(ae(e,t)),decode:e=>$(e),encodeSingleBundle:(e,t,s)=>W(xe(e,t,s)),readTimetag:e=>pe(e),ntpNow:()=>T(),NTP_EPOCH_OFFSET:ne};static#r=null;static getMetricsSchema(){return this.#r??={metrics:{scsynthProcessCount:{offset:0,type:"counter",unit:"count",description:"Audio process() calls"},scsynthMessagesProcessed:{offset:1,type:"counter",unit:"count",description:"OSC messages processed by scsynth"},scsynthMessagesDropped:{offset:2,type:"counter",unit:"count",description:"Messages dropped (ring buffer full)"},scsynthSchedulerDepth:{offset:3,type:"gauge",unit:"count",description:"Current scheduler queue depth"},scsynthSchedulerPeakDepth:{offset:4,type:"gauge",unit:"count",description:"Peak scheduler queue depth (high water mark)"},scsynthSchedulerDropped:{offset:5,type:"counter",unit:"count",description:"Scheduled events dropped"},scsynthSequenceGaps:{offset:6,type:"counter",unit:"count",description:"Messages lost in transit from JS to scsynth"},scsynthWasmErrors:{offset:7,type:"counter",unit:"count",description:"WASM execution errors in audio worklet"},scsynthSchedulerLates:{offset:8,type:"counter",unit:"count",description:"Bundles executed after their scheduled time"},preschedulerPending:{offset:9,type:"gauge",unit:"count",description:"Events waiting to be scheduled"},preschedulerPendingPeak:{offset:10,type:"gauge",unit:"count",description:"Peak pending events"},preschedulerBundlesScheduled:{offset:11,type:"counter",unit:"count",description:"Bundles scheduled"},preschedulerDispatched:{offset:12,type:"counter",unit:"count",description:"Events sent to worklet"},preschedulerEventsCancelled:{offset:13,type:"counter",unit:"count",description:"Events cancelled"},preschedulerMinHeadroomMs:{offset:14,type:"gauge",unit:"ms",description:"Smallest time gap between JS prescheduler dispatch and scsynth scheduler execution"},preschedulerLates:{offset:15,type:"counter",unit:"count",description:"Bundles dispatched after their scheduled execution time"},preschedulerRetriesSucceeded:{offset:16,type:"counter",unit:"count",description:"Retries that succeeded"},preschedulerRetriesFailed:{offset:17,type:"counter",unit:"count",description:"Retries that failed"},preschedulerRetryQueueSize:{offset:18,type:"gauge",unit:"count",description:"Current retry queue size"},preschedulerRetryQueuePeak:{offset:19,type:"gauge",unit:"count",description:"Peak retry queue size"},preschedulerMessagesRetried:{offset:20,type:"counter",unit:"count",description:"Messages that needed retry"},preschedulerTotalDispatches:{offset:21,type:"counter",unit:"count",description:"Total dispatch attempts"},preschedulerBypassed:{offset:22,type:"counter",unit:"count",description:"Messages sent directly from JS to scsynth, bypassing prescheduler (aggregate)"},preschedulerMaxLateMs:{offset:23,type:"gauge",unit:"ms",description:"Maximum lateness at prescheduler (ms)"},oscOutMessagesSent:{offset:24,type:"counter",unit:"count",description:"OSC messages sent from JS to scsynth"},oscOutBytesSent:{offset:25,type:"counter",unit:"bytes",description:"Total bytes sent from JS to scsynth"},oscInMessagesReceived:{offset:26,type:"counter",unit:"count",description:"OSC replies received from scsynth to JS"},oscInBytesReceived:{offset:27,type:"counter",unit:"bytes",description:"Total bytes received from scsynth to JS"},oscInMessagesDropped:{offset:28,type:"counter",unit:"count",description:"Replies lost in transit from scsynth to JS"},oscInCorrupted:{offset:29,type:"counter",unit:"count",description:"Corrupted messages detected from scsynth to JS"},debugMessagesReceived:{offset:30,type:"counter",unit:"count",description:"Debug messages from scsynth"},debugBytesReceived:{offset:31,type:"counter",unit:"bytes",description:"Debug bytes received"},inBufferUsedBytes:{offset:32,type:"gauge",unit:"bytes",description:"Bytes used in IN ring buffer"},outBufferUsedBytes:{offset:33,type:"gauge",unit:"bytes",description:"Bytes used in OUT ring buffer"},debugBufferUsedBytes:{offset:34,type:"gauge",unit:"bytes",description:"Bytes used in DEBUG ring buffer"},inBufferPeakBytes:{offset:35,type:"gauge",unit:"bytes",description:"Peak bytes used in IN ring buffer"},outBufferPeakBytes:{offset:36,type:"gauge",unit:"bytes",description:"Peak bytes used in OUT ring buffer"},debugBufferPeakBytes:{offset:37,type:"gauge",unit:"bytes",description:"Peak bytes used in DEBUG ring buffer"},bypassNonBundle:{offset:38,type:"counter",unit:"count",description:"Plain OSC messages (not bundles) that bypassed prescheduler"},bypassImmediate:{offset:39,type:"counter",unit:"count",description:"Bundles with timetag 0 or 1 that bypassed prescheduler"},bypassNearFuture:{offset:40,type:"counter",unit:"count",description:"Bundles within bypass lookahead threshold that bypassed prescheduler"},bypassLate:{offset:41,type:"counter",unit:"count",description:"Timestamped OSC bundles arriving late into SuperSonic bypassing prescheduler"},scsynthSchedulerMaxLateMs:{offset:42,type:"gauge",unit:"ms",description:"Maximum lateness observed in scsynth scheduler (ms)"},scsynthSchedulerLastLateMs:{offset:43,type:"gauge",unit:"ms",description:"Most recent late magnitude in scsynth scheduler (ms)"},scsynthSchedulerLastLateTick:{offset:44,type:"gauge",unit:"count",description:"Process count when last scsynth late occurred"},ringBufferDirectWriteFails:{offset:45,type:"counter",unit:"count",description:"SAB mode only: optimistic direct writes attempted but failed due to ring buffer lock not being available (delivered via prescheduler instead)"},driftOffsetMs:{offset:46,type:"gauge",unit:"ms",signed:!0,description:"Clock drift between AudioContext and wall clock"},clockOffsetMs:{offset:47,type:"gauge",unit:"ms",signed:!0,description:"Clock offset for multi-system sync"},audioContextState:{offset:48,type:"enum",values:["unknown","running","suspended","closed","interrupted"],description:"AudioContext state"},bufferPoolUsedBytes:{offset:49,type:"gauge",unit:"bytes",description:"Buffer pool bytes used"},bufferPoolAvailableBytes:{offset:50,type:"gauge",unit:"bytes",description:"Buffer pool bytes available"},bufferPoolAllocations:{offset:51,type:"counter",unit:"count",description:"Total buffer allocations"},loadedSynthDefs:{offset:52,type:"gauge",unit:"count",description:"Number of loaded synthdefs"},scsynthSchedulerCapacity:{offset:53,type:"constant",unit:"count",description:"Maximum scheduler queue size"},preschedulerCapacity:{offset:54,type:"constant",unit:"count",description:"Maximum pending events in prescheduler"},inBufferCapacity:{offset:55,type:"constant",unit:"bytes",description:"IN ring buffer capacity"},outBufferCapacity:{offset:56,type:"constant",unit:"bytes",description:"OUT ring buffer capacity"},debugBufferCapacity:{offset:57,type:"constant",unit:"bytes",description:"DEBUG ring buffer capacity"},mode:{offset:58,type:"enum",values:["sab","postMessage"],description:"Transport mode"}},layout:{panels:[{title:"OSC Out",rows:[{label:"sent",cells:[{key:"oscOutMessagesSent"}]},{label:"bytes",cells:[{key:"oscOutBytesSent",kind:"muted",format:"bytes"}]},{label:"bypass",cells:[{key:"preschedulerBypassed",kind:"green"}]},{label:"lost",cells:[{key:"scsynthSequenceGaps",kind:"error"}]}]},{title:"Bypass",rows:[{label:"msg",cells:[{key:"bypassNonBundle",kind:"muted"}]},{label:"imm",cells:[{key:"bypassImmediate",kind:"muted"}]},{label:"near",cells:[{key:"bypassNearFuture",kind:"muted"}]},{label:"late",cells:[{key:"bypassLate",kind:"muted"}]}]},{title:"OSC In",rows:[{label:"received",cells:[{key:"oscInMessagesReceived"}]},{label:"bytes",cells:[{key:"oscInBytesReceived",kind:"muted",format:"bytes"}]},{label:"dropped",cells:[{key:"oscInMessagesDropped",kind:"error"}]},{label:"corrupted",cells:[{key:"oscInCorrupted",kind:"error"}]}]},{title:"Presched Flow",rows:[{label:"pending",cells:[{key:"preschedulerPending"},{sep:" | "},{key:"preschedulerPendingPeak",kind:"muted"}]},{label:"scheduled",cells:[{key:"preschedulerBundlesScheduled"}]},{label:"dispatched",cells:[{key:"preschedulerDispatched",kind:"dim"}]},{label:"min slack",cells:[{key:"preschedulerMinHeadroomMs",kind:"dim",format:"headroom"},{text:" ms",kind:"muted"}]}]},{title:"Presched Health",rows:[{label:"lates",cells:[{key:"preschedulerLates",kind:"error"},{sep:" ("},{key:"preschedulerMaxLateMs",kind:"dim"},{text:"ms max)",kind:"muted"}]},{label:"cancelled",cells:[{key:"preschedulerEventsCancelled",kind:"error"}]},{label:"retried",cells:[{key:"preschedulerMessagesRetried",kind:"dim"},{sep:" | "},{key:"preschedulerRetriesSucceeded",kind:"green"},{sep:" | "},{key:"preschedulerRetriesFailed",kind:"error"}]},{label:"retry queue",cells:[{key:"preschedulerRetryQueueSize"},{sep:" | "},{key:"preschedulerRetryQueuePeak",kind:"muted"}]}]},{title:"scsynth Scheduler",rows:[{label:"queue",cells:[{key:"scsynthSchedulerDepth"},{sep:" | "},{key:"scsynthSchedulerPeakDepth",kind:"muted"}]},{label:"dropped",cells:[{key:"scsynthSchedulerDropped",kind:"error"}]},{label:"lates",cells:[{key:"scsynthSchedulerLates",kind:"error"}]},{label:"max | last",cells:[{key:"scsynthSchedulerMaxLateMs",kind:"error"},{sep:" | "},{key:"scsynthSchedulerLastLateMs",kind:"dim"},{text:" ms",kind:"muted"}]}]},{title:"scsynth",rows:[{label:"processed",cells:[{key:"scsynthMessagesProcessed"}]},{label:"dropped",cells:[{key:"scsynthMessagesDropped",kind:"error"}]},{label:"synthdefs",cells:[{key:"loadedSynthDefs"}]},{label:"clock drift",cells:[{key:"driftOffsetMs",format:"signed"},{text:"ms",kind:"muted"}]}]},{title:"Ring Buffer Level",class:"wide",rows:[{type:"bar",label:"in",usedKey:"inBufferUsedBytes",peakKey:"inBufferPeakBytes",capacityKey:"inBufferCapacity",color:"blue"},{type:"bar",label:"out",usedKey:"outBufferUsedBytes",peakKey:"outBufferPeakBytes",capacityKey:"outBufferCapacity",color:"green"},{type:"bar",label:"dbg",usedKey:"debugBufferUsedBytes",peakKey:"debugBufferPeakBytes",capacityKey:"debugBufferCapacity",color:"purple"},{label:"direct write fails",cells:[{key:"ringBufferDirectWriteFails",kind:"error"}]}]},{title:"AudioWorklet",rows:[{label:"audio",cells:[{key:"audioContextState",kind:"green",format:"enum"}]},{label:"ticks",cells:[{key:"scsynthProcessCount",kind:"dim"}]},{label:"WASM errors",cells:[{key:"scsynthWasmErrors",kind:"error"}]},{label:"debug",cells:[{key:"debugMessagesReceived",kind:"muted"},{text:" ("},{key:"debugBytesReceived",kind:"muted",format:"bytes"},{text:")"}]}]},{title:"Audio Buffers",rows:[{label:"used",cells:[{key:"bufferPoolUsedBytes",format:"bytes"}]},{label:"free",cells:[{key:"bufferPoolAvailableBytes",kind:"green",format:"bytes"}]},{label:"allocs",cells:[{key:"bufferPoolAllocations",kind:"dim"}]}]}]},sentinels:{HEADROOM_UNSET:4294967295}}}static getTreeSchema(){return{nodeCount:{type:"number",description:"Total nodes in tree"},version:{type:"number",description:"Increments on any tree change, useful for detecting updates"},droppedCount:{type:"number",description:"Nodes that exceeded mirror capacity (tree may be incomplete)"},root:{type:"object",description:"Root node of the tree (always a group with id 0)",schema:{id:{type:"number",description:"Unique node ID"},type:{type:"string",values:["group","synth"],description:"Node type"},defName:{type:"string",description:"Synthdef name (synths only, empty for groups)"},children:{type:"array",description:"Child nodes (recursive)",itemSchema:"(self)"}}}}}static getRawTreeSchema(){return{nodeCount:{type:"number",description:"Total nodes in tree"},version:{type:"number",description:"Increments on any tree change, useful for detecting updates"},droppedCount:{type:"number",description:"Nodes that exceeded mirror capacity (tree may be incomplete)"},nodes:{type:"array",description:"Flat array of all nodes with internal linkage pointers",itemSchema:{id:{type:"number",description:"Unique node ID"},parentId:{type:"number",description:"Parent node ID (-1 for root)"},isGroup:{type:"boolean",description:"True if group, false if synth"},prevId:{type:"number",description:"Previous sibling node ID (-1 if none)"},nextId:{type:"number",description:"Next sibling node ID (-1 if none)"},headId:{type:"number",description:"First child node ID (groups only, -1 if empty)"},defName:{type:"string",description:"Synthdef name (synths only, empty for groups)"}}}}}#e;#t;#h=null;#n;#s;#l;#a;#o;#c;#u;#p;#_;#d;#m;#S;#b;#g;#i;#f;#y;#E;#A;#B;#w=null;#M=null;#R=0;#O=[];#U=null;#C=Promise.resolve();#z(e){let t=(s,r,{min:n,max:o,allowZero:a=!0}={})=>{if(typeof r!="number"||!Number.isFinite(r))throw new Error(`scsynthOptions.${s} must be a finite number, got: ${r}`);if(!a&&r===0)throw new Error(`scsynthOptions.${s} must be non-zero, got: ${r}`);if(n!==void 0&&r<n)throw new Error(`scsynthOptions.${s} must be >= ${n}, got: ${r}`);if(o!==void 0&&r>o)throw new Error(`scsynthOptions.${s} must be <= ${o}, got: ${r}`)};if(t("numBuffers",e.numBuffers,{min:1,max:65535}),t("maxNodes",e.maxNodes,{min:1}),t("maxGraphDefs",e.maxGraphDefs,{min:1}),t("maxWireBufs",e.maxWireBufs,{min:1}),t("numAudioBusChannels",e.numAudioBusChannels,{min:1}),t("numInputBusChannels",e.numInputBusChannels,{min:0}),t("numOutputBusChannels",e.numOutputBusChannels,{min:1,max:128}),t("numControlBusChannels",e.numControlBusChannels,{min:1}),e.bufLength!==128)throw new Error(`scsynthOptions.bufLength must be 128 (WebAudio API constraint), got: ${e.bufLength}`);if(t("realTimeMemorySize",e.realTimeMemorySize,{min:1}),t("numRGens",e.numRGens,{min:1}),typeof e.realTime!="boolean")throw new Error(`scsynthOptions.realTime must be a boolean, got: ${typeof e.realTime}`);if(typeof e.memoryLocking!="boolean")throw new Error(`scsynthOptions.memoryLocking must be a boolean, got: ${typeof e.memoryLocking}`);if(e.loadGraphDefs!==0&&e.loadGraphDefs!==1)throw new Error(`scsynthOptions.loadGraphDefs must be 0 or 1, got: ${e.loadGraphDefs}`);if(t("preferredSampleRate",e.preferredSampleRate,{min:0,max:384e3}),e.preferredSampleRate!==0&&e.preferredSampleRate<8e3)throw new Error(`scsynthOptions.preferredSampleRate must be 0 (auto) or >= 8000, got: ${e.preferredSampleRate}`);t("verbosity",e.verbosity,{min:0,max:4})}constructor(e={}){this.#d=!1,this.#m=!1,this.#S=null,this.#b={},this.#g=null,this.#f=new j,this.#y=new J({mode:e.mode||"postMessage"}),this.#A=new se({}),this.#e=null,this.#t=null,this.#n=null,this.#l=null,this.loadedSynthDefs=new Map;let t=e.baseURL||null,s=e.coreBaseURL||t,r=e.workerBaseURL||(t?`${t}workers/`:null),n=e.wasmBaseURL||(s?`${s}wasm/`:null);if(!r||!n)throw new Error(`SuperSonic requires explicit URL configuration.
|
|
6
6
|
|
|
7
7
|
For CDN usage:
|
|
8
8
|
import { SuperSonic } from 'https://unpkg.com/supersonic-scsynth@VERSION/dist/supersonic.js';
|
|
@@ -14,6 +14,6 @@ For CDN usage:
|
|
|
14
14
|
For local usage:
|
|
15
15
|
new SuperSonic({ baseURL: '/path/to/supersonic/dist/' })
|
|
16
16
|
|
|
17
|
-
See: https://github.com/samaaron/supersonic#configuration`);let o={...Ct,...e.scsynthOptions};this.#z(o);let a=e.mode||"postMessage";this.#i={mode:a,snapshotIntervalMs:e.snapshotIntervalMs??150,wasmUrl:e.wasmUrl||n+"scsynth-nrt.wasm",wasmBaseURL:n,workletUrl:e.workletUrl||(s?`${s}workers/scsynth_audio_worklet.js`:r+"scsynth_audio_worklet.js"),workerBaseURL:r,audioContext:e.audioContext||null,autoConnect:e.autoConnect!==!1,audioContextOptions:{latencyHint:"interactive",sampleRate:48e3,...e.audioContextOptions},memory:Mt,worldOptions:o,preschedulerCapacity:e.preschedulerCapacity||65536,bypassLookaheadMs:e.bypassLookaheadMs??500,activityEvent:{maxLineLength:e.activityEvent?.maxLineLength??200,scsynthMaxLineLength:e.activityEvent?.scsynthMaxLineLength??null,oscInMaxLineLength:e.activityEvent?.oscInMaxLineLength??null,oscOutMaxLineLength:e.activityEvent?.oscOutMaxLineLength??null},debug:e.debug??!1,debugScsynth:e.debugScsynth??!1,debugOscIn:e.debugOscIn??!1,debugOscOut:e.debugOscOut??!1,activityConsoleLog:{maxLineLength:e.activityConsoleLog?.maxLineLength??200,scsynthMaxLineLength:e.activityConsoleLog?.scsynthMaxLineLength??null,oscInMaxLineLength:e.activityConsoleLog?.oscInMaxLineLength??null,oscOutMaxLineLength:e.activityConsoleLog?.oscOutMaxLineLength??null}},this.#c=e.sampleBaseURL||(t?`${t}samples/`:null),this.#u=e.synthdefBaseURL||(t?`${t}synthdefs/`:null),this.#p={maxRetries:e.fetchMaxRetries??3,baseDelay:e.fetchRetryDelay??1e3},this.#_=new j({onLoadingEvent:(c,l)=>this.#f.emit(c,l),maxRetries:this.#p.maxRetries,baseDelay:this.#p.baseDelay}),this.bootStats={initStartTime:null,initDuration:null}}get initialized(){return this.#m}get initializing(){return this.#d}get audioContext(){return this.#e}get mode(){return this.#i.mode}get bufferConstants(){return this.#y.bufferConstants}get ringBufferBase(){return this.#y.ringBufferBase}get sharedBuffer(){return this.#y.sharedBuffer}get node(){return this.#h}get osc(){return this.#n}get initTime(){return this.#E?.getNTPStartTime()??0}on(e,t){return this.#f.on(e,t)}off(e,t){return this.#f.off(e,t),this}once(e,t){return this.#f.once(e,t)}removeAllListeners(e){return this.#f.removeAllListeners(e),this}async init(){if(!this.#m)return this.#S?this.#S:(this.#S=this.#Y(),this.#S)}async#Y(){this.#d=!0,this.bootStats.initStartTime=performance.now();try{this.#W(),this.#V(),this.#R(),this.#q(),this.#I();let e=await this.#D();await this.#L(e),await this.#P(),await this.#k()}catch(e){throw this.#d=!1,this.#S=null,console.error("[SuperSonic] Initialization failed:",e),this.#f.emit("error",e),e}}getMetrics(){return this.#x()}getMetricsArray(){return this.#Q(),this.#y.getMergedArray()}getSnapshot(){let e=this.#x(),t=i.getMetricsSchema()?.metrics||{},s={};for(let[n,o]of Object.entries(e)){let a=t[n];a?.description?s[n]={value:o,description:a.description}:s[n]={value:o}}let r=null;return typeof performance<"u"&&performance.memory&&(r={usedJSHeapSize:performance.memory.usedJSHeapSize,totalJSHeapSize:performance.memory.totalJSHeapSize,jsHeapSizeLimit:performance.memory.jsHeapSizeLimit}),{timestamp:new Date().toISOString(),metrics:s,nodeTree:this.getRawTree(),memory:r}}setClockOffset(e){this.#T("set clock offset"),this.#E?.setClockOffset(e)}async recover(){return this.#m?await this.resume()?!0:await this.reload():!1}async resume(){if(!this.#m||!this.#e)return!1;await this.purge();try{await this.#e.resume()}catch{}this.#E?.startDriftTimer();let e=this.#N();if(e===null){let r=this.#e.state==="running";return r&&(this.#E?.resync(),this.#f.emit("resumed")),r}await new Promise(r=>setTimeout(r,200));let t=this.#N(),s=t!==null&&t>e;return s&&(this.#E?.resync(),this.#f.emit("resumed")),s}async suspend(){if(this.#m){this.#E?.stopDriftTimer();try{await this.#e?.suspend()}catch{}}}async reload(){if(!this.#m)return!1;this.#f.emit("reload:start");let e=new Map(this.loadedSynthDefs),t=this.#l?.getAllocatedBuffers()||[];await this.#G(),await this.#$();for(let[s,r]of e)try{await this.send("/d_recv",r)}catch(n){console.error(`[SuperSonic] Failed to restore synthdef ${s}:`,n)}for(let s of t)try{if(this.#i.mode==="postMessage"&&s.source)s.source.type==="file"&&await this.loadSample(s.bufnum,s.source.path,s.source.startFrame||0,s.source.numFrames||0);else{let r=crypto.randomUUID();await this.send("/b_allocPtr",s.bufnum,s.ptr,s.numFrames,s.numChannels,s.sampleRate,r)}}catch(r){console.error(`[SuperSonic] Failed to restore buffer ${s.bufnum}:`,r)}return(e.size>0||t.length>0)&&await this.sync(),this.#f.emit("reload:complete",{success:!0}),!0}async#G(){this.#E?.stopDriftTimer(),this.#a?.clear(),this.#a=null,this.#n&&(this.#n.cancelAll(),this.#n.dispose(),this.#n=null),this.#t&&(this.#t.disconnect(),this.#t=null),this.#e&&(await this.#e.close(),this.#e=null),this.#m=!1,this.loadedSynthDefs.clear(),this.#S=null,this.#w=null,this.#E?.reset()}async#$(){this.#d=!0,this.bootStats.initStartTime=performance.now();try{this.#R(),this.#l&&this.#l.updateAudioContext(this.#e),this.#I();let e=await this.#D();await this.#L(e),await this.#P(),await this.#k()}catch(e){throw this.#d=!1,this.#S=null,console.error("[SuperSonic] Partial init failed:",e),this.#f.emit("error",e),e}}getRawTree(){if(!this.#m)return{nodeCount:0,version:0,droppedCount:0,nodes:[]};let e=this.#y.bufferConstants;if(!e)return{nodeCount:0,version:0,droppedCount:0,nodes:[]};let t,s;if(this.#i.mode==="postMessage"){let r=this.#y.getSnapshotBuffer();if(!r)return{nodeCount:0,version:0,droppedCount:0,nodes:[]};t=r,s=e.METRICS_SIZE}else{let r=this.#y.sharedBuffer;if(!r)return{nodeCount:0,version:0,droppedCount:0,nodes:[]};t=r,s=this.#y.ringBufferBase+e.NODE_TREE_START}return dt(t,s,e)}getTree(){let e=this.getRawTree(),t=n=>({id:n.id,type:n.isGroup?"group":"synth",defName:n.defName,children:[]}),s=new Map;for(let n of e.nodes)s.set(n.id,t(n));let r=null;for(let n of e.nodes){let o=s.get(n.id);if(n.parentId===-1||n.parentId===0&&n.id===0)r=o;else{let a=s.get(n.parentId);a&&a.children.push(o)}}return{nodeCount:e.nodeCount,version:e.version,droppedCount:e.droppedCount,root:r||{id:0,type:"group",defName:"",children:[]}}}startCapture(){this.#T("start capture"),this.#A.start()}stopCapture(){return this.#T("stop capture"),this.#A.stop()}isCaptureEnabled(){return this.#A.isEnabled()}getCaptureFrames(){return this.#A.getFrameCount()}getMaxCaptureDuration(){return this.#A.getMaxDuration()}send(e,...t){this.#T("send OSC messages");let s={"/d_load":"Use loadSynthDef() or send /d_recv with synthdef bytes instead.","/d_loadDir":"Use loadSynthDef() or send /d_recv with synthdef bytes instead.","/b_read":"Use loadSample() to load audio into a buffer.","/b_readChannel":"Use loadSample() to load audio into a buffer.","/b_write":"Writing audio files is not available in the browser.","/b_close":"Writing audio files is not available in the browser.","/clearSched":"Use purge() to clear both the JS prescheduler and WASM scheduler.","/error":"SuperSonic always enables error notifications so you never miss a /fail message."};if(s[e])throw new Error(`${e} is not supported in SuperSonic. ${s[e]}`);if(e==="/d_recv"){let o=t[0];if(o instanceof Uint8Array||o instanceof ArrayBuffer){let a=o instanceof ArrayBuffer?new Uint8Array(o):o,c=N(a)||"unknown";this.loadedSynthDefs.set(c,a)}}if(e==="/d_free")for(let o of t)typeof o=="string"&&this.loadedSynthDefs.delete(o);else e==="/d_freeAll"&&this.loadedSynthDefs.clear();let r=t.map(o=>o instanceof ArrayBuffer?new Uint8Array(o):o);if(this.#i.debug||this.#i.debugOscOut){let o=this.#i.activityConsoleLog.oscOutMaxLineLength??this.#i.activityConsoleLog.maxLineLength,a=t.map(c=>{if(c instanceof Uint8Array||c instanceof ArrayBuffer)return`<${c.byteLength||c.length} bytes>`;let l=JSON.stringify(c);return l.length>o?l.slice(0,o)+"...":l}).join(", ");console.log(`[OSC \u2192] ${e}${a?" "+a:""}`)}if(ir.has(e)){this.#ee(e,r),this.#te(e,r);return}let n=i.osc.encodeMessage(e,r);this.sendOSC(n)}sendOSC(e,t={}){this.#T("send OSC data");let s=this.#J(e);this.#v(s,t)}cancelTag(e){this.#T("cancel by tag"),this.#n.cancelTag(e)}cancelSession(e){this.#T("cancel by session"),this.#n.cancelSession(e)}cancelSessionTag(e,t){this.#T("cancel by session and tag"),this.#n.cancelSessionTag(e,t)}cancelAll(){this.#T("cancel all scheduled"),this.#n.cancelAll()}async purge(){this.#T("purge");let e=this.#n.cancelAllWithAck(),t=new Promise(s=>{let r=n=>{n.data.type==="clearSchedAck"&&(this.#t.port.removeEventListener("message",r),s())};this.#t.port.addEventListener("message",r),this.#t.port.postMessage({type:"clearSched",ack:!0})});await Promise.all([e,t])}createOscChannel(e={}){return this.#T("create OSC channel"),this.#n.createOscChannel(e)}async loadSynthDef(e){this.#T("load synthdef");let t,s;if(typeof e=="string"){let r;if(this.#j(e))r=e;else{if(!this.#u)throw new Error("synthdefBaseURL not configured.");r=`${this.#u}${e}.scsyndef`}let n=N(r),o=await this.#_.fetch(r,{type:"synthdef",name:n});t=new Uint8Array(o),s=N(t)||n}else if(e instanceof ArrayBuffer||ArrayBuffer.isView(e)){if(t=e instanceof ArrayBuffer?new Uint8Array(e):new Uint8Array(e.buffer,e.byteOffset,e.byteLength),s=N(t),!s)throw new Error("Could not extract synthdef name from binary data. Make sure it's a valid .scsyndef file.")}else if(e instanceof Blob){let r=await e.arrayBuffer();if(t=new Uint8Array(r),s=N(t),!s)throw new Error("Could not extract synthdef name from file. Make sure it's a valid .scsyndef file.")}else throw new Error("loadSynthDef source must be a name, path/URL string, ArrayBuffer, Uint8Array, or File/Blob");return await this.send("/d_recv",t),{name:s,size:t.length}}async loadSynthDefs(e){this.#T("load synthdefs");let t={};return await Promise.all(e.map(async s=>{try{await this.loadSynthDef(s),t[s]={success:!0}}catch(r){t[s]={success:!1,error:r.message}}})),t}async loadSample(e,t,s=0,r=0){this.#T("load samples");let n;if(typeof t=="string")n=await this.#l.prepareFromFile({bufnum:e,path:t,startFrame:s,numFrames:r});else if(t instanceof ArrayBuffer||ArrayBuffer.isView(t))n=await this.#l.prepareFromBlob({bufnum:e,blob:t,startFrame:s,numFrames:r});else if(t instanceof Blob){let o=await t.arrayBuffer();n=await this.#l.prepareFromBlob({bufnum:e,blob:o,startFrame:s,numFrames:r})}else throw new Error("loadSample source must be a path/URL string, ArrayBuffer, TypedArray, or File/Blob");return await this.send("/b_allocPtr",e,n.ptr,n.numFrames,n.numChannels,n.sampleRate,n.uuid),await n.allocationComplete}getLoadedBuffers(){return this.#T("get loaded buffers"),(this.#l?.getAllocatedBuffers()||[]).map(({bufnum:t,numFrames:s,numChannels:r,sampleRate:n,source:o})=>({bufnum:t,numFrames:s,numChannels:r,sampleRate:n,source:o?.path||o?.name||null,duration:n>0?s/n:0}))}async sync(e=Math.floor(Math.random()*2147483647)){this.#T("sync"),await this.#se();let t=new Promise((s,r)=>{let n=setTimeout(()=>{this.#a?.delete(e),r(new Error("Timeout waiting for /synced response"))},1e4),o=()=>{clearTimeout(n),this.#a.delete(e),s()};this.#a||(this.#a=new Map),this.#a.set(e,o)});this.send("/sync",e),await t,this.#i.mode==="postMessage"&&await new Promise(s=>setTimeout(s,this.#i.snapshotIntervalMs*2))}getInfo(){return this.#T("get info"),{sampleRate:this.#e.sampleRate,numBuffers:this.#i.worldOptions.numBuffers,totalMemory:this.#i.memory.totalMemory,wasmHeapSize:this.#i.memory.wasmHeapSize,bufferPoolSize:this.#i.memory.bufferPoolSize,bootTimeMs:this.bootStats.initDuration,capabilities:{...this.#b},version:this.#g}}async shutdown(){!this.#m&&!this.#d||(this.#f.emit("shutdown"),this.#E?.stopDriftTimer(),this.#a?.clear(),this.#a=null,this.#n&&(this.#n.cancelAll(),this.#n.dispose(),this.#n=null),this.#t&&(this.#t.disconnect(),this.#t=null),this.#e&&(await this.#e.close(),this.#e=null),this.#l&&(this.#l.destroy(),this.#l=null),this.#o=null,this.#w=null,this.#O=Promise.resolve(),this.#m=!1,this.loadedSynthDefs.clear(),this.#S=null,this.#s=null,this.#E?.reset(),this.bootStats={initStartTime:null,initDuration:null})}async destroy(){this.#f.emit("destroy"),await this.shutdown(),this.#B=null,this.#f.clearAllListeners()}async reset(){await this.shutdown(),await this.init()}#W(){this.#b={audioWorklet:typeof AudioWorklet<"u",sharedArrayBuffer:typeof SharedArrayBuffer<"u",crossOriginIsolated:window.crossOriginIsolated===!0,atomics:typeof Atomics<"u",webWorker:typeof Worker<"u"};let e=this.#i.mode,t=["audioWorklet","webWorker"];e==="sab"&&t.push("sharedArrayBuffer","crossOriginIsolated","atomics");let s=t.filter(r=>!this.#b[r]);if(s.length>0){let r=new Error(`Missing required features for ${e} mode: ${s.join(", ")}`);throw e==="sab"&&!this.#b.crossOriginIsolated&&(r.message+=`
|
|
17
|
+
See: https://github.com/samaaron/supersonic#configuration`);let o={...Mt,...e.scsynthOptions};this.#z(o);let a=e.mode||"postMessage";this.#i={mode:a,snapshotIntervalMs:e.snapshotIntervalMs??150,wasmUrl:e.wasmUrl||n+"scsynth-nrt.wasm",wasmBaseURL:n,workletUrl:e.workletUrl||(s?`${s}workers/scsynth_audio_worklet.js`:r+"scsynth_audio_worklet.js"),workerBaseURL:r,audioContext:e.audioContext||null,autoConnect:e.autoConnect!==!1,audioContextOptions:{latencyHint:"interactive",sampleRate:48e3,...e.audioContextOptions},memory:wt,worldOptions:o,preschedulerCapacity:e.preschedulerCapacity||65536,bypassLookaheadMs:e.bypassLookaheadMs??500,activityEvent:{maxLineLength:e.activityEvent?.maxLineLength??200,scsynthMaxLineLength:e.activityEvent?.scsynthMaxLineLength??null,oscInMaxLineLength:e.activityEvent?.oscInMaxLineLength??null,oscOutMaxLineLength:e.activityEvent?.oscOutMaxLineLength??null},debug:e.debug??!1,debugScsynth:e.debugScsynth??!1,debugOscIn:e.debugOscIn??!1,debugOscOut:e.debugOscOut??!1,activityConsoleLog:{maxLineLength:e.activityConsoleLog?.maxLineLength??200,scsynthMaxLineLength:e.activityConsoleLog?.scsynthMaxLineLength??null,oscInMaxLineLength:e.activityConsoleLog?.oscInMaxLineLength??null,oscOutMaxLineLength:e.activityConsoleLog?.oscOutMaxLineLength??null}},this.#c=e.sampleBaseURL||(t?`${t}samples/`:null),this.#u=e.synthdefBaseURL||(t?`${t}synthdefs/`:null),this.#p={maxRetries:e.fetchMaxRetries??3,baseDelay:e.fetchRetryDelay??1e3},this.#_=new K({onLoadingEvent:(c,l)=>this.#f.emit(c,l),maxRetries:this.#p.maxRetries,baseDelay:this.#p.baseDelay}),this.bootStats={initStartTime:null,initDuration:null}}get initialized(){return this.#d}get initializing(){return this.#m}get audioContext(){return this.#e}get mode(){return this.#i.mode}get bufferConstants(){return this.#y.bufferConstants}get ringBufferBase(){return this.#y.ringBufferBase}get sharedBuffer(){return this.#y.sharedBuffer}get node(){return this.#h}get osc(){return this.#n}get initTime(){return this.#E?.getNTPStartTime()??0}on(e,t){return this.#f.on(e,t)}off(e,t){return this.#f.off(e,t),this}once(e,t){return this.#f.once(e,t)}removeAllListeners(e){return this.#f.removeAllListeners(e),this}async init(){if(!this.#d)return this.#S?this.#S:(this.#S=this.#Y(),this.#S)}async#Y(){this.#m=!0,this.bootStats.initStartTime=performance.now();try{this.#W(),this.#V(),this.#I(),this.#q(),this.#D();let e=await this.#L();await this.#P(e),await this.#k(),await this.#F()}catch(e){throw this.#m=!1,this.#S=null,console.error("[SuperSonic] Initialization failed:",e),this.#f.emit("error",e),e}}getMetrics(){return this.#N()}getMetricsArray(){return this.#Q(),this.#y.getMergedArray()}getSnapshot(){let e=this.#N(),t=i.getMetricsSchema()?.metrics||{},s={};for(let[n,o]of Object.entries(e)){let a=t[n];a?.description?s[n]={value:o,description:a.description}:s[n]={value:o}}let r=null;return typeof performance<"u"&&performance.memory&&(r={usedJSHeapSize:performance.memory.usedJSHeapSize,totalJSHeapSize:performance.memory.totalJSHeapSize,jsHeapSizeLimit:performance.memory.jsHeapSizeLimit}),{timestamp:new Date().toISOString(),metrics:s,nodeTree:this.getRawTree(),memory:r}}setClockOffset(e){this.#T("set clock offset"),this.#E?.setClockOffset(e)}async recover(){return this.#d?await this.resume()?!0:await this.reload():!1}async resume(){if(!this.#d||!this.#e)return!1;await this.purge();try{await this.#e.resume()}catch{}this.#E?.startDriftTimer();let e=this.#v();if(e===null){let r=this.#e.state==="running";return r&&(this.#E?.resync(),this.#f.emit("resumed")),r}await new Promise(r=>setTimeout(r,200));let t=this.#v(),s=t!==null&&t>e;return s&&(this.#E?.resync(),this.#f.emit("resumed")),s}async suspend(){if(this.#d){this.#E?.stopDriftTimer();try{await this.#e?.suspend()}catch{}}}async reload(){if(!this.#d)return!1;this.#f.emit("reload:start");let e=new Map(this.loadedSynthDefs),t=this.#l?.getAllocatedBuffers()||[];await this.#G(),await this.#$();for(let[s,r]of e)try{await this.send("/d_recv",r)}catch(n){console.error(`[SuperSonic] Failed to restore synthdef ${s}:`,n)}for(let s of t)try{if(this.#i.mode==="postMessage"&&s.source)s.source.type==="file"&&await this.loadSample(s.bufnum,s.source.path,s.source.startFrame||0,s.source.numFrames||0);else{let r=crypto.randomUUID();await this.send("/b_allocPtr",s.bufnum,s.ptr,s.numFrames,s.numChannels,s.sampleRate,r)}}catch(r){console.error(`[SuperSonic] Failed to restore buffer ${s.bufnum}:`,r)}return(e.size>0||t.length>0)&&await this.sync(),this.#f.emit("reload:complete",{success:!0}),!0}async#G(){this.#E?.stopDriftTimer(),this.#o?.clear(),this.#o=null,this.#n&&(this.#n.cancelAll(),this.#n.dispose(),this.#n=null),this.#t&&(this.#t.disconnect(),this.#t=null),this.#e&&(await this.#e.close(),this.#e=null),this.#d=!1,this.loadedSynthDefs.clear(),this.#S=null,this.#B=null,this.#E?.reset()}async#$(){this.#m=!0,this.bootStats.initStartTime=performance.now();try{this.#I(),this.#l&&this.#l.updateAudioContext(this.#e),this.#D();let e=await this.#L();await this.#P(e),await this.#k(),await this.#F()}catch(e){throw this.#m=!1,this.#S=null,console.error("[SuperSonic] Partial init failed:",e),this.#f.emit("error",e),e}}getRawTree(){if(!this.#d)return{nodeCount:0,version:0,droppedCount:0,nodes:[]};let e=this.#y.bufferConstants;if(!e)return{nodeCount:0,version:0,droppedCount:0,nodes:[]};let t,s;if(this.#i.mode==="postMessage"){let r=this.#y.getSnapshotBuffer();if(!r)return{nodeCount:0,version:0,droppedCount:0,nodes:[]};t=r,s=e.METRICS_SIZE}else{let r=this.#y.sharedBuffer;if(!r)return{nodeCount:0,version:0,droppedCount:0,nodes:[]};t=r,s=this.#y.ringBufferBase+e.NODE_TREE_START}return ht(t,s,e)}getTree(){let e=this.getRawTree(),t=n=>({id:n.id,type:n.isGroup?"group":"synth",defName:n.defName,children:[]}),s=new Map;for(let n of e.nodes)s.set(n.id,t(n));let r=null;for(let n of e.nodes){let o=s.get(n.id);if(n.parentId===-1||n.parentId===0&&n.id===0)r=o;else{let a=s.get(n.parentId);a&&a.children.push(o)}}return{nodeCount:e.nodeCount,version:e.version,droppedCount:e.droppedCount,root:r||{id:0,type:"group",defName:"",children:[]}}}startCapture(){this.#T("start capture"),this.#A.start()}stopCapture(){return this.#T("stop capture"),this.#A.stop()}isCaptureEnabled(){return this.#A.isEnabled()}getCaptureFrames(){return this.#A.getFrameCount()}getMaxCaptureDuration(){return this.#A.getMaxDuration()}send(e,...t){this.#T("send OSC messages");let s={"/d_load":"Use loadSynthDef() or send /d_recv with synthdef bytes instead.","/d_loadDir":"Use loadSynthDef() or send /d_recv with synthdef bytes instead.","/b_read":"Use loadSample() to load audio into a buffer.","/b_readChannel":"Use loadSample() to load audio into a buffer.","/b_write":"Writing audio files is not available in the browser.","/b_close":"Writing audio files is not available in the browser.","/clearSched":"Use purge() to clear both the JS prescheduler and WASM scheduler.","/error":"SuperSonic always enables error notifications so you never miss a /fail message."};if(s[e])throw new Error(`${e} is not supported in SuperSonic. ${s[e]}`);if(e==="/d_recv"){let o=t[0];if(o instanceof Uint8Array||o instanceof ArrayBuffer){let a=o instanceof ArrayBuffer?new Uint8Array(o):o,c=F(a)||"unknown";this.loadedSynthDefs.set(c,a)}}if(e==="/d_free")for(let o of t)typeof o=="string"&&this.loadedSynthDefs.delete(o);else e==="/d_freeAll"&&this.loadedSynthDefs.clear();let r=t.map(o=>o instanceof ArrayBuffer?new Uint8Array(o):o);if(this.#i.debug||this.#i.debugOscOut){let o=this.#i.activityConsoleLog.oscOutMaxLineLength??this.#i.activityConsoleLog.maxLineLength,a=t.map(c=>{if(c instanceof Uint8Array||c instanceof ArrayBuffer)return`<${c.byteLength||c.length} bytes>`;let l=JSON.stringify(c);return l.length>o?l.slice(0,o)+"...":l}).join(", ");console.log(`[OSC \u2192] ${e}${a?" "+a:""}`)}if(rr.has(e)){this.#ee(e,r),this.#te(e,r);return}let n=i.osc.encodeMessage(e,r);this.sendOSC(n)}sendOSC(e,t={}){this.#T("send OSC data");let s=this.#J(e);this.#H(s,t)}cancelTag(e){this.#T("cancel by tag"),this.#n.cancelTag(e)}cancelSession(e){this.#T("cancel by session"),this.#n.cancelSession(e)}cancelSessionTag(e,t){this.#T("cancel by session and tag"),this.#n.cancelSessionTag(e,t)}cancelAll(){this.#T("cancel all scheduled"),this.#n.cancelAll()}async purge(){this.#T("purge");let e=this.#n.cancelAllWithAck(),t=new Promise(s=>{let r=n=>{n.data.type==="clearSchedAck"&&(this.#t.port.removeEventListener("message",r),s())};this.#t.port.addEventListener("message",r),this.#t.port.postMessage({type:"clearSched",ack:!0})});await Promise.all([e,t])}createOscChannel(e={}){return this.#T("create OSC channel"),this.#n.createOscChannel(e)}async loadSynthDef(e){this.#T("load synthdef");let t,s;if(typeof e=="string"){let r;if(this.#j(e))r=e;else{if(!this.#u)throw new Error("synthdefBaseURL not configured.");r=`${this.#u}${e}.scsyndef`}let n=F(r),o=await this.#_.fetch(r,{type:"synthdef",name:n});t=new Uint8Array(o),s=F(t)||n}else if(e instanceof ArrayBuffer||ArrayBuffer.isView(e)){if(t=e instanceof ArrayBuffer?new Uint8Array(e):new Uint8Array(e.buffer,e.byteOffset,e.byteLength),s=F(t),!s)throw new Error("Could not extract synthdef name from binary data. Make sure it's a valid .scsyndef file.")}else if(e instanceof Blob){let r=await e.arrayBuffer();if(t=new Uint8Array(r),s=F(t),!s)throw new Error("Could not extract synthdef name from file. Make sure it's a valid .scsyndef file.")}else throw new Error("loadSynthDef source must be a name, path/URL string, ArrayBuffer, Uint8Array, or File/Blob");return await this.send("/d_recv",t),{name:s,size:t.length}}async loadSynthDefs(e){this.#T("load synthdefs");let t={};return await Promise.all(e.map(async s=>{try{await this.loadSynthDef(s),t[s]={success:!0}}catch(r){t[s]={success:!1,error:r.message}}})),t}async loadSample(e,t,s=0,r=0){this.#T("load samples");let n;if(typeof t=="string")n=await this.#l.prepareFromFile({bufnum:e,path:t,startFrame:s,numFrames:r});else if(t instanceof ArrayBuffer||ArrayBuffer.isView(t))n=await this.#l.prepareFromBlob({bufnum:e,blob:t,startFrame:s,numFrames:r});else if(t instanceof Blob){let l=await t.arrayBuffer();n=await this.#l.prepareFromBlob({bufnum:e,blob:l,startFrame:s,numFrames:r})}else throw new Error("loadSample source must be a path/URL string, ArrayBuffer, TypedArray, or File/Blob");await this.send("/b_allocPtr",e,n.ptr,n.numFrames,n.numChannels,n.sampleRate,n.uuid),await n.allocationComplete;let{numFrames:o,numChannels:a,sampleRate:c}=n;return{bufnum:e,hash:n.hash,source:typeof t=="string"?t:null,numFrames:o,numChannels:a,sampleRate:c,duration:c>0?o/c:0}}getLoadedBuffers(){return this.#T("get loaded buffers"),(this.#l?.getAllocatedBuffers()||[]).map(({bufnum:t,numFrames:s,numChannels:r,sampleRate:n,source:o,hash:a})=>({bufnum:t,hash:a||null,source:o?.path||o?.name||null,numFrames:s,numChannels:r,sampleRate:n,duration:n>0?s/n:0}))}async sampleInfo(e,t=0,s=0){this.#T("get sample info");let r;if(typeof e=="string")r=e;else if(e instanceof ArrayBuffer||ArrayBuffer.isView(e))r=e;else if(e instanceof Blob)r=await e.arrayBuffer();else throw new Error("sampleInfo source must be a path/URL string, ArrayBuffer, TypedArray, or File/Blob");return this.#l.sampleInfo({source:r,startFrame:t,numFrames:s})}async sync(e=Math.floor(Math.random()*2147483647)){this.#T("sync"),await this.#se();let t=new Promise((s,r)=>{let n=setTimeout(()=>{this.#o?.delete(e),r(new Error("Timeout waiting for /synced response"))},1e4),o=()=>{clearTimeout(n),this.#o.delete(e),s()};this.#o||(this.#o=new Map),this.#o.set(e,o)});this.send("/sync",e),await t,this.#i.mode==="postMessage"&&await new Promise(s=>setTimeout(s,this.#i.snapshotIntervalMs*2))}getInfo(){return this.#T("get info"),{sampleRate:this.#e.sampleRate,numBuffers:this.#i.worldOptions.numBuffers,totalMemory:this.#i.memory.totalMemory,wasmHeapSize:this.#i.memory.wasmHeapSize,bufferPoolSize:this.#i.memory.bufferPoolSize,bootTimeMs:this.bootStats.initDuration,capabilities:{...this.#b},version:this.#g}}async shutdown(){!this.#d&&!this.#m||(this.#f.emit("shutdown"),this.#E?.stopDriftTimer(),this.#o?.clear(),this.#o=null,this.#n&&(this.#n.cancelAll(),this.#n.dispose(),this.#n=null),this.#t&&(this.#t.disconnect(),this.#t=null),this.#e&&(await this.#e.close(),this.#e=null),this.#l&&(this.#l.destroy(),this.#l=null),this.#a=null,this.#B=null,this.#C=Promise.resolve(),this.#d=!1,this.loadedSynthDefs.clear(),this.#S=null,this.#s=null,this.#E?.reset(),this.bootStats={initStartTime:null,initDuration:null})}async destroy(){this.#f.emit("destroy"),await this.shutdown(),this.#M=null,this.#f.clearAllListeners()}async reset(){await this.shutdown(),await this.init()}#W(){this.#b={audioWorklet:typeof AudioWorklet<"u",sharedArrayBuffer:typeof SharedArrayBuffer<"u",crossOriginIsolated:window.crossOriginIsolated===!0,atomics:typeof Atomics<"u",webWorker:typeof Worker<"u"};let e=this.#i.mode,t=["audioWorklet","webWorker"];e==="sab"&&t.push("sharedArrayBuffer","crossOriginIsolated","atomics");let s=t.filter(r=>!this.#b[r]);if(s.length>0){let r=new Error(`Missing required features for ${e} mode: ${s.join(", ")}`);throw e==="sab"&&!this.#b.crossOriginIsolated&&(r.message+=`
|
|
18
18
|
|
|
19
|
-
Consider using mode: 'postMessage' which doesn't require COOP/COEP headers.`),r}if(e!=="sab"&&e!=="postMessage")throw new Error(`Invalid mode: '${e}'. Use 'sab' or 'postMessage'.`)}#V(){let e=this.#i.memory;this.#i.mode==="sab"?this.#s=new WebAssembly.Memory({initial:e.totalPages,maximum:e.totalPages,shared:!0}):this.#s=null}#
|
|
19
|
+
Consider using mode: 'postMessage' which doesn't require COOP/COEP headers.`),r}if(e!=="sab"&&e!=="postMessage")throw new Error(`Invalid mode: '${e}'. Use 'sab' or 'postMessage'.`)}#V(){let e=this.#i.memory;this.#i.mode==="sab"?this.#s=new WebAssembly.Memory({initial:e.totalPages,maximum:e.totalPages,shared:!0}):this.#s=null}#I(){this.#i.audioContext?this.#e=this.#i.audioContext:this.#e=new AudioContext(this.#i.audioContextOptions),this.#e.addEventListener("statechange",()=>{let e=this.#e?.state;if(!e)return;let t=this.#w;this.#w=e,e==="running"&&(t==="suspended"||t==="interrupted")&&this.#E?.resync(),this.#f.emit("audiocontext:statechange",{state:e}),e==="suspended"?this.#f.emit("audiocontext:suspended"):e==="running"?this.#f.emit("audiocontext:resumed"):e==="interrupted"&&this.#f.emit("audiocontext:interrupted")})}#q(){let e=this.#i.mode==="sab"?this.#s.buffer:null;this.#l=new X({mode:this.#i.mode,audioContext:this.#e,sharedBuffer:e,bufferPoolConfig:{start:this.#i.memory.bufferPoolOffset,size:this.#i.memory.bufferPoolSize},sampleBaseURL:this.#c,maxBuffers:this.#i.worldOptions.numBuffers,assetLoader:this.#_})}#D(){this.#a=new Q({bufferManager:this.#l,getDefaultSampleRate:()=>this.#e?.sampleRate||44100})}async#L(){if(this.#M)return this.#M;let e=this.#i.wasmUrl.split("/").pop();this.#f.emit("loading:start",{type:"wasm",name:e});let t=await fetch(this.#i.wasmUrl);if(!t.ok)throw new Error(`Failed to load WASM: ${t.status} ${t.statusText}`);let s=await t.arrayBuffer();return this.#f.emit("loading:complete",{type:"wasm",name:e,size:s.byteLength}),this.#M=s,s}async#P(e){await Ye(this.#e.audioWorklet,this.#i.workletUrl);let t=this.#i.worldOptions.numOutputBusChannels;if(this.#t=new AudioWorkletNode(this.#e,"scsynth-processor",{numberOfInputs:1,numberOfOutputs:1,outputChannelCount:[t]}),this.#i.autoConnect){let o=this.#e.destination;t>2&&(o.channelCount=Math.min(t,o.maxChannelCount),o.channelInterpretation="discrete"),this.#t.connect(o)}this.#h=this.#Z(),this.#t.port.start(),this.#K();let s=this.#i.mode,r=s==="sab"?this.#s.buffer:null;this.#t.port.postMessage({type:"init",mode:s,sharedBuffer:r,snapshotIntervalMs:this.#i.snapshotIntervalMs});let n={type:"loadWasm",wasmBytes:e,worldOptions:this.#i.worldOptions,sampleRate:this.#e.sampleRate};s==="sab"?n.wasmMemory=this.#s:n.memoryPages=this.#i.memoryPages||1280,this.#t.port.postMessage(n),await this.#X(),this.#l.setWorkletPort(this.#t.port)}#Z(){let e=this.#t;return Object.freeze({connect:(...t)=>e.connect(...t),disconnect:(...t)=>e.disconnect(...t),get context(){return e.context},get numberOfOutputs(){return e.numberOfOutputs},get numberOfInputs(){return e.numberOfInputs},get channelCount(){return e.channelCount},get input(){return e}})}async#k(){let e=this.#i.mode,t=this.#y.bufferConstants,s=this.#y.ringBufferBase,r=this.#y.sharedBuffer,n={workerBaseURL:this.#i.workerBaseURL,preschedulerCapacity:this.#i.preschedulerCapacity,snapshotIntervalMs:this.#i.snapshotIntervalMs,bypassLookaheadS:this.#i.bypassLookaheadMs/1e3,getAudioContextTime:()=>this.#e?.currentTime??0,getNTPStartTime:()=>this.#E?.getNTPStartTime()??0};if(e==="sab"&&(n.sharedBuffer=r,n.ringBufferBase=s,n.bufferConstants=t),this.#n=Xe(e,n),this.#n.onReply((o,a,c)=>{let l=ue(o)||null;this.#f.emit("message:raw",{oscData:o,sequence:a,timestamp:c,scheduledTime:l});try{let u=$(o),f=u[0],h=u.slice(1);if(f==="/supersonic/buffer/freed")this.#l?.handleBufferFreed(h);else if(f==="/supersonic/buffer/allocated")this.#l?.handleBufferAllocated(h);else if(f==="/synced"&&h.length>0){let S=h[0];this.#o?.has(S)&&this.#o.get(S)(u)}if(this.#f.emit("message",u),this.#i.debug||this.#i.debugOscIn){let S=this.#i.activityConsoleLog.oscInMaxLineLength??this.#i.activityConsoleLog.maxLineLength,m=h.map(g=>{let p=JSON.stringify(g);return p.length>S?p.slice(0,S)+"...":p}).join(", ")||"";console.log(`[\u2190 OSC] ${f}${m?" "+m:""}`)}}catch(u){console.error("[SuperSonic] Failed to decode OSC message:",u)}}),this.#n.onDebug(o=>{let a=this.#i.activityEvent.scsynthMaxLineLength??this.#i.activityEvent.maxLineLength;if(a>0&&o.text?.length>a&&(o={...o,text:o.text.slice(0,a)+"..."}),this.#f.emit("debug",o),this.#i.debug||this.#i.debugScsynth){let c=this.#i.activityConsoleLog.scsynthMaxLineLength??this.#i.activityConsoleLog.maxLineLength,l=o.text.length>c?o.text.slice(0,c)+"...":o.text;console.log(`[synth] ${l}`)}}),this.#n.onError((o,a)=>{console.error(`[SuperSonic] ${a} error:`,o),this.#f.emit("error",new Error(`${a}: ${o}`))}),this.#n.onOscLog(o=>{for(let a of o){let c=ue(a.oscData)||null;this.#f.emit("message:sent",{oscData:a.oscData,sourceId:a.sourceId,sequence:a.sequence,timestamp:a.timestamp,scheduledTime:c})}}),e==="sab")await this.#n.initialize();else{if(await this.#n.initialize(this.#t.port),this.#n.setBufferConstants(t),this.#O?.length>0)for(let o of this.#O)this.#n.handleDebugRaw(o);this.#U=o=>this.#n.handleDebugRaw(o),this.#O=[]}this.#B=this.#n.createOscChannel({sourceId:0})}async#F(){this.#d=!0,this.#m=!1,this.bootStats.initDuration=performance.now()-this.bootStats.initStartTime,await this.#f.emitAsync("setup"),this.#f.emit("ready",{capabilities:this.#b,bootStats:this.bootStats})}#X(){return new Promise((e,t)=>{let s=setTimeout(()=>{t(new Error("AudioWorklet initialization timeout"))},5e3),r=async n=>{if(n.data.type==="error"){clearTimeout(s),this.#t.port.removeEventListener("message",r),t(new Error(n.data.error||"AudioWorklet error"));return}if(n.data.type==="initialized")if(clearTimeout(s),this.#t.port.removeEventListener("message",r),n.data.success){let o=n.data.ringBufferBase??0,a=n.data.bufferConstants,c=this.#i.mode==="sab"?this.#s.buffer:null;this.#y.initSharedViews(c,o,a);let l=this.#i.worldOptions?.maxNodes??1024,u=a?.NODE_TREE_MIRROR_MAX_NODES??1024;l>u&&console.warn(`SuperSonic: maxNodes (${l}) exceeds NODE_TREE_MIRROR_MAX_NODES (${u}). The node tree mirror will not show all nodes. Rebuild with NODE_TREE_MIRROR_MAX_NODES=${l} to fix.`),this.#E=new te({mode:this.#i.mode,audioContext:this.#e,workletPort:this.#t.port}),this.#E.initSharedViews(c,o,a),await this.#E.initialize(),this.#E.startDriftTimer(),this.#i.mode==="sab"&&this.#A.update(c,o,a),this.#i.mode==="postMessage"&&n.data.initialSnapshot&&this.#y.updateSnapshot(n.data.initialSnapshot),e()}else t(new Error(n.data.error||"AudioWorklet initialization failed"))};this.#t.port.addEventListener("message",r),this.#t.port.start()})}#K(){this.#t.port.addEventListener("message",e=>{let{data:t}=e;switch(t.type){case"error":console.error("[Worklet] Error:",t.error),this.#f.emit("error",new Error(t.error));break;case"version":this.#g=t.version;break;case"snapshot":t.buffer&&(this.#y.updateSnapshot(t.buffer),this.#R=t.snapshotsSent);break;case"debugRawBatch":this.#U?this.#U(t):this.#O.push(t);break;case"oscLog":t.entries&&this.#n?.handleOscLog&&this.#n.handleOscLog(t.entries);break}})}#x(){return{preschedulerMetrics:this.#n?.getPreschedulerMetrics(),transportMetrics:this.#n?.getMetrics(),driftOffsetMs:this.#E?.getDriftOffset()??0,ntpStartTime:this.#E?.getNTPStartTime()??0,clockOffsetMs:this.#E?.getClockOffset()??0,audioContextState:this.#e?.state||"unknown",bufferPoolStats:this.#l?.getStats(),loadedSynthDefsCount:this.loadedSynthDefs?.size||0,preschedulerCapacity:this.#i.preschedulerCapacity}}#N(){return this.#y.gatherMetrics(this.#x())}#Q(){this.#y.updateMergedArray(this.#x())}#v(){if(this.#i.mode==="sab"){let t=this.#y.getMetricsView();return t?t[0]:null}let e=this.#y.getSnapshotBuffer();return e?new Uint32Array(e,0,1)[0]:null}#T(e="perform this operation"){if(!this.#d)throw new Error(`SuperSonic not initialized. Call init() before attempting to ${e}.`)}#re(e){let s={nonBundle:"bypassNonBundle",immediate:"bypassImmediate",nearFuture:"bypassNearFuture",late:"bypassLate"}[e];s&&this.#y.addMetric(s)}#j(e){return e.includes("/")||e.includes("://")}#J(e){if(e instanceof Uint8Array)return e;if(e instanceof ArrayBuffer)return new Uint8Array(e);throw new Error("oscData must be ArrayBuffer or Uint8Array")}#H(e,t={}){let s=this.#B.classify(e);if(q(s))this.#i.mode==="sab"?this.#B.send(e):this.#n.sendImmediate(e,s);else{let r=this.#y.bufferConstants?.scheduler_slot_size;if(r&&e.length>r)throw new Error(`OSC bundle too large to schedule (${e.length} > ${r} bytes). Use immediate timestamp (0 or 1) for large messages, or reduce bundle size.`);this.#n.sendWithOptions(e,t)}}#ee(e,t){let s=(o,a)=>{let c=t[o];if(!Number.isFinite(c))throw new Error(a)},r=(o,a)=>{if(typeof t[o]!="string")throw new Error(a)},n=(o,a)=>{let c=t[o];if(!(c instanceof Uint8Array||c instanceof ArrayBuffer))throw new Error(a)};switch(e){case"/b_alloc":s(0,"/b_alloc requires a buffer number"),s(1,"/b_alloc requires a frame count");break;case"/b_allocRead":s(0,"/b_allocRead requires a buffer number"),r(1,"/b_allocRead requires a file path");break;case"/b_allocReadChannel":s(0,"/b_allocReadChannel requires a buffer number"),r(1,"/b_allocReadChannel requires a file path");break;case"/b_allocFile":s(0,"/b_allocFile requires a buffer number"),n(1,"/b_allocFile requires audio file data as blob");break}}#te(e,t){this.#C=this.#C.then(async()=>{let s=[e,...t],{packet:r}=await this.#a.rewritePacket(s),n=i.osc.encodeMessage(r[0],r.slice(1));this.#H(n)}).catch(s=>{console.error(`[SuperSonic] Buffer command ${e} failed:`,s),this.#f.emit("error",s)})}#se(){return this.#C}};export{A as OscChannel,Ct as SuperSonic,Bt as osc};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "supersonic-scsynth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.53.0",
|
|
4
4
|
"description": "SuperCollider scsynth WebAssembly port for AudioWorklet - Run SuperCollider synthesis in the browser",
|
|
5
5
|
"main": "dist/supersonic.js",
|
|
6
6
|
"types": "supersonic.d.ts",
|
|
@@ -14,7 +14,13 @@
|
|
|
14
14
|
"dev": "cd example && npx serve",
|
|
15
15
|
"test": "playwright test --reporter=list --max-failures=1",
|
|
16
16
|
"test:all": "playwright test --reporter=list",
|
|
17
|
-
"prepublishOnly": "./build.sh --release"
|
|
17
|
+
"prepublishOnly": "./build.sh --release",
|
|
18
|
+
"test:types": "tsd"
|
|
19
|
+
},
|
|
20
|
+
"tsd": {
|
|
21
|
+
"compilerOptions": {
|
|
22
|
+
"module": "esnext"
|
|
23
|
+
}
|
|
18
24
|
},
|
|
19
25
|
"repository": {
|
|
20
26
|
"type": "git",
|
|
@@ -63,7 +69,8 @@
|
|
|
63
69
|
},
|
|
64
70
|
"devDependencies": {
|
|
65
71
|
"@playwright/test": "^1.49.0",
|
|
66
|
-
"esbuild": "^0.24.0"
|
|
72
|
+
"esbuild": "^0.24.0",
|
|
73
|
+
"tsd": "^0.33.0"
|
|
67
74
|
},
|
|
68
75
|
"engines": {
|
|
69
76
|
"node": ">=18.0.0"
|
package/supersonic.d.ts
CHANGED
|
@@ -579,22 +579,34 @@ export interface Snapshot {
|
|
|
579
579
|
} | null;
|
|
580
580
|
}
|
|
581
581
|
|
|
582
|
-
/**
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
582
|
+
/**
|
|
583
|
+
* Metadata about decoded audio content.
|
|
584
|
+
*
|
|
585
|
+
* Returned by {@link SuperSonic.sampleInfo}. Also the shape of each entry
|
|
586
|
+
* in {@link SuperSonic.getLoadedBuffers} (with `bufnum`) and the return
|
|
587
|
+
* value of {@link SuperSonic.loadSample} (with `bufnum`).
|
|
588
|
+
*/
|
|
589
|
+
export interface SampleInfo {
|
|
590
|
+
/** SHA-256 hex hash of the decoded interleaved audio content. */
|
|
591
|
+
hash: string;
|
|
592
|
+
/** Original source path/URL, or null for inline data. */
|
|
593
|
+
source: string | null;
|
|
586
594
|
/** Number of sample frames. */
|
|
587
595
|
numFrames: number;
|
|
588
596
|
/** Number of channels. */
|
|
589
597
|
numChannels: number;
|
|
590
598
|
/** Sample rate in Hz. */
|
|
591
599
|
sampleRate: number;
|
|
592
|
-
/** Original source path/URL, or null. */
|
|
593
|
-
source: string | null;
|
|
594
600
|
/** Duration in seconds. */
|
|
595
601
|
duration: number;
|
|
596
602
|
}
|
|
597
603
|
|
|
604
|
+
/** Info about a loaded audio buffer, returned by {@link SuperSonic.getLoadedBuffers}. */
|
|
605
|
+
export interface LoadedBufferInfo extends SampleInfo {
|
|
606
|
+
/** Buffer slot number. */
|
|
607
|
+
bufnum: number;
|
|
608
|
+
}
|
|
609
|
+
|
|
598
610
|
/** Result from {@link SuperSonic.loadSynthDef}. */
|
|
599
611
|
export interface LoadSynthDefResult {
|
|
600
612
|
/** Extracted SynthDef name. */
|
|
@@ -604,15 +616,9 @@ export interface LoadSynthDefResult {
|
|
|
604
616
|
}
|
|
605
617
|
|
|
606
618
|
/** Result from {@link SuperSonic.loadSample}. */
|
|
607
|
-
export interface LoadSampleResult {
|
|
619
|
+
export interface LoadSampleResult extends SampleInfo {
|
|
608
620
|
/** Buffer slot the sample was loaded into. */
|
|
609
621
|
bufnum: number;
|
|
610
|
-
/** Number of sample frames loaded. */
|
|
611
|
-
numFrames: number;
|
|
612
|
-
/** Number of channels. */
|
|
613
|
-
numChannels: number;
|
|
614
|
-
/** Sample rate in Hz. */
|
|
615
|
-
sampleRate: number;
|
|
616
622
|
}
|
|
617
623
|
|
|
618
624
|
/** Boot timing statistics. */
|
|
@@ -953,6 +959,20 @@ export declare const osc: {
|
|
|
953
959
|
NTP_EPOCH_OFFSET: number;
|
|
954
960
|
};
|
|
955
961
|
|
|
962
|
+
// ============================================================================
|
|
963
|
+
// OSC Command Types
|
|
964
|
+
// ============================================================================
|
|
965
|
+
|
|
966
|
+
/** Node add action: 0=head, 1=tail, 2=before, 3=after, 4=replace */
|
|
967
|
+
export type AddAction = 0 | 1 | 2 | 3 | 4;
|
|
968
|
+
|
|
969
|
+
/** Commands blocked at runtime — typed as compile-time errors */
|
|
970
|
+
export type BlockedCommand =
|
|
971
|
+
| '/d_load' | '/d_loadDir'
|
|
972
|
+
| '/b_read' | '/b_readChannel'
|
|
973
|
+
| '/b_write' | '/b_close'
|
|
974
|
+
| '/clearSched' | '/error';
|
|
975
|
+
|
|
956
976
|
// ============================================================================
|
|
957
977
|
// SuperSonic
|
|
958
978
|
// ============================================================================
|
|
@@ -1268,6 +1288,162 @@ export class SuperSonic {
|
|
|
1268
1288
|
* sonic.send('/d_load', 'beep');
|
|
1269
1289
|
* // Error: /d_load is not supported. Use loadSynthDef() or send /d_recv instead.
|
|
1270
1290
|
*/
|
|
1291
|
+
|
|
1292
|
+
// ── Blocked commands ─────────────────────────────────────────────────
|
|
1293
|
+
// These throw at runtime. Typed as `never` with deprecation hints.
|
|
1294
|
+
|
|
1295
|
+
/** @deprecated Use loadSynthDef() or send('/d_recv', bytes) instead. Filesystem access is not available in the browser. */
|
|
1296
|
+
send(address: '/d_load', ...args: OscArg[]): never;
|
|
1297
|
+
/** @deprecated Use loadSynthDef() or send('/d_recv', bytes) instead. Filesystem access is not available in the browser. */
|
|
1298
|
+
send(address: '/d_loadDir', ...args: OscArg[]): never;
|
|
1299
|
+
/** @deprecated Use loadSample() instead. Filesystem access is not available in the browser. */
|
|
1300
|
+
send(address: '/b_read', ...args: OscArg[]): never;
|
|
1301
|
+
/** @deprecated Use loadSample() instead. Filesystem access is not available in the browser. */
|
|
1302
|
+
send(address: '/b_readChannel', ...args: OscArg[]): never;
|
|
1303
|
+
/** @deprecated File writing is not available in the browser. */
|
|
1304
|
+
send(address: '/b_write', ...args: OscArg[]): never;
|
|
1305
|
+
/** @deprecated File writing is not available in the browser. */
|
|
1306
|
+
send(address: '/b_close', ...args: OscArg[]): never;
|
|
1307
|
+
/** @deprecated Use purge() to clear both the JS prescheduler and WASM scheduler. */
|
|
1308
|
+
send(address: '/clearSched', ...args: OscArg[]): never;
|
|
1309
|
+
/** @deprecated SuperSonic always enables error notifications so you never miss a /fail reply. */
|
|
1310
|
+
send(address: '/error', ...args: OscArg[]): never;
|
|
1311
|
+
|
|
1312
|
+
// ── Top-level commands ─────────────────────────────────────────────
|
|
1313
|
+
|
|
1314
|
+
/** Query server status. Replies with `/status.reply`: unused, numUGens, numSynths, numGroups, numSynthDefs, avgCPU%, peakCPU%, nominalSampleRate, actualSampleRate. */
|
|
1315
|
+
send(address: '/status'): void;
|
|
1316
|
+
/** Query server version. Replies with `/version.reply`: programName, majorVersion, minorVersion, patchName, gitBranch, commitHash. */
|
|
1317
|
+
send(address: '/version'): void;
|
|
1318
|
+
/** Register (1) or unregister (0) for server notifications (`/n_go`, `/n_end`, `/n_on`, `/n_off`, `/n_move`). Replies with `/done /notify clientID`. */
|
|
1319
|
+
send(address: '/notify', flag: 0 | 1, clientID?: number): void;
|
|
1320
|
+
/** Enable/disable OSC message dumping to debug output. 0=off, 1=parsed, 2=hex, 3=both. */
|
|
1321
|
+
send(address: '/dumpOSC', flag: 0 | 1 | 2 | 3): void;
|
|
1322
|
+
/** Async. Wait for all prior async commands to complete. Replies with `/synced syncID`. */
|
|
1323
|
+
send(address: '/sync', syncID: number): void;
|
|
1324
|
+
/** Query realtime memory usage. Replies with `/rtMemoryStatus.reply`: freeBytes, largestFreeBlockBytes. */
|
|
1325
|
+
send(address: '/rtMemoryStatus'): void;
|
|
1326
|
+
|
|
1327
|
+
// ── SynthDef commands ──────────────────────────────────────────────
|
|
1328
|
+
|
|
1329
|
+
/** Async. Load a compiled synthdef from bytes. Optional completionMessage is an encoded OSC message executed after loading. Replies with `/done /d_recv`. */
|
|
1330
|
+
send(address: '/d_recv', bytes: Uint8Array | ArrayBuffer, completionMessage?: Uint8Array | ArrayBuffer): void;
|
|
1331
|
+
/** Free one or more loaded synthdefs by name. */
|
|
1332
|
+
send(address: '/d_free', ...names: [string, ...string[]]): void;
|
|
1333
|
+
/** Free all loaded synthdefs. Not in the official SC reference but supported by scsynth. */
|
|
1334
|
+
send(address: '/d_freeAll'): void;
|
|
1335
|
+
|
|
1336
|
+
// ── Synth commands ─────────────────────────────────────────────────
|
|
1337
|
+
|
|
1338
|
+
/** Create a new synth from a loaded synthdef. addAction: 0=head, 1=tail, 2=before, 3=after, 4=replace. Controls are alternating name/index and value pairs. Values can be numbers or bus mapping strings like `"c0"` (control bus 0) or `"a0"` (audio bus 0). Use nodeID=-1 for auto-assign. */
|
|
1339
|
+
send(address: '/s_new', defName: string, nodeID: number, addAction: AddAction, targetID: number, ...controls: (string | number)[]): void;
|
|
1340
|
+
/** Get synth control values. Controls can be indices or names. Replies with `/n_set nodeID control value ...`. */
|
|
1341
|
+
send(address: '/s_get', nodeID: number, ...controls: (string | number)[]): void;
|
|
1342
|
+
/** Get sequential synth control values. Control can be an index or name. Replies with `/n_setn nodeID control count values...`. For multiple ranges, use the catch-all overload. */
|
|
1343
|
+
send(address: '/s_getn', nodeID: number, control: number | string, count: number): void;
|
|
1344
|
+
/** Release client-side synth ID tracking. Synths continue running but are reassigned to reserved negative IDs. Use when you no longer need to communicate with the synth and want to reuse the ID. */
|
|
1345
|
+
send(address: '/s_noid', ...nodeIDs: [number, ...number[]]): void;
|
|
1346
|
+
|
|
1347
|
+
// ── Node commands ──────────────────────────────────────────────────
|
|
1348
|
+
|
|
1349
|
+
/** Free (delete) one or more nodes. */
|
|
1350
|
+
send(address: '/n_free', ...nodeIDs: [number, ...number[]]): void;
|
|
1351
|
+
/** Set node control values. Controls are alternating name/index and value pairs. If the node is a group, sets the control on all nodes in the group. */
|
|
1352
|
+
send(address: '/n_set', nodeID: number, ...controls: (string | number)[]): void;
|
|
1353
|
+
/** Set sequential control values starting at the given control index/name. For multiple ranges, use the catch-all overload. */
|
|
1354
|
+
send(address: '/n_setn', nodeID: number, control: number | string, count: number, ...values: number[]): void;
|
|
1355
|
+
/** Fill sequential controls with a single value. For multiple ranges, use the catch-all overload. */
|
|
1356
|
+
send(address: '/n_fill', nodeID: number, control: number | string, count: number, value: number): void;
|
|
1357
|
+
/** Turn nodes on (1) or off (0). Args are repeating [nodeID, flag] pairs. */
|
|
1358
|
+
send(address: '/n_run', ...pairs: [number, 0 | 1, ...(number | 0 | 1)[]]): void;
|
|
1359
|
+
/** Move nodeA to execute immediately before nodeB. Args are repeating [nodeA, nodeB] pairs. */
|
|
1360
|
+
send(address: '/n_before', ...pairs: [number, number, ...number[]]): void;
|
|
1361
|
+
/** Move nodeA to execute immediately after nodeB. Args are repeating [nodeA, nodeB] pairs. */
|
|
1362
|
+
send(address: '/n_after', ...pairs: [number, number, ...number[]]): void;
|
|
1363
|
+
/** Reorder nodes within a group. addAction: 0=head, 1=tail, 2=before target, 3=after target. Does not support 4 (replace). */
|
|
1364
|
+
send(address: '/n_order', addAction: 0 | 1 | 2 | 3, targetID: number, ...nodeIDs: [number, ...number[]]): void;
|
|
1365
|
+
/** Query node info. Replies with `/n_info` for each node: nodeID, parentGroupID, prevNodeID, nextNodeID, isGroup, [headNodeID, tailNodeID]. */
|
|
1366
|
+
send(address: '/n_query', ...nodeIDs: [number, ...number[]]): void;
|
|
1367
|
+
/** Print control values and calculation rates for each node to debug output. No reply message. */
|
|
1368
|
+
send(address: '/n_trace', ...nodeIDs: [number, ...number[]]): void;
|
|
1369
|
+
/** Map controls to read from control buses. Mappings are repeating [control, busIndex] pairs. Set busIndex to -1 to unmap. */
|
|
1370
|
+
send(address: '/n_map', nodeID: number, ...mappings: (string | number)[]): void;
|
|
1371
|
+
/** Map a range of sequential controls to sequential control buses. Mappings are repeating [control, busIndex, count] triplets. */
|
|
1372
|
+
send(address: '/n_mapn', nodeID: number, ...mappings: (string | number)[]): void;
|
|
1373
|
+
/** Map controls to read from audio buses. Mappings are repeating [control, busIndex] pairs. Set busIndex to -1 to unmap. */
|
|
1374
|
+
send(address: '/n_mapa', nodeID: number, ...mappings: (string | number)[]): void;
|
|
1375
|
+
/** Map a range of sequential controls to sequential audio buses. Mappings are repeating [control, busIndex, count] triplets. */
|
|
1376
|
+
send(address: '/n_mapan', nodeID: number, ...mappings: (string | number)[]): void;
|
|
1377
|
+
|
|
1378
|
+
// ── Group commands ─────────────────────────────────────────────────
|
|
1379
|
+
|
|
1380
|
+
/** Create new groups. Args are repeating [groupID, addAction, targetID] triplets. addAction: 0=head, 1=tail, 2=before, 3=after, 4=replace. */
|
|
1381
|
+
send(address: '/g_new', ...args: [number, AddAction, number, ...(number | AddAction)[]]): void;
|
|
1382
|
+
/** Create new parallel groups (children evaluated in unspecified order). Same signature as /g_new. */
|
|
1383
|
+
send(address: '/p_new', ...args: [number, AddAction, number, ...(number | AddAction)[]]): void;
|
|
1384
|
+
/** Free all immediate children of one or more groups (groups themselves remain). */
|
|
1385
|
+
send(address: '/g_freeAll', ...groupIDs: [number, ...number[]]): void;
|
|
1386
|
+
/** Recursively free all synths inside one or more groups and their nested sub-groups. */
|
|
1387
|
+
send(address: '/g_deepFree', ...groupIDs: [number, ...number[]]): void;
|
|
1388
|
+
/** Move node to head of group. Args are repeating [groupID, nodeID] pairs. */
|
|
1389
|
+
send(address: '/g_head', ...pairs: [number, number, ...number[]]): void;
|
|
1390
|
+
/** Move node to tail of group. Args are repeating [groupID, nodeID] pairs. */
|
|
1391
|
+
send(address: '/g_tail', ...pairs: [number, number, ...number[]]): void;
|
|
1392
|
+
/** Print group's node tree to debug output. Args are repeating [groupID, flag] pairs. flag: 0=structure only, non-zero=include control values. No reply message. */
|
|
1393
|
+
send(address: '/g_dumpTree', ...groupFlagPairs: [number, number, ...number[]]): void;
|
|
1394
|
+
/** Query group tree structure. Args are repeating [groupID, flag] pairs. flag: 0=structure only, non-zero=include control values. Replies with `/g_queryTree.reply`. */
|
|
1395
|
+
send(address: '/g_queryTree', ...groupFlagPairs: [number, number, ...number[]]): void;
|
|
1396
|
+
|
|
1397
|
+
// ── UGen commands ──────────────────────────────────────────────────
|
|
1398
|
+
|
|
1399
|
+
/** Send a command to a specific UGen instance within a synth. The command name and args are UGen-specific. */
|
|
1400
|
+
send(address: '/u_cmd', nodeID: number, ugenIndex: number, command: string, ...args: OscArg[]): void;
|
|
1401
|
+
|
|
1402
|
+
// ── Buffer commands ────────────────────────────────────────────────
|
|
1403
|
+
|
|
1404
|
+
/** Async. Allocate an empty buffer. Queued and rewritten to /b_allocPtr internally. Use sync() after to ensure completion. Replies with `/done /b_allocPtr bufnum`. */
|
|
1405
|
+
send(address: '/b_alloc', bufnum: number, numFrames: number, numChannels?: number, sampleRate?: number): void;
|
|
1406
|
+
/** Async. Allocate a buffer and read an audio file into it. The path is fetched via the configured sampleBaseURL. Queued and rewritten internally. Replies with `/done /b_allocPtr bufnum`. */
|
|
1407
|
+
send(address: '/b_allocRead', bufnum: number, path: string, startFrame?: number, numFrames?: number): void;
|
|
1408
|
+
/** Async. Allocate a buffer and read specific channels from an audio file. Queued and rewritten internally. Replies with `/done /b_allocPtr bufnum`. */
|
|
1409
|
+
send(address: '/b_allocReadChannel', bufnum: number, path: string, startFrame: number, numFrames: number, ...channels: number[]): void;
|
|
1410
|
+
/** Async. SuperSonic extension: allocate a buffer from inline audio file bytes (WAV, FLAC, OGG, etc.) without URL fetch. Queued and rewritten internally. */
|
|
1411
|
+
send(address: '/b_allocFile', bufnum: number, data: Uint8Array | ArrayBuffer): void;
|
|
1412
|
+
/** Async. Free a buffer. Optional completionMessage is an encoded OSC message executed after freeing. Replies with `/done /b_free bufnum`. */
|
|
1413
|
+
send(address: '/b_free', bufnum: number, completionMessage?: Uint8Array | ArrayBuffer): void;
|
|
1414
|
+
/** Async. Zero a buffer's sample data. Optional completionMessage is an encoded OSC message executed after zeroing. Replies with `/done /b_zero bufnum`. */
|
|
1415
|
+
send(address: '/b_zero', bufnum: number, completionMessage?: Uint8Array | ArrayBuffer): void;
|
|
1416
|
+
/** Query buffer info. Replies with `/b_info` for each buffer: bufnum, numFrames, numChannels, sampleRate. */
|
|
1417
|
+
send(address: '/b_query', ...bufnums: [number, ...number[]]): void;
|
|
1418
|
+
/** Get individual sample values. Replies with `/b_set bufnum index value ...`. */
|
|
1419
|
+
send(address: '/b_get', bufnum: number, ...sampleIndices: [number, ...number[]]): void;
|
|
1420
|
+
/** Set individual buffer samples. Args are repeating [index, value] pairs after bufnum. */
|
|
1421
|
+
send(address: '/b_set', bufnum: number, ...indexValuePairs: number[]): void;
|
|
1422
|
+
/** Set sequential buffer samples starting at startIndex. For multiple ranges, use the catch-all overload. */
|
|
1423
|
+
send(address: '/b_setn', bufnum: number, startIndex: number, count: number, ...values: number[]): void;
|
|
1424
|
+
/** Get sequential sample values. Replies with `/b_setn bufnum startIndex count values...`. For multiple ranges, use the catch-all overload. */
|
|
1425
|
+
send(address: '/b_getn', bufnum: number, startIndex: number, count: number): void;
|
|
1426
|
+
/** Fill sequential buffer samples with a single value. For multiple ranges, use the catch-all overload. */
|
|
1427
|
+
send(address: '/b_fill', bufnum: number, startIndex: number, count: number, value: number): void;
|
|
1428
|
+
/** Async. Generate buffer contents. Commands: "sine1", "sine2", "sine3", "cheby", "copy". Flags (for sine/cheby): 1=normalize, 2=wavetable, 4=clear (OR together, e.g. 7=all). Replies with `/done /b_gen bufnum`. */
|
|
1429
|
+
send(address: '/b_gen', bufnum: number, command: string, ...args: OscArg[]): void;
|
|
1430
|
+
|
|
1431
|
+
// ── Control bus commands ───────────────────────────────────────────
|
|
1432
|
+
|
|
1433
|
+
/** Set control bus values. Args are repeating [busIndex, value] pairs. */
|
|
1434
|
+
send(address: '/c_set', ...busIndexValuePairs: number[]): void;
|
|
1435
|
+
/** Get control bus values. Replies with `/c_set index value ...`. */
|
|
1436
|
+
send(address: '/c_get', ...busIndices: [number, ...number[]]): void;
|
|
1437
|
+
/** Set sequential control bus values starting at startIndex. For multiple ranges, use the catch-all overload. */
|
|
1438
|
+
send(address: '/c_setn', startIndex: number, count: number, ...values: number[]): void;
|
|
1439
|
+
/** Get sequential control bus values. Replies with `/c_setn startIndex count values...`. For multiple ranges, use the catch-all overload. */
|
|
1440
|
+
send(address: '/c_getn', startIndex: number, count: number): void;
|
|
1441
|
+
/** Fill sequential control buses with a single value. For multiple ranges, use the catch-all overload. */
|
|
1442
|
+
send(address: '/c_fill', startIndex: number, count: number, value: number): void;
|
|
1443
|
+
|
|
1444
|
+
// ── Catch-all ──────────────────────────────────────────────────────
|
|
1445
|
+
|
|
1446
|
+
/** Send any OSC message. Use this for commands not covered by typed overloads, or for multi-range variants of commands like /n_setn, /b_fill, /c_getn. */
|
|
1271
1447
|
send(address: string, ...args: OscArg[]): void;
|
|
1272
1448
|
|
|
1273
1449
|
/**
|
|
@@ -1429,6 +1605,35 @@ export class SuperSonic {
|
|
|
1429
1605
|
*/
|
|
1430
1606
|
getLoadedBuffers(): LoadedBufferInfo[];
|
|
1431
1607
|
|
|
1608
|
+
/**
|
|
1609
|
+
* Get sample metadata (including content hash) without allocating a buffer.
|
|
1610
|
+
*
|
|
1611
|
+
* Fetches, decodes, and hashes the audio, returning the same info that
|
|
1612
|
+
* would appear in the {@link loadSample} result if the content were loaded.
|
|
1613
|
+
* No buffer slot is consumed and no OSC is sent to scsynth.
|
|
1614
|
+
*
|
|
1615
|
+
* Use this to inspect content or check for duplicates before loading.
|
|
1616
|
+
*
|
|
1617
|
+
* @param source - Sample path/URL, raw bytes, or File/Blob
|
|
1618
|
+
* @param startFrame - First frame to read (default: 0)
|
|
1619
|
+
* @param numFrames - Number of frames to read (default: 0 = all)
|
|
1620
|
+
* @returns Sample metadata including hash, frame count, channels, sample rate, and duration
|
|
1621
|
+
*
|
|
1622
|
+
* @example
|
|
1623
|
+
* const info = await sonic.sampleInfo('kick.wav');
|
|
1624
|
+
* console.log(info.hash, info.duration, info.numChannels);
|
|
1625
|
+
*
|
|
1626
|
+
* const loaded = sonic.getLoadedBuffers();
|
|
1627
|
+
* if (loaded.some(b => b.hash === info.hash)) {
|
|
1628
|
+
* console.log('Already loaded');
|
|
1629
|
+
* }
|
|
1630
|
+
*/
|
|
1631
|
+
sampleInfo(
|
|
1632
|
+
source: string | ArrayBuffer | ArrayBufferView | Blob,
|
|
1633
|
+
startFrame?: number,
|
|
1634
|
+
numFrames?: number,
|
|
1635
|
+
): Promise<SampleInfo>;
|
|
1636
|
+
|
|
1432
1637
|
/**
|
|
1433
1638
|
* Wait for scsynth to process all pending commands.
|
|
1434
1639
|
*
|