supersonic-scsynth 0.4.0 → 0.6.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.
@@ -143,6 +143,38 @@ class ScsynthProcessor extends AudioWorkletProcessor {
143
143
 
144
144
  }
145
145
 
146
+ // Write worldOptions to SharedArrayBuffer for C++ to read
147
+ // WorldOptions are written after ring buffer storage (65536 bytes)
148
+ writeWorldOptionsToMemory() {
149
+ if (!this.worldOptions || !this.wasmMemory) {
150
+ return;
151
+ }
152
+
153
+ // WorldOptions location: ringBufferBase + 65536 (after ring_buffer_storage)
154
+ const WORLD_OPTIONS_OFFSET = this.ringBufferBase + 65536;
155
+ const uint32View = new Uint32Array(this.wasmMemory.buffer, WORLD_OPTIONS_OFFSET, 32);
156
+ const float32View = new Float32Array(this.wasmMemory.buffer, WORLD_OPTIONS_OFFSET, 32);
157
+
158
+ // Write worldOptions as uint32/float32 values
159
+ // Order must match C++ reading code in audio_processor.cpp
160
+ uint32View[0] = this.worldOptions.numBuffers || 1024;
161
+ uint32View[1] = this.worldOptions.maxNodes || 1024;
162
+ uint32View[2] = this.worldOptions.maxGraphDefs || 1024;
163
+ uint32View[3] = this.worldOptions.maxWireBufs || 64;
164
+ uint32View[4] = this.worldOptions.numAudioBusChannels || 128;
165
+ uint32View[5] = this.worldOptions.numInputBusChannels || 0;
166
+ uint32View[6] = this.worldOptions.numOutputBusChannels || 2;
167
+ uint32View[7] = this.worldOptions.numControlBusChannels || 4096;
168
+ uint32View[8] = this.worldOptions.bufLength || 128;
169
+ uint32View[9] = this.worldOptions.realTimeMemorySize || 16384;
170
+ uint32View[10] = this.worldOptions.numRGens || 64;
171
+ uint32View[11] = this.worldOptions.realTime ? 1 : 0;
172
+ uint32View[12] = this.worldOptions.memoryLocking ? 1 : 0;
173
+ uint32View[13] = this.worldOptions.loadGraphDefs || 0;
174
+ uint32View[14] = this.worldOptions.preferredSampleRate || 0;
175
+ uint32View[15] = this.worldOptions.verbosity || 0;
176
+ }
177
+
146
178
  // Write debug message to SharedArrayBuffer DEBUG ring buffer
