supersonic-scsynth 0.6.2 → 0.6.3

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "wasmFile": "scsynth-nrt.wasm",
3
- "buildId": "20251122-162420",
4
- "buildTime": "2025-11-22T16:24:20Z",
5
- "gitHash": "c67b2bee29"
3
+ "buildId": "20251122-184320",
4
+ "buildTime": "2025-11-22T18:43:20Z",
5
+ "gitHash": "5e1fc4d9e"
6
6
  }
Binary file
@@ -1,281 +1,2 @@
1
- /*
2
- SuperSonic - SuperCollider AudioWorklet WebAssembly port
3
- Copyright (c) 2025 Sam Aaron
4
-
5
- Based on SuperCollider by James McCartney and community
6
- GPL v3 or later
7
- */
8
-
9
- /**
10
- * DEBUG Worker - Receives debug messages from AudioWorklet
11
- * Uses Atomics.wait() for instant wake when debug logs arrive
12
- * Reads from DEBUG ring buffer and forwards to main thread
13
- * ES5-compatible for Qt WebEngine
14
- */
15
-
16
- // Ring buffer configuration
17
- var sharedBuffer = null;
18
- var ringBufferBase = null;
19
- var atomicView = null;
20
- var dataView = null;
21
- var uint8View = null;
22
-
23
- // Ring buffer layout constants (loaded from WASM at initialization)
24
- var bufferConstants = null;
25
-
26
- // Control indices (calculated after init)
27
- var CONTROL_INDICES = {};
28
-
29
- // Metrics view (for writing stats to SAB)
30
- var metricsView = null;
31
- var METRICS_INDICES = {};
32
-
33
- // Worker state
34
- var running = false;
35
-
36
- var DEBUG_DEBUGWORKER_LOGS = false;
37
- function debugWorkerLog() {
38
- if (DEBUG_DEBUGWORKER_LOGS) {
39
- console.log.apply(console, arguments);
40
- }
41
- }
42
-
43
- /**
44
- * Initialize ring buffer access
45
- */
46
- function initRingBuffer(buffer, base, constants) {
47
- sharedBuffer = buffer;
48
- ringBufferBase = base;
49
- bufferConstants = constants;
50
- atomicView = new Int32Array(sharedBuffer);
51
- dataView = new DataView(sharedBuffer);
52
- uint8View = new Uint8Array(sharedBuffer);
53
-
54
- // Calculate control indices using constants from WASM
55
- CONTROL_INDICES = {
56
- DEBUG_HEAD: (ringBufferBase + bufferConstants.CONTROL_START + 16) / 4,
57
- DEBUG_TAIL: (ringBufferBase + bufferConstants.CONTROL_START + 20) / 4
58
- };
59
-
60
- // Initialize metrics view (Debug metrics are at offsets 23-26 in the metrics array)
61
- var metricsBase = ringBufferBase + bufferConstants.METRICS_START;
62
- metricsView = new Uint32Array(sharedBuffer, metricsBase, bufferConstants.METRICS_SIZE / 4);
63
-
64
- METRICS_INDICES = {
65
- MESSAGES_RECEIVED: 23,
66
- WAKEUPS: 24,
67
- TIMEOUTS: 25,
68
- BYTES_READ: 26
69
- };
70
- }
71
-
72
- /**
73
- * Read debug messages from buffer
74
- */
75
- function readDebugMessages() {
76
- var head = Atomics.load(atomicView, CONTROL_INDICES.DEBUG_HEAD);
77
- var tail = Atomics.load(atomicView, CONTROL_INDICES.DEBUG_TAIL);
78
-
79
- if (head === tail) {
80
- return null; // No messages
81
- }
82
-
83
- var messages = [];
84
- var currentTail = tail;
85
- var messagesRead = 0;
86
- var maxMessages = 1000; // Process up to 1000 messages per wake
87
-
88
- while (currentTail !== head && messagesRead < maxMessages) {
89
- var bytesToEnd = bufferConstants.DEBUG_BUFFER_SIZE - currentTail;
90
- if (bytesToEnd < bufferConstants.MESSAGE_HEADER_SIZE) {
91
- currentTail = 0;
92
- continue;
93
- }
94
-
95
- var readPos = ringBufferBase + bufferConstants.DEBUG_BUFFER_START + currentTail;
96
-
97
- // Read message header (now contiguous or wrapped)
98
- var magic = dataView.getUint32(readPos, true);
99
-
100
- // Check for padding marker - skip to beginning
101
- if (magic === bufferConstants.PADDING_MAGIC) {
102
- currentTail = 0;
103
- continue;
104
- }
105
-
106
- // Validate message magic
107
- if (magic !== bufferConstants.MESSAGE_MAGIC) {
108
- console.error('[DebugWorker] Corrupted message at position', currentTail);
109
- // Skip this byte and continue
110
- currentTail = (currentTail + 1) % bufferConstants.DEBUG_BUFFER_SIZE;
111
- continue;
112
- }
113
-
114
- var length = dataView.getUint32(readPos + 4, true);
115
- var sequence = dataView.getUint32(readPos + 8, true);
116
-
117
- // Validate message length
118
- if (length < bufferConstants.MESSAGE_HEADER_SIZE || length > bufferConstants.DEBUG_BUFFER_SIZE) {
119
- console.error('[DebugWorker] Invalid message length:', length);
120
- currentTail = (currentTail + 1) % bufferConstants.DEBUG_BUFFER_SIZE;
121
- continue;
122
- }
123
-
124
- // Read payload (debug text) - now contiguous due to padding
125
- var payloadLength = length - bufferConstants.MESSAGE_HEADER_SIZE;
126
- var payloadStart = readPos + bufferConstants.MESSAGE_HEADER_SIZE;
127
-
128
- // Convert bytes to string using TextDecoder for proper UTF-8 handling
129
- var payloadBytes = uint8View.slice(payloadStart, payloadStart + payloadLength);
130
- var decoder = new TextDecoder('utf-8');
131
- var messageText = decoder.decode(payloadBytes);
132
-
133
- // Remove trailing newline if present
134
- if (messageText.endsWith('\n')) {
135
- messageText = messageText.slice(0, -1);
136
- }
137
-
138
- messages.push({
139
- text: messageText,
140
- timestamp: performance.now(),
141
- sequence: sequence
142
- });
143
-
144
- // Move to next message
145
- currentTail = (currentTail + length) % bufferConstants.DEBUG_BUFFER_SIZE;
146
- messagesRead++;
147
- if (metricsView) Atomics.add(metricsView, METRICS_INDICES.MESSAGES_RECEIVED, 1);
148
- }
149
-
150
- // Update tail pointer (consume messages)
151
- if (messagesRead > 0) {
152
- Atomics.store(atomicView, CONTROL_INDICES.DEBUG_TAIL, currentTail);
153
- if (metricsView) Atomics.add(metricsView, METRICS_INDICES.BYTES_READ, messagesRead);
154
- }
155
-
156
- return messages.length > 0 ? messages : null;
157
- }
158
-
159
- /**
160
- * Main wait loop using Atomics.wait for instant wake
161
- */
162
- function waitLoop() {
163
- while (running) {
164
- try {
165
- // Get current DEBUG_HEAD value
166
- var currentHead = Atomics.load(atomicView, CONTROL_INDICES.DEBUG_HEAD);
167
- var currentTail = Atomics.load(atomicView, CONTROL_INDICES.DEBUG_TAIL);
168
-
169
- // If buffer is empty, wait for AudioWorklet to notify us
170
- if (currentHead === currentTail) {
171
- // Wait for up to 100ms (allows checking stop signal)
172
- var result = Atomics.wait(atomicView, CONTROL_INDICES.DEBUG_HEAD, currentHead, 100);
173
-
174
- if (result === 'ok' || result === 'not-equal') {
175
- // We were notified or value changed!
176
- if (metricsView) Atomics.add(metricsView, METRICS_INDICES.WAKEUPS, 1);
177
- } else if (result === 'timed-out') {
178
- if (metricsView) Atomics.add(metricsView, METRICS_INDICES.TIMEOUTS, 1);
179
- continue; // Check running flag
180
- }
181
- }
182
-
183
- // Read all available debug messages
184
- var messages = readDebugMessages();
185
-
186
- if (messages && messages.length > 0) {
187
- // Send to main thread
188
- self.postMessage({
189
- type: 'debug',
190
- messages: messages
191
- });
192
- }
193
-
194
- } catch (error) {
195
- console.error('[DebugWorker] Error in wait loop:', error);
196
- self.postMessage({
197
- type: 'error',
198
- error: error.message
199
- });
200
-
201
- // Brief pause on error before retrying (use existing atomicView)
202
- // Wait on a value that won't change for 10ms as a simple delay
203
- Atomics.wait(atomicView, 0, atomicView[0], 10);
204
- }
205
- }
206
- }
207
-
208
- /**
209
- * Start the wait loop
210
- */
211
- function start() {
212
- if (!sharedBuffer) {
213
- console.error('[DebugWorker] Cannot start - not initialized');
214
- return;
215
- }
216
-
217
- if (running) {
218
- console.warn('[DebugWorker] Already running');
219
- return;
220
- }
221
-
222
- running = true;
223
- waitLoop();
224
- }
225
-
226
- /**
227
- * Stop the wait loop
228
- */
229
- function stop() {
230
- running = false;
231
- }
232
-
233
- /**
234
- * Clear debug buffer
235
- */
236
- function clear() {
237
- if (!sharedBuffer) return;
238
-
239
- // Reset head and tail to 0
240
- Atomics.store(atomicView, CONTROL_INDICES.DEBUG_HEAD, 0);
241
- Atomics.store(atomicView, CONTROL_INDICES.DEBUG_TAIL, 0);
242
- }
243
-
244
- /**
245
- * Handle messages from main thread
246
- */
247
- self.addEventListener('message', function(event) {
248
- var data = event.data;
249
-
250
- try {
251
- switch (data.type) {
252
- case 'init':
253
- initRingBuffer(data.sharedBuffer, data.ringBufferBase, data.bufferConstants);
254
- self.postMessage({ type: 'initialized' });
255
- break;
256
-
257
- case 'start':
258
- start();
259
- break;
260
-
261
- case 'stop':
262
- stop();
263
- break;
264
-
265
- case 'clear':
266
- clear();
267
- break;
268
-
269
- default:
270
- console.warn('[DebugWorker] Unknown message type:', data.type);
271
- }
272
- } catch (error) {
273
- console.error('[DebugWorker] Error:', error);
274
- self.postMessage({
275
- type: 'error',
276
- error: error.message
277
- });
278
- }
279
- });
280
-
281
- debugWorkerLog('[DebugWorker] Script loaded');
1
+ (()=>{var u=null,l=null,o=null,D=null,B=null,r=null,s={},i=null,f={},S=!1;function T(n,a,t){u=n,l=a,r=t,o=new Int32Array(u),D=new DataView(u),B=new Uint8Array(u),s={DEBUG_HEAD:(l+r.CONTROL_START+16)/4,DEBUG_TAIL:(l+r.CONTROL_START+20)/4};var e=l+r.METRICS_START;i=new Uint32Array(u,e,r.METRICS_SIZE/4),f={MESSAGES_RECEIVED:23,WAKEUPS:24,TIMEOUTS:25,BYTES_READ:26}}function p(){var n=Atomics.load(o,s.DEBUG_HEAD),a=Atomics.load(o,s.DEBUG_TAIL);if(n===a)return null;for(var t=[],e=a,E=0,U=1e3;e!==n&&E<U;){var I=r.DEBUG_BUFFER_SIZE-e;if(I<r.MESSAGE_HEADER_SIZE){e=0;continue}var A=l+r.DEBUG_BUFFER_START+e,v=D.getUint32(A,!0);if(v===r.PADDING_MAGIC){e=0;continue}if(v!==r.MESSAGE_MAGIC){console.error("[DebugWorker] Corrupted message at position",e),e=(e+1)%r.DEBUG_BUFFER_SIZE;continue}var c=D.getUint32(A+4,!0),g=D.getUint32(A+8,!0);if(c<r.MESSAGE_HEADER_SIZE||c>r.DEBUG_BUFFER_SIZE){console.error("[DebugWorker] Invalid message length:",c),e=(e+1)%r.DEBUG_BUFFER_SIZE;continue}var G=c-r.MESSAGE_HEADER_SIZE,d=A+r.MESSAGE_HEADER_SIZE,R=B.slice(d,d+G),m=new TextDecoder("utf-8"),_=m.decode(R);_.endsWith(`
2
+ `)&&(_=_.slice(0,-1)),t.push({text:_,timestamp:performance.now(),sequence:g}),e=(e+c)%r.DEBUG_BUFFER_SIZE,E++,i&&Atomics.add(i,f.MESSAGES_RECEIVED,1)}return E>0&&(Atomics.store(o,s.DEBUG_TAIL,e),i&&Atomics.add(i,f.BYTES_READ,E)),t.length>0?t:null}function w(){for(;S;)try{var n=Atomics.load(o,s.DEBUG_HEAD),a=Atomics.load(o,s.DEBUG_TAIL);if(n===a){var t=Atomics.wait(o,s.DEBUG_HEAD,n,100);if(t==="ok"||t==="not-equal")i&&Atomics.add(i,f.WAKEUPS,1);else if(t==="timed-out"){i&&Atomics.add(i,f.TIMEOUTS,1);continue}}var e=p();e&&e.length>0&&self.postMessage({type:"debug",messages:e})}catch(E){console.error("[DebugWorker] Error in wait loop:",E),self.postMessage({type:"error",error:E.message}),Atomics.wait(o,0,o[0],10)}}function M(){if(!u){console.error("[DebugWorker] Cannot start - not initialized");return}if(S){console.warn("[DebugWorker] Already running");return}S=!0,w()}function b(){S=!1}function C(){u&&(Atomics.store(o,s.DEBUG_HEAD,0),Atomics.store(o,s.DEBUG_TAIL,0))}self.addEventListener("message",function(n){var a=n.data;try{switch(a.type){case"init":T(a.sharedBuffer,a.ringBufferBase,a.bufferConstants),self.postMessage({type:"initialized"});break;case"start":M();break;case"stop":b();break;case"clear":C();break;default:console.warn("[DebugWorker] Unknown message type:",a.type)}}catch(t){console.error("[DebugWorker] Error:",t),self.postMessage({type:"error",error:t.message})}});})();
@@ -1,279 +1 @@
1
- /*
2
- SuperSonic - SuperCollider AudioWorklet WebAssembly port
3
- Copyright (c) 2025 Sam Aaron
4
-
5
- Based on SuperCollider by James McCartney and community
6
- GPL v3 or later
7
- */
8
-
9
- /**
10
- * OSC IN Worker - Receives OSC messages from scsynth
11
- * Uses Atomics.wait() for instant wake when data arrives
12
- * Reads from OUT ring buffer and forwards to main thread
13
- * ES5-compatible for Qt WebEngine
14
- */
15
-
16
- // Ring buffer configuration
17
- var sharedBuffer = null;
18
- var ringBufferBase = null;
19
- var atomicView = null;
20
- var dataView = null;
21
- var uint8View = null;
22
-
23
- // Ring buffer layout constants (loaded from WASM at initialization)
24
- var bufferConstants = null;
25
-
26
- // Control indices (calculated after init)
27
- var CONTROL_INDICES = {};
28
-
29
- // Metrics view (for writing stats to SAB)
30
- var metricsView = null;
31
- var METRICS_INDICES = {};
32
-
33
- // Worker state
34
- var running = false;
35
-
36
- var DEBUG_OSCIN_LOGS = false;
37
- function oscInLog() {
38
- if (DEBUG_OSCIN_LOGS) {
39
- console.log.apply(console, arguments);
40
- }
41
- }
42
-
43
- // Sequence tracking for dropped message detection
44
- var lastSequenceReceived = -1;
45
-
46
- /**
47
- * Initialize ring buffer access
48
- */
49
- function initRingBuffer(buffer, base, constants) {
50
- sharedBuffer = buffer;
51
- ringBufferBase = base;
52
- bufferConstants = constants;
53
- atomicView = new Int32Array(sharedBuffer);
54
- dataView = new DataView(sharedBuffer);
55
- uint8View = new Uint8Array(sharedBuffer);
56
-
57
- // Calculate control indices using constants from WASM
58
- CONTROL_INDICES = {
59
- OUT_HEAD: (ringBufferBase + bufferConstants.CONTROL_START + 8) / 4,
60
- OUT_TAIL: (ringBufferBase + bufferConstants.CONTROL_START + 12) / 4
61
- };
62
-
63
- // Initialize metrics view (OSC In metrics are at offsets 19-22 in the metrics array)
64
- var metricsBase = ringBufferBase + bufferConstants.METRICS_START;
65
- metricsView = new Uint32Array(sharedBuffer, metricsBase, bufferConstants.METRICS_SIZE / 4);
66
-
67
- METRICS_INDICES = {
68
- MESSAGES_RECEIVED: 19,
69
- DROPPED_MESSAGES: 20,
70
- WAKEUPS: 21,
71
- TIMEOUTS: 22
72
- };
73
- }
74
-
75
- /**
76
- * Read all available messages from OUT buffer
77
- */
78
- function readMessages() {
79
- var head = Atomics.load(atomicView, CONTROL_INDICES.OUT_HEAD);
80
- var tail = Atomics.load(atomicView, CONTROL_INDICES.OUT_TAIL);
81
-
82
- var messages = [];
83
-
84
- if (head === tail) {
85
- return messages; // No messages
86
- }
87
-
88
- var currentTail = tail;
89
- var messagesRead = 0;
90
- var maxMessages = 100;
91
-
92
- while (currentTail !== head && messagesRead < maxMessages) {
93
- var bytesToEnd = bufferConstants.OUT_BUFFER_SIZE - currentTail;
94
- if (bytesToEnd < bufferConstants.MESSAGE_HEADER_SIZE) {
95
- currentTail = 0;
96
- continue;
97
- }
98
-
99
- var readPos = ringBufferBase + bufferConstants.OUT_BUFFER_START + currentTail;
100
-
101
- // Read message header (now contiguous or wrapped)
102
- var magic = dataView.getUint32(readPos, true);
103
-
104
- // Check for padding marker - skip to beginning
105
- if (magic === bufferConstants.PADDING_MAGIC) {
106
- currentTail = 0;
107
- continue;
108
- }
109
-
110
- if (magic !== bufferConstants.MESSAGE_MAGIC) {
111
- console.error('[OSCInWorker] Corrupted message at position', currentTail);
112
- if (metricsView) Atomics.add(metricsView, METRICS_INDICES.DROPPED_MESSAGES, 1);
113
- // Skip this byte and continue
114
- currentTail = (currentTail + 1) % bufferConstants.OUT_BUFFER_SIZE;
115
- continue;
116
- }
117
-
118
- var length = dataView.getUint32(readPos + 4, true);
119
- var sequence = dataView.getUint32(readPos + 8, true);
120
- var padding = dataView.getUint32(readPos + 12, true); // unused padding field
121
-
122
- // Validate message length
123
- if (length < bufferConstants.MESSAGE_HEADER_SIZE || length > bufferConstants.OUT_BUFFER_SIZE) {
124
- console.error('[OSCInWorker] Invalid message length:', length);
125
- if (metricsView) Atomics.add(metricsView, METRICS_INDICES.DROPPED_MESSAGES, 1);
126
- currentTail = (currentTail + 1) % bufferConstants.OUT_BUFFER_SIZE;
127
- continue;
128
- }
129
-
130
- // Check for dropped messages via sequence
131
- if (lastSequenceReceived >= 0) {
132
- var expectedSeq = (lastSequenceReceived + 1) & 0xFFFFFFFF;
133
- if (sequence !== expectedSeq) {
134
- var dropped = (sequence - expectedSeq + 0x100000000) & 0xFFFFFFFF;
135
- if (dropped < 1000) { // Sanity check
136
- console.warn('[OSCInWorker] Detected', dropped, 'dropped messages (expected seq', expectedSeq, 'got', sequence, ')');
137
- if (metricsView) Atomics.add(metricsView, METRICS_INDICES.DROPPED_MESSAGES, dropped);
138
- }
139
- }
140
- }
141
- lastSequenceReceived = sequence;
142
-
143
- // Read payload (OSC binary data) - now contiguous due to padding
144
- var payloadLength = length - bufferConstants.MESSAGE_HEADER_SIZE;
145
- var payloadStart = readPos + bufferConstants.MESSAGE_HEADER_SIZE;
146
-
147
- // Create a proper copy (not a view into SharedArrayBuffer)
148
- var payload = new Uint8Array(payloadLength);
149
- for (var i = 0; i < payloadLength; i++) {
150
- payload[i] = uint8View[payloadStart + i];
151
- }
152
-
153
- messages.push({
154
- oscData: payload,
155
- sequence: sequence
156
- });
157
-
158
- // Move to next message
159
- currentTail = (currentTail + length) % bufferConstants.OUT_BUFFER_SIZE;
160
- messagesRead++;
161
- if (metricsView) Atomics.add(metricsView, METRICS_INDICES.MESSAGES_RECEIVED, 1);
162
- }
163
-
164
- // Update tail pointer (consume messages)
165
- if (messagesRead > 0) {
166
- Atomics.store(atomicView, CONTROL_INDICES.OUT_TAIL, currentTail);
167
- }
168
-
169
- return messages;
170
- }
171
-
172
- /**
173
- * Main wait loop using Atomics.wait for instant wake
174
- */
175
- function waitLoop() {
176
- while (running) {
177
- try {
178
- // Get current OUT_HEAD value
179
- var currentHead = Atomics.load(atomicView, CONTROL_INDICES.OUT_HEAD);
180
- var currentTail = Atomics.load(atomicView, CONTROL_INDICES.OUT_TAIL);
181
-
182
- // If buffer is empty, wait for AudioWorklet to notify us
183
- if (currentHead === currentTail) {
184
- // Wait for up to 100ms (allows checking stop signal)
185
- var result = Atomics.wait(atomicView, CONTROL_INDICES.OUT_HEAD, currentHead, 100);
186
-
187
- if (result === 'ok' || result === 'not-equal') {
188
- // We were notified or value changed!
189
- if (metricsView) Atomics.add(metricsView, METRICS_INDICES.WAKEUPS, 1);
190
- } else if (result === 'timed-out') {
191
- if (metricsView) Atomics.add(metricsView, METRICS_INDICES.TIMEOUTS, 1);
192
- continue; // Check running flag
193
- }
194
- }
195
-
196
- // Read all available messages
197
- var messages = readMessages();
198
-
199
- if (messages.length > 0) {
200
- // Send to main thread
201
- self.postMessage({
202
- type: 'messages',
203
- messages: messages
204
- });
205
- }
206
-
207
- } catch (error) {
208
- console.error('[OSCInWorker] Error in wait loop:', error);
209
- self.postMessage({
210
- type: 'error',
211
- error: error.message
212
- });
213
-
214
- // Brief pause on error before retrying (use existing atomicView)
215
- // Wait on a value that won't change for 10ms as a simple delay
216
- Atomics.wait(atomicView, 0, atomicView[0], 10);
217
- }
218
- }
219
- }
220
-
221
- /**
222
- * Start the wait loop
223
- */
224
- function start() {
225
- if (!sharedBuffer) {
226
- console.error('[OSCInWorker] Cannot start - not initialized');
227
- return;
228
- }
229
-
230
- if (running) {
231
- console.warn('[OSCInWorker] Already running');
232
- return;
233
- }
234
-
235
- running = true;
236
- waitLoop();
237
- }
238
-
239
- /**
240
- * Stop the wait loop
241
- */
242
- function stop() {
243
- running = false;
244
- }
245
-
246
- /**
247
- * Handle messages from main thread
248
- */
249
- self.addEventListener('message', function(event) {
250
- var data = event.data;
251
-
252
- try {
253
- switch (data.type) {
254
- case 'init':
255
- initRingBuffer(data.sharedBuffer, data.ringBufferBase, data.bufferConstants);
256
- self.postMessage({ type: 'initialized' });
257
- break;
258
-
259
- case 'start':
260
- start();
261
- break;
262
-
263
- case 'stop':
264
- stop();
265
- break;
266
-
267
- default:
268
- console.warn('[OSCInWorker] Unknown message type:', data.type);
269
- }
270
- } catch (error) {
271
- console.error('[OSCInWorker] Error:', error);
272
- self.postMessage({
273
- type: 'error',
274
- error: error.message
275
- });
276
- }
277
- });
278
-
279
- oscInLog('[OSCInWorker] Script loaded');
1
+ (()=>{var f=null,l=null,o=null,u=null,F=null,e=null,E={},a=null,s={},v=!1;var U=-1;function M(i,t,n){f=i,l=t,e=n,o=new Int32Array(f),u=new DataView(f),F=new Uint8Array(f),E={OUT_HEAD:(l+e.CONTROL_START+8)/4,OUT_TAIL:(l+e.CONTROL_START+12)/4};var r=l+e.METRICS_START;a=new Uint32Array(f,r,e.METRICS_SIZE/4),s={MESSAGES_RECEIVED:19,DROPPED_MESSAGES:20,WAKEUPS:21,TIMEOUTS:22}}function w(){var i=Atomics.load(o,E.OUT_HEAD),t=Atomics.load(o,E.OUT_TAIL),n=[];if(i===t)return n;for(var r=t,S=0,g=100;r!==i&&S<g;){var D=e.OUT_BUFFER_SIZE-r;if(D<e.MESSAGE_HEADER_SIZE){r=0;continue}var A=l+e.OUT_BUFFER_START+r,d=u.getUint32(A,!0);if(d===e.PADDING_MAGIC){r=0;continue}if(d!==e.MESSAGE_MAGIC){console.error("[OSCInWorker] Corrupted message at position",r),a&&Atomics.add(a,s.DROPPED_MESSAGES,1),r=(r+1)%e.OUT_BUFFER_SIZE;continue}var c=u.getUint32(A+4,!0),_=u.getUint32(A+8,!0),G=u.getUint32(A+12,!0);if(c<e.MESSAGE_HEADER_SIZE||c>e.OUT_BUFFER_SIZE){console.error("[OSCInWorker] Invalid message length:",c),a&&Atomics.add(a,s.DROPPED_MESSAGES,1),r=(r+1)%e.OUT_BUFFER_SIZE;continue}if(U>=0){var T=U+1&4294967295;if(_!==T){var O=_-T+4294967296&4294967295;O<1e3&&(console.warn("[OSCInWorker] Detected",O,"dropped messages (expected seq",T,"got",_,")"),a&&Atomics.add(a,s.DROPPED_MESSAGES,O))}}U=_;for(var R=c-e.MESSAGE_HEADER_SIZE,C=A+e.MESSAGE_HEADER_SIZE,m=new Uint8Array(R),I=0;I<R;I++)m[I]=F[C+I];n.push({oscData:m,sequence:_}),r=(r+c)%e.OUT_BUFFER_SIZE,S++,a&&Atomics.add(a,s.MESSAGES_RECEIVED,1)}return S>0&&Atomics.store(o,E.OUT_TAIL,r),n}function p(){for(;v;)try{var i=Atomics.load(o,E.OUT_HEAD),t=Atomics.load(o,E.OUT_TAIL);if(i===t){var n=Atomics.wait(o,E.OUT_HEAD,i,100);if(n==="ok"||n==="not-equal")a&&Atomics.add(a,s.WAKEUPS,1);else if(n==="timed-out"){a&&Atomics.add(a,s.TIMEOUTS,1);continue}}var r=w();r.length>0&&self.postMessage({type:"messages",messages:r})}catch(S){console.error("[OSCInWorker] Error in wait loop:",S),self.postMessage({type:"error",error:S.message}),Atomics.wait(o,0,o[0],10)}}function k(){if(!f){console.error("[OSCInWorker] Cannot start - not initialized");return}if(v){console.warn("[OSCInWorker] Already running");return}v=!0,p()}function B(){v=!1}self.addEventListener("message",function(i){var t=i.data;try{switch(t.type){case"init":M(t.sharedBuffer,t.ringBufferBase,t.bufferConstants),self.postMessage({type:"initialized"});break;case"start":k();break;case"stop":B();break;default:console.warn("[OSCInWorker] Unknown message type:",t.type)}}catch(n){console.error("[OSCInWorker] Error:",n),self.postMessage({type:"error",error:n.message})}});})();