@libraz/libsonare 1.1.0 → 1.2.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/dist/index.js CHANGED
@@ -15,7 +15,21 @@ var PitchClass = {
15
15
  };
16
16
  var Mode = {
17
17
  Major: 0,
18
- Minor: 1
18
+ Minor: 1,
19
+ Dorian: 2,
20
+ Phrygian: 3,
21
+ Lydian: 4,
22
+ Mixolydian: 5,
23
+ Locrian: 6
24
+ };
25
+ var KeyProfile = {
26
+ KrumhanslSchmuckler: 0,
27
+ Temperley: 1,
28
+ Shaath: 2,
29
+ FaraldoEDMT: 3,
30
+ FaraldoEDMA: 4,
31
+ FaraldoEDMM: 5,
32
+ BellmanBudge: 6
19
33
  };
20
34
  var ChordQuality = {
21
35
  Major: 0,
@@ -26,7 +40,15 @@ var ChordQuality = {
26
40
  Major7: 5,
27
41
  Minor7: 6,
28
42
  Sus2: 7,
29
- Sus4: 8
43
+ Sus4: 8,
44
+ Unknown: 9,
45
+ Add9: 10,
46
+ MinorAdd9: 11,
47
+ Dim7: 12,
48
+ HalfDim7: 13,
49
+ Major9: 14,
50
+ Dominant9: 15,
51
+ Sus2Add4: 16
30
52
  };
31
53
  var SectionType = {
32
54
  Intro: 0,
@@ -35,10 +57,47 @@ var SectionType = {
35
57
  Chorus: 3,
36
58
  Bridge: 4,
37
59
  Instrumental: 5,
38
- Outro: 6
60
+ Outro: 6,
61
+ Unknown: 7
39
62
  };
40
63
 
41
64
  // src/index.ts
65
+ var EXPECTED_ENGINE_ABI_VERSION = 2;
66
+ function automationCurveCode(curve) {
67
+ switch (curve) {
68
+ case "linear":
69
+ return 0;
70
+ case "exponential":
71
+ return 1;
72
+ case "hold":
73
+ return 2;
74
+ case "s-curve":
75
+ return 3;
76
+ default:
77
+ throw new Error(`Invalid automation curve: ${curve}`);
78
+ }
79
+ }
80
+ function panLawCode(panLaw) {
81
+ if (typeof panLaw === "number") {
82
+ return panLaw;
83
+ }
84
+ switch (panLaw) {
85
+ case "const4.5dB":
86
+ return 1;
87
+ case "const6dB":
88
+ return 2;
89
+ case "linear0dB":
90
+ return 3;
91
+ default:
92
+ return 0;
93
+ }
94
+ }
95
+ function meterTapCode(tap) {
96
+ return tap === "preFader" || tap === 0 ? 0 : 1;
97
+ }
98
+ function sendTimingCode(timing) {
99
+ return timing === "preFader" || timing === 0 ? 0 : 1;
100
+ }
42
101
  var module = null;
43
102
  var initPromise = null;
44
103
  async function init(options) {
@@ -68,17 +127,206 @@ function version() {
68
127
  }
69
128
  return module.version();
70
129
  }
130
+ function engineAbiVersion() {
131
+ if (!module) {
132
+ throw new Error("Module not initialized. Call init() first.");
133
+ }
134
+ return module.engineAbiVersion();
135
+ }
136
+ function engineCapabilities() {
137
+ const abiVersion = engineAbiVersion();
138
+ const sharedArrayBuffer = typeof globalThis.SharedArrayBuffer === "function";
139
+ const atomics = typeof globalThis.Atomics === "object";
140
+ const audioWorklet = typeof AudioWorkletNode !== "undefined" || typeof globalThis.AudioWorkletProcessor !== "undefined";
141
+ return {
142
+ engineAbiVersion: abiVersion,
143
+ expectedEngineAbiVersion: EXPECTED_ENGINE_ABI_VERSION,
144
+ abiCompatible: abiVersion === EXPECTED_ENGINE_ABI_VERSION,
145
+ sharedArrayBuffer,
146
+ atomics,
147
+ audioWorklet,
148
+ mode: sharedArrayBuffer && atomics ? "sab" : "postMessage"
149
+ };
150
+ }
151
+ var RealtimeEngine = class {
152
+ constructor(sampleRate = 48e3, maxBlockSize = 128, commandCapacity = 1024, telemetryCapacity = 1024) {
153
+ if (!module) {
154
+ throw new Error("Module not initialized. Call init() first.");
155
+ }
156
+ const capabilities = engineCapabilities();
157
+ if (!capabilities.abiCompatible) {
158
+ throw new Error(
159
+ `Engine ABI mismatch: wasm=${capabilities.engineAbiVersion}, expected=${capabilities.expectedEngineAbiVersion}`
160
+ );
161
+ }
162
+ this.native = new module.RealtimeEngine(
163
+ sampleRate,
164
+ maxBlockSize,
165
+ commandCapacity,
166
+ telemetryCapacity
167
+ );
168
+ }
169
+ prepare(sampleRate, maxBlockSize, commandCapacity = 1024, telemetryCapacity = 1024) {
170
+ this.native.prepare(sampleRate, maxBlockSize, commandCapacity, telemetryCapacity);
171
+ }
172
+ /** Queue a sample-accurate parameter change (engine kSetParam). */
173
+ setParameter(paramId, value, renderFrame = -1) {
174
+ this.native.setParameter(paramId, value, renderFrame);
175
+ }
176
+ /** Queue a smoothed parameter change (engine kSetParamSmoothed). */
177
+ setParameterSmoothed(paramId, value, renderFrame = -1) {
178
+ this.native.setParameterSmoothed(paramId, value, renderFrame);
179
+ }
180
+ /** Read back the current transport state snapshot. */
181
+ getTransportState() {
182
+ return this.native.getTransportState();
183
+ }
184
+ play(renderFrame = -1) {
185
+ this.native.play(renderFrame);
186
+ }
187
+ stop(renderFrame = -1) {
188
+ this.native.stop(renderFrame);
189
+ }
190
+ seekSample(timelineSample, renderFrame = -1) {
191
+ this.native.seekSample(timelineSample, renderFrame);
192
+ }
193
+ seekPpq(ppq, renderFrame = -1) {
194
+ this.native.seekPpq(ppq, renderFrame);
195
+ }
196
+ setTempo(bpm) {
197
+ this.native.setTempo(bpm);
198
+ }
199
+ setTimeSignature(numerator, denominator) {
200
+ this.native.setTimeSignature(numerator, denominator);
201
+ }
202
+ setLoop(startPpq, endPpq, enabled = true) {
203
+ this.native.setLoop(startPpq, endPpq, enabled);
204
+ }
205
+ addParameter(info) {
206
+ this.native.addParameter(info);
207
+ }
208
+ parameterCount() {
209
+ return this.native.parameterCount();
210
+ }
211
+ parameterInfoByIndex(index) {
212
+ return this.native.parameterInfoByIndex(index);
213
+ }
214
+ parameterInfo(id) {
215
+ return this.native.parameterInfo(id);
216
+ }
217
+ setAutomationLane(paramId, points) {
218
+ this.native.setAutomationLane(paramId, points);
219
+ }
220
+ automationLaneCount() {
221
+ return this.native.automationLaneCount();
222
+ }
223
+ setMarkers(markers) {
224
+ this.native.setMarkers(markers);
225
+ }
226
+ markerCount() {
227
+ return this.native.markerCount();
228
+ }
229
+ markerByIndex(index) {
230
+ return this.native.markerByIndex(index);
231
+ }
232
+ marker(id) {
233
+ return this.native.marker(id);
234
+ }
235
+ seekMarker(markerId, renderFrame = -1) {
236
+ this.native.seekMarker(markerId, renderFrame);
237
+ }
238
+ setLoopFromMarkers(startMarkerId, endMarkerId) {
239
+ this.native.setLoopFromMarkers(startMarkerId, endMarkerId);
240
+ }
241
+ setMetronome(config) {
242
+ this.native.setMetronome(config);
243
+ }
244
+ metronome() {
245
+ return this.native.metronome();
246
+ }
247
+ countInEndSample(startSample, bars) {
248
+ return Number(this.native.countInEndSample(startSample, bars));
249
+ }
250
+ setGraph(spec) {
251
+ this.native.setGraph(spec);
252
+ }
253
+ graphNodeCount() {
254
+ return this.native.graphNodeCount();
255
+ }
256
+ graphConnectionCount() {
257
+ return this.native.graphConnectionCount();
258
+ }
259
+ setClips(clips) {
260
+ this.native.setClips(clips);
261
+ }
262
+ clipCount() {
263
+ return this.native.clipCount();
264
+ }
265
+ setCaptureBuffer(numChannels, capacityFrames) {
266
+ this.native.setCaptureBuffer(numChannels, capacityFrames);
267
+ }
268
+ armCapture(armed = true) {
269
+ this.native.armCapture(armed);
270
+ }
271
+ setCapturePunch(startSample, endSample, enabled = true) {
272
+ this.native.setCapturePunch(startSample, endSample, enabled);
273
+ }
274
+ resetCapture() {
275
+ this.native.resetCapture();
276
+ }
277
+ captureStatus() {
278
+ return this.native.captureStatus();
279
+ }
280
+ capturedAudio() {
281
+ return this.native.capturedAudio();
282
+ }
283
+ process(channels) {
284
+ return this.native.process(channels);
285
+ }
286
+ processWithMonitor(channels) {
287
+ return this.native.processWithMonitor(channels);
288
+ }
289
+ renderOffline(channels, blockSize = 128) {
290
+ return this.native.renderOffline(channels, blockSize);
291
+ }
292
+ bounceOffline(options) {
293
+ return this.native.bounceOffline(options);
294
+ }
295
+ freezeOffline(options) {
296
+ return this.native.freezeOffline(options);
297
+ }
298
+ drainTelemetry(maxRecords = 1024) {
299
+ return this.native.drainTelemetry(maxRecords);
300
+ }
301
+ drainMeterTelemetry(maxRecords = 1024) {
302
+ return this.native.drainMeterTelemetry(maxRecords);
303
+ }
304
+ destroy() {
305
+ this.native.delete();
306
+ }
307
+ };
71
308
  function detectBpm(samples, sampleRate) {
72
309
  if (!module) {
73
310
  throw new Error("Module not initialized. Call init() first.");
74
311
  }
75
312
  return module.detectBpm(samples, sampleRate);
76
313
  }
77
- function detectKey(samples, sampleRate) {
314
+ function detectKey(samples, sampleRate, options = {}) {
78
315
  if (!module) {
79
316
  throw new Error("Module not initialized. Call init() first.");
80
317
  }
81
- const result = module.detectKey(samples, sampleRate);
318
+ const result = module._detectKeyWithOptions(
319
+ samples,
320
+ sampleRate,
321
+ options.nFft ?? 4096,
322
+ options.hopLength ?? 512,
323
+ options.useHpss ?? false,
324
+ options.loudnessWeighted ?? false,
325
+ options.highPassHz ?? 0,
326
+ keyModeValues(options.modes),
327
+ keyProfileValue(options.profile),
328
+ options.genreHint ?? ""
329
+ );
82
330
  return {
83
331
  root: result.root,
84
332
  mode: result.mode,
@@ -87,6 +335,88 @@ function detectKey(samples, sampleRate) {
87
335
  shortName: result.shortName
88
336
  };
89
337
  }
338
+ function convertKeyCandidate(wasm) {
339
+ return {
340
+ key: {
341
+ root: wasm.key.root,
342
+ mode: wasm.key.mode,
343
+ confidence: wasm.key.confidence,
344
+ name: wasm.key.name,
345
+ shortName: wasm.key.shortName
346
+ },
347
+ correlation: wasm.correlation
348
+ };
349
+ }
350
+ function keyModeValues(modes) {
351
+ if (!modes) {
352
+ return [];
353
+ }
354
+ if (modes === "major-minor") {
355
+ return [Mode.Major, Mode.Minor];
356
+ }
357
+ if (modes === "all" || modes === "modal") {
358
+ return [
359
+ Mode.Major,
360
+ Mode.Minor,
361
+ Mode.Dorian,
362
+ Mode.Phrygian,
363
+ Mode.Lydian,
364
+ Mode.Mixolydian,
365
+ Mode.Locrian
366
+ ];
367
+ }
368
+ const names = {
369
+ major: Mode.Major,
370
+ minor: Mode.Minor,
371
+ dorian: Mode.Dorian,
372
+ phrygian: Mode.Phrygian,
373
+ lydian: Mode.Lydian,
374
+ mixolydian: Mode.Mixolydian,
375
+ locrian: Mode.Locrian
376
+ };
377
+ return modes.map((mode) => typeof mode === "number" ? mode : names[mode]);
378
+ }
379
+ function keyProfileValue(profile) {
380
+ if (profile === void 0) {
381
+ return -1;
382
+ }
383
+ if (typeof profile === "number") {
384
+ return profile;
385
+ }
386
+ const names = {
387
+ ks: KeyProfile.KrumhanslSchmuckler,
388
+ krumhansl: KeyProfile.KrumhanslSchmuckler,
389
+ temperley: KeyProfile.Temperley,
390
+ shaath: KeyProfile.Shaath,
391
+ keyfinder: KeyProfile.Shaath,
392
+ "faraldo-edmt": KeyProfile.FaraldoEDMT,
393
+ edmt: KeyProfile.FaraldoEDMT,
394
+ "faraldo-edma": KeyProfile.FaraldoEDMA,
395
+ edma: KeyProfile.FaraldoEDMA,
396
+ "faraldo-edmm": KeyProfile.FaraldoEDMM,
397
+ edmm: KeyProfile.FaraldoEDMM,
398
+ "bellman-budge": KeyProfile.BellmanBudge,
399
+ bellman: KeyProfile.BellmanBudge
400
+ };
401
+ return names[profile];
402
+ }
403
+ function detectKeyCandidates(samples, sampleRate, options = {}) {
404
+ if (!module) {
405
+ throw new Error("Module not initialized. Call init() first.");
406
+ }
407
+ return module._detectKeyCandidates(
408
+ samples,
409
+ sampleRate,
410
+ options.nFft ?? 4096,
411
+ options.hopLength ?? 512,
412
+ options.useHpss ?? false,
413
+ options.loudnessWeighted ?? false,
414
+ options.highPassHz ?? 0,
415
+ keyModeValues(options.modes),
416
+ keyProfileValue(options.profile),
417
+ options.genreHint ?? ""
418
+ ).map(convertKeyCandidate);
419
+ }
90
420
  function detectOnsets(samples, sampleRate) {
91
421
  if (!module) {
92
422
  throw new Error("Module not initialized. Call init() first.");
@@ -99,6 +429,58 @@ function detectBeats(samples, sampleRate) {
99
429
  }
100
430
  return module.detectBeats(samples, sampleRate);
101
431
  }
432
+ function detectDownbeats(samples, sampleRate) {
433
+ if (!module) {
434
+ throw new Error("Module not initialized. Call init() first.");
435
+ }
436
+ return module.detectDownbeats(samples, sampleRate);
437
+ }
438
+ function convertChordAnalysisResult(wasm) {
439
+ return {
440
+ chords: wasm.chords.map((c) => ({
441
+ root: c.root,
442
+ bass: c.bass,
443
+ quality: c.quality,
444
+ start: c.start,
445
+ end: c.end,
446
+ confidence: c.confidence,
447
+ name: c.name
448
+ }))
449
+ };
450
+ }
451
+ function detectChords(samples, sampleRate, options = {}) {
452
+ if (!module) {
453
+ throw new Error("Module not initialized. Call init() first.");
454
+ }
455
+ const result = module.detectChords(
456
+ samples,
457
+ sampleRate,
458
+ options.minDuration ?? 0.3,
459
+ options.smoothingWindow ?? 2,
460
+ options.threshold ?? 0.5,
461
+ options.useTriadsOnly ?? false,
462
+ options.nFft ?? 2048,
463
+ options.hopLength ?? 512,
464
+ options.useBeatSync ?? true,
465
+ options.useHmm ?? false,
466
+ options.hmmBeamWidth ?? 24,
467
+ options.useKeyContext ?? false,
468
+ options.keyRoot ?? PitchClass.C,
469
+ options.keyMode ?? Mode.Major,
470
+ options.detectInversions ?? false,
471
+ chordChromaMethodValue(options.chromaMethod ?? "stft")
472
+ );
473
+ return convertChordAnalysisResult(result);
474
+ }
475
+ function chordChromaMethodValue(method) {
476
+ if (method === "stft") {
477
+ return 0;
478
+ }
479
+ if (method === "nnls") {
480
+ return 1;
481
+ }
482
+ throw new Error(`Invalid chord chroma method: ${method}`);
483
+ }
102
484
  function convertAnalysisResult(wasm) {
103
485
  const beatTimes = new Float32Array(wasm.beats.length);
104
486
  for (let i = 0; i < wasm.beats.length; i++) {
@@ -119,6 +501,7 @@ function convertAnalysisResult(wasm) {
119
501
  beats: wasm.beats,
120
502
  chords: wasm.chords.map((c) => ({
121
503
  root: c.root,
504
+ bass: c.bass,
122
505
  quality: c.quality,
123
506
  start: c.start,
124
507
  end: c.end,
@@ -146,6 +529,31 @@ function analyze(samples, sampleRate) {
146
529
  const result = module.analyze(samples, sampleRate);
147
530
  return convertAnalysisResult(result);
148
531
  }
532
+ function analyzeImpulseResponse(samples, sampleRate, nOctaveBands = 6) {
533
+ if (!module) {
534
+ throw new Error("Module not initialized. Call init() first.");
535
+ }
536
+ const result = module.analyzeImpulseResponse(
537
+ samples,
538
+ sampleRate,
539
+ nOctaveBands
540
+ );
541
+ return result;
542
+ }
543
+ function detectAcoustic(samples, sampleRate, nOctaveBands = 6, nThirdOctaveSubbands = 24, minDecayDb = 30, noiseFloorMarginDb = 10) {
544
+ if (!module) {
545
+ throw new Error("Module not initialized. Call init() first.");
546
+ }
547
+ const result = module.detectAcoustic(
548
+ samples,
549
+ sampleRate,
550
+ nOctaveBands,
551
+ nThirdOctaveSubbands,
552
+ minDecayDb,
553
+ noiseFloorMarginDb
554
+ );
555
+ return result;
556
+ }
149
557
  function analyzeWithProgress(samples, sampleRate, onProgress) {
150
558
  if (!module) {
151
559
  throw new Error("Module not initialized. Call init() first.");
@@ -183,6 +591,24 @@ function pitchShift(samples, sampleRate, semitones) {
183
591
  }
184
592
  return module.pitchShift(samples, sampleRate, semitones);
185
593
  }
594
+ function pitchCorrectToMidi(samples, sampleRate, currentMidi, targetMidi) {
595
+ if (!module) {
596
+ throw new Error("Module not initialized. Call init() first.");
597
+ }
598
+ return module.pitchCorrectToMidi(samples, sampleRate, currentMidi, targetMidi);
599
+ }
600
+ function noteStretch(samples, sampleRate, onsetSample, offsetSample, stretchRatio) {
601
+ if (!module) {
602
+ throw new Error("Module not initialized. Call init() first.");
603
+ }
604
+ return module.noteStretch(samples, sampleRate, onsetSample, offsetSample, stretchRatio);
605
+ }
606
+ function voiceChange(samples, sampleRate, pitchSemitones, formantFactor) {
607
+ if (!module) {
608
+ throw new Error("Module not initialized. Call init() first.");
609
+ }
610
+ return module.voiceChange(samples, sampleRate, pitchSemitones, formantFactor);
611
+ }
186
612
  function normalize(samples, sampleRate, targetDb = 0) {
187
613
  if (!module) {
188
614
  throw new Error("Module not initialized. Call init() first.");
@@ -252,6 +678,24 @@ function masteringStereoAnalyze(analysisName, left, right, sampleRate, params =
252
678
  }
253
679
  return module.masteringStereoAnalyze(analysisName, left, right, sampleRate, params);
254
680
  }
681
+ function masteringAssistantSuggest(samples, sampleRate, params = {}) {
682
+ if (!module) {
683
+ throw new Error("Module not initialized. Call init() first.");
684
+ }
685
+ return module.masteringAssistantSuggest(samples, sampleRate, params);
686
+ }
687
+ function masteringAudioProfile(samples, sampleRate, params = {}) {
688
+ if (!module) {
689
+ throw new Error("Module not initialized. Call init() first.");
690
+ }
691
+ return module.masteringAudioProfile(samples, sampleRate, params);
692
+ }
693
+ function masteringStreamingPreview(samples, sampleRate, platforms = []) {
694
+ if (!module) {
695
+ throw new Error("Module not initialized. Call init() first.");
696
+ }
697
+ return module.masteringStreamingPreview(samples, sampleRate, platforms);
698
+ }
255
699
  function masteringChain(samples, sampleRate, config) {
256
700
  if (!module) {
257
701
  throw new Error("Module not initialized. Call init() first.");
@@ -314,6 +758,32 @@ function masterAudioStereo(left, right, sampleRate, presetName, overrides = null
314
758
  }
315
759
  return module.masterAudioStereo(presetName, left, right, sampleRate, overrides);
316
760
  }
761
+ function mixingScenePresetNames() {
762
+ if (!module) {
763
+ throw new Error("Module not initialized. Call init() first.");
764
+ }
765
+ return module.mixingScenePresetNames();
766
+ }
767
+ function mixingScenePresetJson(preset) {
768
+ if (!module) {
769
+ throw new Error("Module not initialized. Call init() first.");
770
+ }
771
+ return module.mixingScenePresetJson(preset);
772
+ }
773
+ function mixStereo(leftChannels, rightChannels, sampleRate = 48e3, options = {}) {
774
+ if (!module) {
775
+ throw new Error("Module not initialized. Call init() first.");
776
+ }
777
+ if (leftChannels.length === 0 || leftChannels.length !== rightChannels.length) {
778
+ throw new Error("leftChannels and rightChannels must have the same non-zero length.");
779
+ }
780
+ return module.mixStereo(
781
+ leftChannels,
782
+ rightChannels,
783
+ sampleRate,
784
+ options
785
+ );
786
+ }
317
787
  var StreamingMasteringChain = class {
318
788
  constructor(config) {
319
789
  if (!module) {
@@ -363,6 +833,403 @@ var StreamingMasteringChain = class {
363
833
  this.chain.delete();
364
834
  }
365
835
  };
836
+ var StreamingEqualizer = class {
837
+ constructor(config = {}) {
838
+ if (!module) {
839
+ throw new Error("Module not initialized. Call init() first.");
840
+ }
841
+ this.eq = module.createEqualizer(config);
842
+ }
843
+ /**
844
+ * Configure the band at `index` (0..23). Omitted fields use C++ defaults.
845
+ */
846
+ setBand(index, band) {
847
+ this.eq.setBand(index, band);
848
+ }
849
+ /** Disable and reset every band. */
850
+ clear() {
851
+ this.eq.clear();
852
+ }
853
+ /**
854
+ * Set the global phase mode: 1=ZeroLatency, 2=NaturalPhase, 3=LinearPhase.
855
+ */
856
+ setPhaseMode(mode) {
857
+ this.eq.setPhaseMode(mode);
858
+ }
859
+ /** Enable or disable output auto-gain compensation. */
860
+ setAutoGain(enabled) {
861
+ this.eq.setAutoGain(enabled);
862
+ }
863
+ /** Set all-band EQ gain scale as a 0.0..2.0 multiplier. */
864
+ setGainScale(scale) {
865
+ this.eq.setGainScale(scale);
866
+ }
867
+ /** Set post-EQ output gain in dB. */
868
+ setOutputGainDb(gainDb) {
869
+ this.eq.setOutputGainDb(gainDb);
870
+ }
871
+ /** Set post-EQ stereo balance in -1.0..1.0; mono input ignores pan. */
872
+ setOutputPan(pan) {
873
+ this.eq.setOutputPan(pan);
874
+ }
875
+ /**
876
+ * Provide a mono external sidechain key for dynamic bands that opt into
877
+ * `external_sidechain`. The samples are copied into an owned buffer.
878
+ */
879
+ setSidechainMono(samples) {
880
+ this.eq.setSidechainMono(samples);
881
+ }
882
+ /**
883
+ * Provide a stereo external sidechain key. Both channels must match length.
884
+ */
885
+ setSidechainStereo(left, right) {
886
+ if (left.length !== right.length) {
887
+ throw new Error("Sidechain channel lengths must match.");
888
+ }
889
+ this.eq.setSidechainStereo(left, right);
890
+ }
891
+ /** Release any borrowed external sidechain buffers. */
892
+ clearSidechain() {
893
+ this.eq.clearSidechain();
894
+ }
895
+ /** Auto-gain applied on the most recent block, in dB. */
896
+ lastAutoGainDb() {
897
+ return this.eq.lastAutoGainDb();
898
+ }
899
+ /** Reported processing latency in samples (non-zero for linear-phase bands). */
900
+ latencySamples() {
901
+ return this.eq.latencySamples();
902
+ }
903
+ /**
904
+ * Process one mono block, returning the equalized samples (same length).
905
+ */
906
+ processMono(samples) {
907
+ return this.eq.processMono(samples);
908
+ }
909
+ /**
910
+ * Process one stereo block, returning the equalized channels.
911
+ */
912
+ processStereo(left, right) {
913
+ if (left.length !== right.length) {
914
+ throw new Error("Stereo channel lengths must match.");
915
+ }
916
+ return this.eq.processStereo(left, right);
917
+ }
918
+ /**
919
+ * Read the latest pre/post spectrum snapshot for metering. `seq` increments
920
+ * each time a new snapshot is published.
921
+ */
922
+ spectrum() {
923
+ return this.eq.spectrum();
924
+ }
925
+ /**
926
+ * Configure bands so the source spectrum matches the reference spectrum.
927
+ *
928
+ * @param source - Source audio (mono samples)
929
+ * @param reference - Reference audio (mono samples)
930
+ * @param options - `sampleRate` (default 48000) and `maxBands` (default 8)
931
+ */
932
+ match(source, reference, options = {}) {
933
+ this.eq.match(source, reference, options);
934
+ }
935
+ /** Release the underlying WASM object. Safe to call only once. */
936
+ delete() {
937
+ this.eq.delete();
938
+ }
939
+ };
940
+ function mixerScenePresetJson(preset) {
941
+ if (!module) {
942
+ throw new Error("Module not initialized. Call init() first.");
943
+ }
944
+ return module.mixerPresetJson(preset);
945
+ }
946
+ var Mixer = class _Mixer {
947
+ constructor(mixer) {
948
+ this.mixer = mixer;
949
+ }
950
+ /**
951
+ * Build a mixer from a scene JSON string.
952
+ *
953
+ * @param json - Scene JSON (strips, buses, sends, connections, inserts)
954
+ * @param sampleRate - Sample rate in Hz (default: 48000)
955
+ * @param blockSize - Maximum block size per {@link processStereo} call (default: 512)
956
+ */
957
+ static fromSceneJson(json, sampleRate = 48e3, blockSize = 512) {
958
+ if (!module) {
959
+ throw new Error("Module not initialized. Call init() first.");
960
+ }
961
+ return new _Mixer(module.createMixerFromSceneJson(json, sampleRate, blockSize));
962
+ }
963
+ /** Rebuild and compile the routing graph from the current scene topology. */
964
+ compile() {
965
+ this.mixer.compile();
966
+ }
967
+ /**
968
+ * Mix one block of per-strip stereo audio into the stereo master.
969
+ *
970
+ * @param leftChannels - `leftChannels[i]` is the left channel of strip `i`
971
+ * @param rightChannels - `rightChannels[i]` is the right channel of strip `i`
972
+ * @returns Mixed stereo master (`left`, `right`, `sampleRate`)
973
+ */
974
+ processStereo(leftChannels, rightChannels) {
975
+ if (leftChannels.length !== rightChannels.length) {
976
+ throw new Error("leftChannels and rightChannels must have the same length.");
977
+ }
978
+ return this.mixer.processStereo(leftChannels, rightChannels);
979
+ }
980
+ /**
981
+ * Mix one block into caller-owned output arrays.
982
+ *
983
+ * This avoids allocating the result object and result `Float32Array`s. It is
984
+ * intended for realtime bridges such as AudioWorklet; the input channel count
985
+ * must match the scene strip count and all arrays must have the same length.
986
+ */
987
+ processStereoInto(leftChannels, rightChannels, outLeft, outRight) {
988
+ if (leftChannels.length !== rightChannels.length) {
989
+ throw new Error("leftChannels and rightChannels must have the same length.");
990
+ }
991
+ if (outLeft.length !== outRight.length) {
992
+ throw new Error("outLeft and outRight must have the same length.");
993
+ }
994
+ this.mixer.processStereoInto(leftChannels, rightChannels, outLeft, outRight);
995
+ }
996
+ /**
997
+ * Create reusable WASM-heap input/output views for realtime-style processing.
998
+ *
999
+ * Fill `leftInputs[i]` / `rightInputs[i]`, call `process()`, then read
1000
+ * `outLeft` / `outRight`. The views are owned by this mixer and become invalid
1001
+ * after {@link delete}.
1002
+ */
1003
+ createRealtimeBuffer() {
1004
+ const stripCount = this.stripCount();
1005
+ const leftInputs = [];
1006
+ const rightInputs = [];
1007
+ for (let index = 0; index < stripCount; index++) {
1008
+ leftInputs.push(this.mixer.inputLeftView(index));
1009
+ rightInputs.push(this.mixer.inputRightView(index));
1010
+ }
1011
+ const outLeft = this.mixer.outputLeftView();
1012
+ const outRight = this.mixer.outputRightView();
1013
+ return {
1014
+ leftInputs,
1015
+ rightInputs,
1016
+ outLeft,
1017
+ outRight,
1018
+ process: (numSamples = outLeft.length) => this.mixer.processPreparedStereo(numSamples)
1019
+ };
1020
+ }
1021
+ /** Number of strips in the mixer (e.g. strips loaded from the scene). */
1022
+ stripCount() {
1023
+ return this.mixer.stripCount();
1024
+ }
1025
+ /**
1026
+ * Schedule sample-accurate insert-parameter automation on a strip's insert.
1027
+ *
1028
+ * @param stripIndex - Strip index in `[0, stripCount())`
1029
+ * @param insertIndex - Index into the strip's combined insert sequence
1030
+ * (`[pre-inserts... post-inserts...]`)
1031
+ * @param paramId - Processor-specific parameter id
1032
+ * @param samplePos - Absolute samples from the start of processing (the mixer
1033
+ * advances an internal position from 0 on the first {@link processStereo}
1034
+ * call; recompiling resets it to 0)
1035
+ * @param value - Target parameter value
1036
+ * @param curve - Interpolation curve (default: `'linear'`)
1037
+ * @throws If the strip index is out of range or the schedule call fails
1038
+ * (unknown curve, out-of-range insert index, or full event lane)
1039
+ */
1040
+ scheduleInsertAutomation(stripIndex, insertIndex, paramId, samplePos, value, curve = "linear") {
1041
+ this.mixer.scheduleInsertAutomation(
1042
+ stripIndex,
1043
+ insertIndex,
1044
+ paramId,
1045
+ samplePos,
1046
+ value,
1047
+ automationCurveCode(curve)
1048
+ );
1049
+ }
1050
+ /**
1051
+ * Resolve a strip's index in `[0, stripCount())` from its scene id, or `null`
1052
+ * when no strip with that id exists (matches the Node binding's `number | null`).
1053
+ */
1054
+ stripById(id) {
1055
+ const index = this.mixer.stripById(id);
1056
+ return index < 0 ? null : index;
1057
+ }
1058
+ /**
1059
+ * Add a bus to the mixer topology. `role` is one of `'master'`, `'aux'`, or
1060
+ * `'submix'` (defaults to `'aux'`). Marks the routing graph dirty; call
1061
+ * {@link compile} (or {@link processStereo}) to rebuild.
1062
+ */
1063
+ addBus(id, role = "aux") {
1064
+ this.mixer.addBus(id, role);
1065
+ }
1066
+ /** Remove a bus by id. Marks the routing graph dirty. */
1067
+ removeBus(id) {
1068
+ this.mixer.removeBus(id);
1069
+ }
1070
+ /** Number of buses in the mixer topology. */
1071
+ busCount() {
1072
+ return this.mixer.busCount();
1073
+ }
1074
+ /**
1075
+ * Add a VCA group with the given gain offset (dB). `members` is a list of
1076
+ * strip ids governed by the group (may be empty).
1077
+ */
1078
+ addVcaGroup(id, gainDb = 0, members = []) {
1079
+ this.mixer.addVcaGroup(id, gainDb, members);
1080
+ }
1081
+ /** Remove a VCA group by id. */
1082
+ removeVcaGroup(id) {
1083
+ this.mixer.removeVcaGroup(id);
1084
+ }
1085
+ /** Number of VCA groups in the mixer topology. */
1086
+ vcaGroupCount() {
1087
+ return this.mixer.vcaGroupCount();
1088
+ }
1089
+ /**
1090
+ * Set a strip's solo state. Takes effect on the next process without a
1091
+ * graph recompile.
1092
+ */
1093
+ setSoloed(stripIndex, soloed) {
1094
+ this.mixer.setSoloed(stripIndex, soloed);
1095
+ }
1096
+ /**
1097
+ * Mark a strip solo-safe so it is never implied-muted by another strip's
1098
+ * solo. Takes effect on the next process without a graph recompile.
1099
+ */
1100
+ setSoloSafe(stripIndex, soloSafe) {
1101
+ this.mixer.setSoloSafe(stripIndex, soloSafe);
1102
+ }
1103
+ /** Invert the polarity of the left and/or right channel of a strip. */
1104
+ setPolarityInvert(stripIndex, invertLeft, invertRight) {
1105
+ this.mixer.setPolarityInvert(stripIndex, invertLeft, invertRight);
1106
+ }
1107
+ /** Set the strip's pan law. */
1108
+ setPanLaw(stripIndex, panLaw) {
1109
+ this.mixer.setPanLaw(stripIndex, panLawCode(panLaw));
1110
+ }
1111
+ /**
1112
+ * Set a per-strip channel delay in samples. This changes the strip's reported
1113
+ * latency; recompile to re-run latency compensation.
1114
+ */
1115
+ setChannelDelaySamples(stripIndex, delaySamples) {
1116
+ this.mixer.setChannelDelaySamples(stripIndex, delaySamples);
1117
+ }
1118
+ /** Set the strip's live VCA gain offset in dB (not persisted to the scene). */
1119
+ setVcaOffsetDb(stripIndex, offsetDb) {
1120
+ this.mixer.setVcaOffsetDb(stripIndex, offsetDb);
1121
+ }
1122
+ /** Set independent left/right pan positions (dual-pan mode). */
1123
+ setDualPan(stripIndex, leftPan, rightPan) {
1124
+ this.mixer.setDualPan(stripIndex, leftPan, rightPan);
1125
+ }
1126
+ /**
1127
+ * Add a send to a strip after construction.
1128
+ *
1129
+ * @param stripIndex - Strip index in `[0, stripCount())`
1130
+ * @param id - Send id
1131
+ * @param destinationBusId - Destination bus id
1132
+ * @param sendDb - Initial send level in dB
1133
+ * @param timing - `'preFader'` or `'postFader'` (default: `'postFader'`)
1134
+ * @returns The new send's index
1135
+ */
1136
+ addSend(stripIndex, id, destinationBusId, sendDb, timing = "postFader") {
1137
+ return this.mixer.addSend(stripIndex, id, destinationBusId, sendDb, sendTimingCode(timing));
1138
+ }
1139
+ /** Set the send level (in dB) for an existing send by index. */
1140
+ setSendDb(stripIndex, sendIndex, sendDb) {
1141
+ this.mixer.setSendDb(stripIndex, sendIndex, sendDb);
1142
+ }
1143
+ /**
1144
+ * Read a strip's meter snapshot at the given tap point.
1145
+ *
1146
+ * @param stripIndex - Strip index in `[0, stripCount())`
1147
+ * @param tap - `'preFader'` or `'postFader'` (default: `'postFader'`)
1148
+ */
1149
+ meterTap(stripIndex, tap = "postFader") {
1150
+ return this.mixer.meterTap(stripIndex, meterTapCode(tap));
1151
+ }
1152
+ /**
1153
+ * Read a strip's meter snapshot. Alias of {@link meterTap}, provided for
1154
+ * cross-binding (Node/Python) parity.
1155
+ *
1156
+ * @param stripIndex - Strip index in `[0, stripCount())`
1157
+ * @param tap - `'preFader'` or `'postFader'` (default: `'postFader'`)
1158
+ */
1159
+ stripMeter(stripIndex, tap = "postFader") {
1160
+ return this.mixer.stripMeter(stripIndex, meterTapCode(tap));
1161
+ }
1162
+ /**
1163
+ * Schedule sample-accurate fader automation on a strip.
1164
+ *
1165
+ * @param stripIndex - Strip index in `[0, stripCount())`
1166
+ * @param samplePos - Absolute samples from the start of processing
1167
+ * @param faderDb - Target fader level in dB
1168
+ * @param curve - Interpolation curve (default: `'linear'`)
1169
+ */
1170
+ scheduleFaderAutomation(stripIndex, samplePos, faderDb, curve = "linear") {
1171
+ this.mixer.scheduleFaderAutomation(stripIndex, samplePos, faderDb, automationCurveCode(curve));
1172
+ }
1173
+ /**
1174
+ * Schedule sample-accurate pan automation on a strip.
1175
+ *
1176
+ * @param stripIndex - Strip index in `[0, stripCount())`
1177
+ * @param samplePos - Absolute samples from the start of processing
1178
+ * @param pan - Target pan position
1179
+ * @param curve - Interpolation curve (default: `'linear'`)
1180
+ */
1181
+ schedulePanAutomation(stripIndex, samplePos, pan, curve = "linear") {
1182
+ this.mixer.schedulePanAutomation(stripIndex, samplePos, pan, automationCurveCode(curve));
1183
+ }
1184
+ /**
1185
+ * Schedule sample-accurate width automation on a strip.
1186
+ *
1187
+ * @param stripIndex - Strip index in `[0, stripCount())`
1188
+ * @param samplePos - Absolute samples from the start of processing
1189
+ * @param width - Target stereo width
1190
+ * @param curve - Interpolation curve (default: `'linear'`)
1191
+ */
1192
+ scheduleWidthAutomation(stripIndex, samplePos, width, curve = "linear") {
1193
+ this.mixer.scheduleWidthAutomation(stripIndex, samplePos, width, automationCurveCode(curve));
1194
+ }
1195
+ /**
1196
+ * Schedule sample-accurate send-level automation on a strip's send.
1197
+ *
1198
+ * @param stripIndex - Strip index in `[0, stripCount())`
1199
+ * @param sendIndex - Send index in the strip's add order
1200
+ * @param samplePos - Absolute samples from the start of processing
1201
+ * @param db - Target send level in dB
1202
+ * @param curve - Interpolation curve (default: `'linear'`)
1203
+ */
1204
+ scheduleSendAutomation(stripIndex, sendIndex, samplePos, db, curve = "linear") {
1205
+ this.mixer.scheduleSendAutomation(
1206
+ stripIndex,
1207
+ sendIndex,
1208
+ samplePos,
1209
+ db,
1210
+ automationCurveCode(curve)
1211
+ );
1212
+ }
1213
+ /**
1214
+ * Read up to `maxPoints` of a strip's most recent goniometer samples
1215
+ * (oldest to newest).
1216
+ */
1217
+ readGoniometerLatest(stripIndex, maxPoints) {
1218
+ return this.mixer.readGoniometerLatest(stripIndex, maxPoints);
1219
+ }
1220
+ /** Serialize the current scene (strips, buses, sends, connections) to JSON. */
1221
+ toSceneJson() {
1222
+ return this.mixer.toSceneJson();
1223
+ }
1224
+ /** Release the underlying WASM object. Safe to call only once. */
1225
+ delete() {
1226
+ this.mixer.delete();
1227
+ }
1228
+ /** Alias for {@link delete}, provided for cross-binding (Node) compatibility. */
1229
+ destroy() {
1230
+ this.delete();
1231
+ }
1232
+ };
366
1233
  function trim(samples, sampleRate, thresholdDb = -60) {
367
1234
  if (!module) {
368
1235
  throw new Error("Module not initialized. Call init() first.");
@@ -393,6 +1260,51 @@ function mfcc(samples, sampleRate, nFft = 2048, hopLength = 512, nMels = 128, nM
393
1260
  }
394
1261
  return module.mfcc(samples, sampleRate, nFft, hopLength, nMels, nMfcc);
395
1262
  }
1263
+ function melToStft(melPower, nMels, nFrames, sampleRate, nFft = 2048, hopLength = 512, fmin = 0, fmax = 0) {
1264
+ if (!module) {
1265
+ throw new Error("Module not initialized. Call init() first.");
1266
+ }
1267
+ return module.melToStft(melPower, nMels, nFrames, sampleRate, nFft, hopLength, fmin, fmax);
1268
+ }
1269
+ function melToAudio(melPower, nMels, nFrames, sampleRate, nFft = 2048, hopLength = 512, nIter = 32, fmin = 0, fmax = 0) {
1270
+ if (!module) {
1271
+ throw new Error("Module not initialized. Call init() first.");
1272
+ }
1273
+ return module.melToAudio(
1274
+ melPower,
1275
+ nMels,
1276
+ nFrames,
1277
+ sampleRate,
1278
+ nFft,
1279
+ hopLength,
1280
+ nIter,
1281
+ fmin,
1282
+ fmax
1283
+ );
1284
+ }
1285
+ function mfccToMel(mfccCoefficients, nMfcc, nFrames, nMels = 128) {
1286
+ if (!module) {
1287
+ throw new Error("Module not initialized. Call init() first.");
1288
+ }
1289
+ return module.mfccToMel(mfccCoefficients, nMfcc, nFrames, nMels);
1290
+ }
1291
+ function mfccToAudio(mfccCoefficients, nMfcc, nFrames, nMels, sampleRate, nFft = 2048, hopLength = 512, nIter = 32, fmin = 0, fmax = 0) {
1292
+ if (!module) {
1293
+ throw new Error("Module not initialized. Call init() first.");
1294
+ }
1295
+ return module.mfccToAudio(
1296
+ mfccCoefficients,
1297
+ nMfcc,
1298
+ nFrames,
1299
+ nMels,
1300
+ sampleRate,
1301
+ nFft,
1302
+ hopLength,
1303
+ nIter,
1304
+ fmin,
1305
+ fmax
1306
+ );
1307
+ }
396
1308
  function chroma(samples, sampleRate, nFft = 2048, hopLength = 512) {
397
1309
  if (!module) {
398
1310
  throw new Error("Module not initialized. Call init() first.");
@@ -603,17 +1515,89 @@ function tonnetz(chromagram, nChroma, nFrames) {
603
1515
  }
604
1516
  return module.tonnetz(chromagram, nChroma, nFrames);
605
1517
  }
606
- function tempogram(onsetEnvelope, sampleRate, hopLength = 512, winLength = 384) {
1518
+ function tempogram(onsetEnvelope2, sampleRate, hopLength = 512, winLength = 384, mode = "autocorrelation") {
607
1519
  if (!module) {
608
1520
  throw new Error("Module not initialized. Call init() first.");
609
1521
  }
610
- return module.tempogram(onsetEnvelope, sampleRate, hopLength, winLength);
1522
+ return module.tempogram(onsetEnvelope2, sampleRate, hopLength, winLength, mode);
611
1523
  }
612
- function plp(onsetEnvelope, sampleRate, hopLength = 512, tempoMin = 30, tempoMax = 300, winLength = 384) {
1524
+ function cyclicTempogram(onsetEnvelope2, sampleRate, hopLength = 512, winLength = 384, bpmMin = 60, nBins = 60) {
613
1525
  if (!module) {
614
1526
  throw new Error("Module not initialized. Call init() first.");
615
1527
  }
616
- return module.plp(onsetEnvelope, sampleRate, hopLength, tempoMin, tempoMax, winLength);
1528
+ return module.cyclicTempogram(onsetEnvelope2, sampleRate, hopLength, winLength, bpmMin, nBins);
1529
+ }
1530
+ function plp(onsetEnvelope2, sampleRate, hopLength = 512, tempoMin = 30, tempoMax = 300, winLength = 384) {
1531
+ if (!module) {
1532
+ throw new Error("Module not initialized. Call init() first.");
1533
+ }
1534
+ return module.plp(onsetEnvelope2, sampleRate, hopLength, tempoMin, tempoMax, winLength);
1535
+ }
1536
+ function nnlsChroma(samples, sampleRate = 22050) {
1537
+ if (!module) {
1538
+ throw new Error("Module not initialized. Call init() first.");
1539
+ }
1540
+ return module.nnlsChroma(samples, sampleRate);
1541
+ }
1542
+ function cqt(samples, sampleRate = 22050, hopLength = 512, fmin = 32.70319566257483, nBins = 84, binsPerOctave = 12) {
1543
+ if (!module) {
1544
+ throw new Error("Module not initialized. Call init() first.");
1545
+ }
1546
+ return module.cqt(samples, sampleRate, hopLength, fmin, nBins, binsPerOctave);
1547
+ }
1548
+ function vqt(samples, sampleRate = 22050, hopLength = 512, fmin = 32.70319566257483, nBins = 84, binsPerOctave = 12, gamma = 0) {
1549
+ if (!module) {
1550
+ throw new Error("Module not initialized. Call init() first.");
1551
+ }
1552
+ return module.vqt(samples, sampleRate, hopLength, fmin, nBins, binsPerOctave, gamma);
1553
+ }
1554
+ function analyzeSections(samples, sampleRate = 22050, nFft = 2048, hopLength = 512, minSectionSec = 8) {
1555
+ if (!module) {
1556
+ throw new Error("Module not initialized. Call init() first.");
1557
+ }
1558
+ return module.analyzeSections(samples, sampleRate, nFft, hopLength, minSectionSec).map((s) => ({ ...s, type: s.type }));
1559
+ }
1560
+ function analyzeMelody(samples, sampleRate = 22050, fmin = 65, fmax = 2093, frameLength = 2048, hopLength = 512, threshold = 0.1) {
1561
+ if (!module) {
1562
+ throw new Error("Module not initialized. Call init() first.");
1563
+ }
1564
+ return module.analyzeMelody(samples, sampleRate, fmin, fmax, frameLength, hopLength, threshold);
1565
+ }
1566
+ function onsetEnvelope(samples, sampleRate = 22050, nFft = 2048, hopLength = 512, nMels = 128) {
1567
+ if (!module) {
1568
+ throw new Error("Module not initialized. Call init() first.");
1569
+ }
1570
+ return module.onsetEnvelope(samples, sampleRate, nFft, hopLength, nMels);
1571
+ }
1572
+ function fourierTempogram(onsetEnvelope2, sampleRate = 22050, hopLength = 512, winLength = 384) {
1573
+ if (!module) {
1574
+ throw new Error("Module not initialized. Call init() first.");
1575
+ }
1576
+ return module.fourierTempogram(onsetEnvelope2, sampleRate, hopLength, winLength);
1577
+ }
1578
+ function tempogramRatio(tempogramData, winLength = 384, sampleRate = 22050, hopLength = 512) {
1579
+ if (!module) {
1580
+ throw new Error("Module not initialized. Call init() first.");
1581
+ }
1582
+ return module.tempogramRatio(tempogramData, winLength, sampleRate, hopLength);
1583
+ }
1584
+ function lufs(samples, sampleRate = 22050) {
1585
+ if (!module) {
1586
+ throw new Error("Module not initialized. Call init() first.");
1587
+ }
1588
+ return module.lufs(samples, sampleRate);
1589
+ }
1590
+ function momentaryLufs(samples, sampleRate = 22050) {
1591
+ if (!module) {
1592
+ throw new Error("Module not initialized. Call init() first.");
1593
+ }
1594
+ return module.momentaryLufs(samples, sampleRate);
1595
+ }
1596
+ function shortTermLufs(samples, sampleRate = 22050) {
1597
+ if (!module) {
1598
+ throw new Error("Module not initialized. Call init() first.");
1599
+ }
1600
+ return module.shortTermLufs(samples, sampleRate);
617
1601
  }
618
1602
  function resample(samples, srcSr, targetSr) {
619
1603
  if (!module) {
@@ -650,8 +1634,11 @@ var Audio = class _Audio {
650
1634
  detectBpm() {
651
1635
  return detectBpm(this._samples, this._sampleRate);
652
1636
  }
653
- detectKey() {
654
- return detectKey(this._samples, this._sampleRate);
1637
+ detectKey(options = {}) {
1638
+ return detectKey(this._samples, this._sampleRate, options);
1639
+ }
1640
+ detectKeyCandidates(options = {}) {
1641
+ return detectKeyCandidates(this._samples, this._sampleRate, options);
655
1642
  }
656
1643
  detectOnsets() {
657
1644
  return detectOnsets(this._samples, this._sampleRate);
@@ -659,6 +1646,12 @@ var Audio = class _Audio {
659
1646
  detectBeats() {
660
1647
  return detectBeats(this._samples, this._sampleRate);
661
1648
  }
1649
+ detectDownbeats() {
1650
+ return detectDownbeats(this._samples, this._sampleRate);
1651
+ }
1652
+ detectChords(options = {}) {
1653
+ return detectChords(this._samples, this._sampleRate, options);
1654
+ }
662
1655
  analyze() {
663
1656
  return analyze(this._samples, this._sampleRate);
664
1657
  }
@@ -681,6 +1674,15 @@ var Audio = class _Audio {
681
1674
  pitchShift(semitones) {
682
1675
  return pitchShift(this._samples, this._sampleRate, semitones);
683
1676
  }
1677
+ pitchCorrectToMidi(currentMidi, targetMidi) {
1678
+ return pitchCorrectToMidi(this._samples, this._sampleRate, currentMidi, targetMidi);
1679
+ }
1680
+ noteStretch(onsetSample, offsetSample, stretchRatio) {
1681
+ return noteStretch(this._samples, this._sampleRate, onsetSample, offsetSample, stretchRatio);
1682
+ }
1683
+ voiceChange(pitchSemitones, formantFactor) {
1684
+ return voiceChange(this._samples, this._sampleRate, pitchSemitones, formantFactor);
1685
+ }
684
1686
  normalize(targetDb = 0) {
685
1687
  return normalize(this._samples, this._sampleRate, targetDb);
686
1688
  }
@@ -715,6 +1717,21 @@ var Audio = class _Audio {
715
1717
  chroma(nFft = 2048, hopLength = 512) {
716
1718
  return chroma(this._samples, this._sampleRate, nFft, hopLength);
717
1719
  }
1720
+ nnlsChroma() {
1721
+ return nnlsChroma(this._samples, this._sampleRate);
1722
+ }
1723
+ onsetEnvelope(nFft = 2048, hopLength = 512, nMels = 128) {
1724
+ return onsetEnvelope(this._samples, this._sampleRate, nFft, hopLength, nMels);
1725
+ }
1726
+ lufs() {
1727
+ return lufs(this._samples, this._sampleRate);
1728
+ }
1729
+ momentaryLufs() {
1730
+ return momentaryLufs(this._samples, this._sampleRate);
1731
+ }
1732
+ shortTermLufs() {
1733
+ return shortTermLufs(this._samples, this._sampleRate);
1734
+ }
718
1735
  spectralCentroid(nFft = 2048, hopLength = 512) {
719
1736
  return spectralCentroid(this._samples, this._sampleRate, nFft, hopLength);
720
1737
  }
@@ -761,16 +1778,64 @@ var StreamAnalyzer = class {
761
1778
  if (!module) {
762
1779
  throw new Error("Module not initialized. Call init() first.");
763
1780
  }
764
- this.analyzer = new module.StreamAnalyzer(
1781
+ const wasmModule = module;
1782
+ const args = [
765
1783
  config.sampleRate,
766
1784
  config.nFft ?? 2048,
767
1785
  config.hopLength ?? 512,
768
1786
  config.nMels ?? 128,
1787
+ config.fmin ?? 0,
1788
+ config.fmax ?? 0,
1789
+ config.tuningRefHz ?? 440,
1790
+ config.computeMagnitude ?? true,
769
1791
  config.computeMel ?? true,
770
1792
  config.computeChroma ?? true,
771
1793
  config.computeOnset ?? true,
772
- config.emitEveryNFrames ?? 1
773
- );
1794
+ config.computeSpectral ?? true,
1795
+ config.emitEveryNFrames ?? 1,
1796
+ config.magnitudeDownsample ?? 1,
1797
+ config.keyUpdateIntervalSec ?? 5,
1798
+ config.bpmUpdateIntervalSec ?? 10,
1799
+ config.window ?? 0,
1800
+ config.outputFormat ?? 0
1801
+ ];
1802
+ const isArityError = (error) => {
1803
+ const message = String(error?.message ?? error);
1804
+ return message.includes("invalid number of parameters");
1805
+ };
1806
+ const createLegacy = () => {
1807
+ const LegacyStreamAnalyzer = wasmModule.StreamAnalyzer;
1808
+ return new LegacyStreamAnalyzer(
1809
+ args[0],
1810
+ args[1],
1811
+ args[2],
1812
+ args[3],
1813
+ args[8],
1814
+ args[9],
1815
+ args[10],
1816
+ args[12]
1817
+ );
1818
+ };
1819
+ const hasExtendedConfig = config.fmin !== void 0 || config.fmax !== void 0 || config.tuningRefHz !== void 0 || config.computeMagnitude !== void 0 || config.computeSpectral !== void 0 || config.magnitudeDownsample !== void 0 || config.keyUpdateIntervalSec !== void 0 || config.bpmUpdateIntervalSec !== void 0 || config.window !== void 0 || config.outputFormat !== void 0;
1820
+ if (hasExtendedConfig) {
1821
+ try {
1822
+ this.analyzer = new wasmModule.StreamAnalyzer(...args);
1823
+ } catch (error) {
1824
+ if (!isArityError(error)) {
1825
+ throw error;
1826
+ }
1827
+ this.analyzer = createLegacy();
1828
+ }
1829
+ } else {
1830
+ try {
1831
+ this.analyzer = createLegacy();
1832
+ } catch (error) {
1833
+ if (!isArityError(error)) {
1834
+ throw error;
1835
+ }
1836
+ this.analyzer = new wasmModule.StreamAnalyzer(...args);
1837
+ }
1838
+ }
774
1839
  }
775
1840
  /**
776
1841
  * Process audio samples.
@@ -804,6 +1869,12 @@ var StreamAnalyzer = class {
804
1869
  readFrames(maxFrames) {
805
1870
  return this.analyzer.readFramesSoa(maxFrames);
806
1871
  }
1872
+ readFramesU8(maxFrames) {
1873
+ return this.analyzer.readFramesU8(maxFrames);
1874
+ }
1875
+ readFramesI16(maxFrames) {
1876
+ return this.analyzer.readFramesI16(maxFrames);
1877
+ }
807
1878
  /**
808
1879
  * Reset the analyzer state.
809
1880
  *
@@ -833,6 +1904,7 @@ var StreamAnalyzer = class {
833
1904
  chordRoot: s.estimate.chordRoot,
834
1905
  chordQuality: s.estimate.chordQuality,
835
1906
  chordConfidence: s.estimate.chordConfidence,
1907
+ chordStartTime: s.estimate.chordStartTime,
836
1908
  chordProgression: s.estimate.chordProgression.map((c) => ({
837
1909
  root: c.root,
838
1910
  quality: c.quality,
@@ -925,25 +1997,42 @@ var StreamAnalyzer = class {
925
1997
  export {
926
1998
  Audio,
927
1999
  ChordQuality,
2000
+ EXPECTED_ENGINE_ABI_VERSION,
2001
+ KeyProfile,
2002
+ Mixer,
928
2003
  Mode,
929
2004
  PitchClass as Pitch,
930
2005
  PitchClass,
2006
+ RealtimeEngine,
931
2007
  SectionType,
932
2008
  StreamAnalyzer,
2009
+ StreamingEqualizer,
933
2010
  StreamingMasteringChain,
934
2011
  amplitudeToDb,
935
2012
  analyze,
2013
+ analyzeImpulseResponse,
2014
+ analyzeMelody,
2015
+ analyzeSections,
936
2016
  analyzeWithProgress,
937
2017
  chroma,
2018
+ cqt,
2019
+ cyclicTempogram,
938
2020
  dbToAmplitude,
939
2021
  dbToPower,
940
2022
  deemphasis,
2023
+ detectAcoustic,
941
2024
  detectBeats,
942
2025
  detectBpm,
2026
+ detectChords,
2027
+ detectDownbeats,
943
2028
  detectKey,
2029
+ detectKeyCandidates,
944
2030
  detectOnsets,
2031
+ engineAbiVersion,
2032
+ engineCapabilities,
945
2033
  fixFrames,
946
2034
  fixLength,
2035
+ fourierTempogram,
947
2036
  frameSignal,
948
2037
  framesToSamples,
949
2038
  framesToTime,
@@ -954,9 +2043,12 @@ export {
954
2043
  hzToNote,
955
2044
  init,
956
2045
  isInitialized,
2046
+ lufs,
957
2047
  masterAudio,
958
2048
  masterAudioStereo,
959
2049
  mastering,
2050
+ masteringAssistantSuggest,
2051
+ masteringAudioProfile,
960
2052
  masteringChain,
961
2053
  masteringChainStereo,
962
2054
  masteringChainStereoWithProgress,
@@ -971,16 +2063,30 @@ export {
971
2063
  masteringProcessorNames,
972
2064
  masteringStereoAnalysisNames,
973
2065
  masteringStereoAnalyze,
2066
+ masteringStreamingPreview,
974
2067
  melSpectrogram,
2068
+ melToAudio,
975
2069
  melToHz,
2070
+ melToStft,
976
2071
  mfcc,
2072
+ mfccToAudio,
2073
+ mfccToMel,
977
2074
  midiToHz,
2075
+ mixStereo,
2076
+ mixerScenePresetJson,
2077
+ mixingScenePresetJson,
2078
+ mixingScenePresetNames,
2079
+ momentaryLufs,
2080
+ nnlsChroma,
978
2081
  normalize,
2082
+ noteStretch,
979
2083
  noteToHz,
2084
+ onsetEnvelope,
980
2085
  padCenter,
981
2086
  pcen,
982
2087
  peakPick,
983
2088
  percussive,
2089
+ pitchCorrectToMidi,
984
2090
  pitchPyin,
985
2091
  pitchShift,
986
2092
  pitchYin,
@@ -990,6 +2096,7 @@ export {
990
2096
  resample,
991
2097
  rmsEnergy,
992
2098
  samplesToFrames,
2099
+ shortTermLufs,
993
2100
  spectralBandwidth,
994
2101
  spectralCentroid,
995
2102
  spectralFlatness,
@@ -998,6 +2105,7 @@ export {
998
2105
  stft,
999
2106
  stftDb,
1000
2107
  tempogram,
2108
+ tempogramRatio,
1001
2109
  timeStretch,
1002
2110
  timeToFrames,
1003
2111
  tonnetz,
@@ -1005,6 +2113,8 @@ export {
1005
2113
  trimSilence,
1006
2114
  vectorNormalize,
1007
2115
  version,
2116
+ voiceChange,
2117
+ vqt,
1008
2118
  zeroCrossingRate
1009
2119
  };
1010
2120
  //# sourceMappingURL=index.js.map