147
179
  js_debug(message) {
148
180
  if (!this.uint8View || !this.atomicView || !this.CONTROL_INDICES || !this.ringBufferBase) {
@@ -217,6 +249,10 @@ class ScsynthProcessor extends AudioWorkletProcessor {
217
249
  // Save memory reference for later use (WASM imports memory, doesn't export it)
218
250
  this.wasmMemory = memory;
219
251
 
252
+ // Store worldOptions and sampleRate for C++ initialization
253
+ this.worldOptions = data.worldOptions || {};
254
+ this.sampleRate = data.sampleRate || 48000; // Fallback to 48000 if not provided
255
+
220
256
  // Import object for WASM
221
257
  // scsynth with pthread support requires these imports
222
258
  // (pthread stubs are no-ops - AudioWorklet is single-threaded)
@@ -271,9 +307,13 @@ class ScsynthProcessor extends AudioWorkletProcessor {
271
307
 
272
308
  this.calculateBufferIndices(this.ringBufferBase);
273
309
 
310
+ // Write worldOptions to SharedArrayBuffer for C++ to read
311
+ this.writeWorldOptionsToMemory();
312
+
274
313
  // Initialize WASM memory
275
314
  if (this.wasmInstance.exports.init_memory) {
276
- this.wasmInstance.exports.init_memory(48000.0);
315
+ // Pass actual sample rate from AudioContext (not hardcoded!)
316
+ this.wasmInstance.exports.init_memory(this.sampleRate);
277
317
 
278
318
  this.isInitialized = true;
279
319
 
@@ -299,9 +339,13 @@ class ScsynthProcessor extends AudioWorkletProcessor {
299
339
 
300
340
  this.calculateBufferIndices(this.ringBufferBase);
301
341
 
342
+ // Write worldOptions to SharedArrayBuffer for C++ to read
343
+ this.writeWorldOptionsToMemory();
344
+
302
345
  // Initialize WASM memory
303
346
  if (this.wasmInstance.exports.init_memory) {
304
- this.wasmInstance.exports.init_memory(48000.0);
347
+ // Pass actual sample rate from AudioContext (not hardcoded!)
348
+ this.wasmInstance.exports.init_memory(this.sampleRate);
305
349
 
306
350
  this.isInitialized = true;
307
351
 
@@ -317,59 +361,6 @@ class ScsynthProcessor extends AudioWorkletProcessor {
317
361
  }
318
362
  }
319
363
 
320
- if (data.type === 'getMetrics') {
321
- // Return current metrics (only if initialized)
322
- if (this.atomicView && this.METRICS_INDICES && this.CONTROL_INDICES && this.bufferConstants) {
323
- // Calculate buffer usage percentages (use constants from WASM)
324
- const IN_BUFFER_SIZE = this.bufferConstants.IN_BUFFER_SIZE;
325
- const OUT_BUFFER_SIZE = this.bufferConstants.OUT_BUFFER_SIZE;
326
- const DEBUG_BUFFER_SIZE = this.bufferConstants.DEBUG_BUFFER_SIZE;
327
-
328
- const inHead = Atomics.load(this.atomicView, this.CONTROL_INDICES.IN_HEAD);
329
- const inTail = Atomics.load(this.atomicView, this.CONTROL_INDICES.IN_TAIL);
330
- const inUsed = (inHead - inTail + IN_BUFFER_SIZE) % IN_BUFFER_SIZE;
331
- const inPercentage = Math.round((inUsed / IN_BUFFER_SIZE) * 100);
332
-
333
- const outHead = Atomics.load(this.atomicView, this.CONTROL_INDICES.OUT_HEAD);
334
- const outTail = Atomics.load(this.atomicView, this.CONTROL_INDICES.OUT_TAIL);
335
- const outUsed = (outHead - outTail + OUT_BUFFER_SIZE) % OUT_BUFFER_SIZE;
336
- const outPercentage = Math.round((outUsed / OUT_BUFFER_SIZE) * 100);
337
-
338
- const debugHead = Atomics.load(this.atomicView, this.CONTROL_INDICES.DEBUG_HEAD);
339
- const debugTail = Atomics.load(this.atomicView, this.CONTROL_INDICES.DEBUG_TAIL);
340
- const debugUsed = (debugHead - debugTail + DEBUG_BUFFER_SIZE) % DEBUG_BUFFER_SIZE;
341
- const debugPercentage = Math.round((debugUsed / DEBUG_BUFFER_SIZE) * 100);
342
-
343
- const metrics = {
344
- processCount: Atomics.load(this.atomicView, this.METRICS_INDICES.PROCESS_COUNT),
345
- bufferOverruns: Atomics.load(this.atomicView, this.METRICS_INDICES.BUFFER_OVERRUNS),
346
- messagesProcessed: Atomics.load(this.atomicView, this.METRICS_INDICES.MESSAGES_PROCESSED),
347
- messagesDropped: Atomics.load(this.atomicView, this.METRICS_INDICES.MESSAGES_DROPPED),
348
- schedulerQueueDepth: Atomics.load(this.atomicView, this.METRICS_INDICES.SCHEDULER_QUEUE_DEPTH),
349
- schedulerQueueMax: Atomics.load(this.atomicView, this.METRICS_INDICES.SCHEDULER_QUEUE_MAX),
350
- schedulerQueueDropped: Atomics.load(this.atomicView, this.METRICS_INDICES.SCHEDULER_QUEUE_DROPPED),
351
- statusFlags: Atomics.load(this.atomicView, this.CONTROL_INDICES.STATUS_FLAGS),
352
- inBufferUsed: {
353
- bytes: inUsed,
354
- percentage: inPercentage
355
- },
356
- outBufferUsed: {
357
- bytes: outUsed,
358
- percentage: outPercentage
359
- },
360
- debugBufferUsed: {
361
- bytes: debugUsed,
362
- percentage: debugPercentage
363
- }
364
- };
365
-
366
- this.port.postMessage({
367
- type: 'metrics',
368
- metrics: metrics
369
- });
370
- }
371
- }
372
-
373
364
  if (data.type === 'getVersion') {
374
365
  // Return Supersonic/SuperCollider version string
375
366
  if (this.wasmInstance && this.wasmInstance.exports.get_supersonic_version_string) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supersonic-scsynth",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "SuperCollider scsynth WebAssembly port for AudioWorklet - Run SuperCollider synthesis in the browser",
5
5
  "main": "dist/supersonic.js",
6
6
  "unpkg": "dist/supersonic.js",