@libraz/libsonare 1.5.4 → 1.5.5

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
@@ -200,6 +200,10 @@ function assertSampleRate(fnName, sampleRate) {
200
200
  );
201
201
  }
202
202
  }
203
+ function validateAudioBuffer(samples, sampleRate) {
204
+ assertSamples("Audio.fromBuffer", samples, true);
205
+ assertSampleRate("Audio.fromBuffer", sampleRate);
206
+ }
203
207
  function assertNonNegativeInteger(fnName, value, argName) {
204
208
  if (!Number.isInteger(value) || value < 0) {
205
209
  throw new RangeError(`${fnName}: ${argName} must be a non-negative integer`);
@@ -322,7 +326,7 @@ function noteStretch(samples, sampleRate = 22050, options = {}) {
322
326
  request.samples,
323
327
  request.sampleRate ?? 22050,
324
328
  request.onsetSample ?? 0,
325
- request.offsetSample ?? 0,
329
+ request.offsetSample ?? request.samples.length,
326
330
  request.stretchRatio ?? 1
327
331
  );
328
332
  }
@@ -333,7 +337,7 @@ function noteMove(samples, sampleRate = 22050, options = {}) {
333
337
  request.samples,
334
338
  request.sampleRate ?? 22050,
335
339
  request.onsetSample ?? 0,
336
- request.offsetSample ?? 0,
340
+ request.offsetSample ?? request.samples.length,
337
341
  request.targetOnsetSample ?? 0
338
342
  );
339
343
  }
@@ -405,22 +409,6 @@ function flattenChainConfig(config) {
405
409
  }
406
410
  };
407
411
  walk(config, "");
408
- const aliases = {
409
- "repair.denoise": "repair.denoise.enabled",
410
- "repair.nFft": "repair.denoise.nFft",
411
- "repair.hopLength": "repair.denoise.hopLength",
412
- "repair.ddAlpha": "repair.denoise.ddAlpha",
413
- "repair.gainFloor": "repair.denoise.gainFloor",
414
- "eq.tiltDb": "eq.tilt.tiltDb",
415
- "eq.pivotHz": "eq.tilt.pivotHz"
416
- };
417
- for (const [legacy, canonical] of Object.entries(aliases)) {
418
- const value = out[legacy];
419
- if (value !== void 0) {
420
- out[canonical] = value;
421
- delete out[legacy];
422
- }
423
- }
424
412
  return out;
425
413
  }
426
414
 
@@ -980,7 +968,17 @@ function vectorNormalize(values, normType = 0, threshold = 0) {
980
968
  function pcen(values, nBins = 0, nFrames = 0, options = {}) {
981
969
  if (!(values instanceof Float32Array)) {
982
970
  const r = values;
983
- return pcen(r.values, r.nBins, r.nFrames, r.options);
971
+ const {
972
+ values: requestValues,
973
+ nBins: requestBins,
974
+ nFrames: requestFrames,
975
+ options: legacyOptions,
976
+ ...flatOptions
977
+ } = r;
978
+ return pcen(requestValues, requestBins, requestFrames, {
979
+ ...legacyOptions,
980
+ ...flatOptions
981
+ });
984
982
  }
985
983
  return requireModule8().pcen(values, nBins, nFrames, options);
986
984
  }
@@ -1056,7 +1054,13 @@ function nnlsChroma(samples, sampleRate = 22050, options = {}) {
1056
1054
  return nnlsChroma(samples.samples, samples.sampleRate, samples);
1057
1055
  }
1058
1056
  validateMusicSamples("nnlsChroma", samples, sampleRate, options);
1059
- return requireModule9().nnlsChroma(samples, sampleRate);
1057
+ return requireModule9().nnlsChroma(
1058
+ samples,
1059
+ sampleRate,
1060
+ options.enableStftBlend ?? true,
1061
+ options.stftBlendWeight ?? 0.55,
1062
+ options.stftBlendNFft ?? 4096
1063
+ );
1060
1064
  }
1061
1065
  function cqt(samples, sampleRate = 22050, hopLength = 512, fmin = 32.70319566257483, nBins = 84, binsPerOctave = 12, options = {}) {
1062
1066
  if (!(samples instanceof Float32Array)) {
@@ -1112,7 +1116,7 @@ function hybridCqt(samples, sampleRate = 22050, hopLength = 512, fmin = 32.70319
1112
1116
  validateFrequencyBounds("hybridCqt", fmin);
1113
1117
  return requireModule9().hybridCqt(samples, sampleRate, hopLength, fmin, nBins, binsPerOctave);
1114
1118
  }
1115
- function vqt(samples, sampleRate = 22050, hopLength = 512, fmin = 32.70319566257483, nBins = 84, binsPerOctave = 12, gamma = 0, options = {}) {
1119
+ function vqt(samples, sampleRate = 22050, hopLength = 512, fmin = 32.70319566257483, nBins = 84, binsPerOctave = 12, gamma = -1, options = {}) {
1116
1120
  if (!(samples instanceof Float32Array)) {
1117
1121
  const request = samples;
1118
1122
  return vqt(
@@ -1130,9 +1134,6 @@ function vqt(samples, sampleRate = 22050, hopLength = 512, fmin = 32.70319566257
1130
1134
  validatePositiveIntegers("vqt", { hopLength, nBins, binsPerOctave });
1131
1135
  validateFrequencyBounds("vqt", fmin);
1132
1136
  assertFiniteScalar("vqt", gamma, "gamma");
1133
- if (gamma < 0) {
1134
- throw new RangeError("vqt: gamma must be non-negative");
1135
- }
1136
1137
  return requireModule9().vqt(samples, sampleRate, hopLength, fmin, nBins, binsPerOctave, gamma);
1137
1138
  }
1138
1139
  function validateCqtInverse(fnName, magnitude, nBins, nFrames, sampleRate, hopLength, fmin, binsPerOctave, nIter, options) {
@@ -1188,7 +1189,7 @@ function cqtToAudio(magnitude, nBins = 0, nFrames = 0, sampleRate = 22050, hopLe
1188
1189
  nIter
1189
1190
  );
1190
1191
  }
1191
- function vqtToAudio(magnitude, nBins = 0, nFrames = 0, sampleRate = 22050, hopLength = 512, fmin = 32.70319566257483, binsPerOctave = 12, gamma = 0, nIter = 32, options = {}) {
1192
+ function vqtToAudio(magnitude, nBins = 0, nFrames = 0, sampleRate = 22050, hopLength = 512, fmin = 32.70319566257483, binsPerOctave = 12, gamma = -1, nIter = 32, options = {}) {
1192
1193
  if (!(magnitude instanceof Float32Array)) {
1193
1194
  const request = magnitude;
1194
1195
  return vqtToAudio(
@@ -1217,9 +1218,6 @@ function vqtToAudio(magnitude, nBins = 0, nFrames = 0, sampleRate = 22050, hopLe
1217
1218
  options
1218
1219
  );
1219
1220
  assertFiniteScalar("vqtToAudio", gamma, "gamma");
1220
- if (gamma < 0) {
1221
- throw new RangeError("vqtToAudio: gamma must be non-negative");
1222
- }
1223
1221
  return requireModule9().vqtToAudio(
1224
1222
  magnitude,
1225
1223
  nBins,
@@ -1243,8 +1241,8 @@ function analyzeSections(samples, sampleRate = 22050, options = {}) {
1243
1241
  hopLength: options.hopLength ?? 512
1244
1242
  });
1245
1243
  assertFiniteScalar("analyzeSections", options.minSectionSec ?? 4, "minSectionSec");
1246
- if ((options.minSectionSec ?? 4) <= 0) {
1247
- throw new RangeError("analyzeSections: minSectionSec must be positive");
1244
+ if ((options.minSectionSec ?? 4) < 0) {
1245
+ throw new RangeError("analyzeSections: minSectionSec must be non-negative");
1248
1246
  }
1249
1247
  const sections = requireModule9().analyzeSections(
1250
1248
  samples,
@@ -1394,7 +1392,7 @@ function shortTermLufs(samples, sampleRate = 22050, options = {}) {
1394
1392
  function requireModule10() {
1395
1393
  return getSonareModule();
1396
1394
  }
1397
- function pitchYin(samples, sampleRate = 22050, frameLength = 2048, hopLength = 512, fmin = 65, fmax = 2093, threshold = 0.3, fillNa = false) {
1395
+ function pitchYin(samples, sampleRate = 22050, frameLength = 2048, hopLength = 512, fmin = 65, fmax = 2093, threshold = 0.1, fillNa = false) {
1398
1396
  if (!(samples instanceof Float32Array)) {
1399
1397
  const request = samples;
1400
1398
  return pitchYin(
@@ -1419,7 +1417,7 @@ function pitchYin(samples, sampleRate = 22050, frameLength = 2048, hopLength = 5
1419
1417
  fillNa
1420
1418
  );
1421
1419
  }
1422
- function pitchPyin(samples, sampleRate = 22050, frameLength = 2048, hopLength = 512, fmin = 65, fmax = 2093, threshold = 0.3, fillNa = false) {
1420
+ function pitchPyin(samples, sampleRate = 22050, frameLength = 2048, hopLength = 512, fmin = 65, fmax = 2093, threshold = 0.1, fillNa = false) {
1423
1421
  if (!(samples instanceof Float32Array)) {
1424
1422
  const request = samples;
1425
1423
  return pitchPyin(
@@ -1575,10 +1573,10 @@ function remix(samples, intervals, sampleRate = 22050, alignZeros = false) {
1575
1573
  const intervalsI32 = intervals instanceof Int32Array ? intervals : Int32Array.from(intervals, (v) => Math.trunc(v));
1576
1574
  return requireModule12().remix(samples, intervalsI32, sampleRate, alignZeros);
1577
1575
  }
1578
- function phaseVocoder(samples, rate = 1, sampleRate = 22050, nFft = 2048, hopLength = 512) {
1576
+ function phaseVocoder(samples, sampleRate = 22050, rate = 1, nFft = 2048, hopLength = 512) {
1579
1577
  if (!(samples instanceof Float32Array)) {
1580
1578
  const r = samples;
1581
- return phaseVocoder(r.samples, r.rate, r.sampleRate, r.nFft, r.hopLength);
1579
+ return phaseVocoder(r.samples, r.sampleRate ?? 22050, r.rate, r.nFft, r.hopLength);
1582
1580
  }
1583
1581
  return requireModule12().phaseVocoder(samples, sampleRate, rate, nFft, hopLength);
1584
1582
  }
@@ -1708,7 +1706,7 @@ function stftDb(samples, sampleRate = 22050, nFft = 2048, hopLength = 512, optio
1708
1706
  validatePositiveIntegers2("stftDb", { nFft, hopLength });
1709
1707
  return requireModule13().stftDb(samples, sampleRate, nFft, hopLength);
1710
1708
  }
1711
- function chromaCens(samples, sampleRate = 22050, hopLength = 512, nChroma = 12, options = {}) {
1709
+ function chromaCens(samples, sampleRate = 22050, hopLength = 512, nChroma = 12, binsPerOctave = 36, options = {}) {
1712
1710
  if (!(samples instanceof Float32Array)) {
1713
1711
  const request = samples;
1714
1712
  return chromaCens(
@@ -1716,14 +1714,18 @@ function chromaCens(samples, sampleRate = 22050, hopLength = 512, nChroma = 12,
1716
1714
  request.sampleRate,
1717
1715
  request.hopLength,
1718
1716
  request.nChroma,
1717
+ request.binsPerOctave,
1719
1718
  request
1720
1719
  );
1721
1720
  }
1722
1721
  validateSpectrogramSamples("chromaCens", samples, sampleRate, options);
1723
- validatePositiveIntegers2("chromaCens", { hopLength, nChroma });
1724
- return requireModule13().chromaCens(samples, sampleRate, hopLength, nChroma);
1722
+ validatePositiveIntegers2("chromaCens", { hopLength, nChroma, binsPerOctave });
1723
+ if (binsPerOctave % nChroma !== 0) {
1724
+ throw new RangeError("chromaCens: binsPerOctave must be a multiple of nChroma");
1725
+ }
1726
+ return requireModule13().chromaCens(samples, sampleRate, hopLength, nChroma, binsPerOctave);
1725
1727
  }
1726
- function chromaCqt(samples, sampleRate = 22050, hopLength = 512, nChroma = 12, options = {}) {
1728
+ function chromaCqt(samples, sampleRate = 22050, hopLength = 512, nChroma = 12, binsPerOctave = 36, options = {}) {
1727
1729
  if (!(samples instanceof Float32Array)) {
1728
1730
  const request = samples;
1729
1731
  return chromaCqt(
@@ -1731,12 +1733,16 @@ function chromaCqt(samples, sampleRate = 22050, hopLength = 512, nChroma = 12, o
1731
1733
  request.sampleRate,
1732
1734
  request.hopLength,
1733
1735
  request.nChroma,
1736
+ request.binsPerOctave,
1734
1737
  request
1735
1738
  );
1736
1739
  }
1737
1740
  validateSpectrogramSamples("chromaCqt", samples, sampleRate, options);
1738
- validatePositiveIntegers2("chromaCqt", { hopLength, nChroma });
1739
- return requireModule13().chromaCqt(samples, sampleRate, hopLength, nChroma);
1741
+ validatePositiveIntegers2("chromaCqt", { hopLength, nChroma, binsPerOctave });
1742
+ if (binsPerOctave % nChroma !== 0) {
1743
+ throw new RangeError("chromaCqt: binsPerOctave must be a multiple of nChroma");
1744
+ }
1745
+ return requireModule13().chromaCqt(samples, sampleRate, hopLength, nChroma, binsPerOctave);
1740
1746
  }
1741
1747
  function bassChroma(samples, sampleRate = 22050, hopLength = 512, nChroma = 12, options = {}) {
1742
1748
  if (!(samples instanceof Float32Array)) {
@@ -1870,7 +1876,7 @@ function melToAudio(melPower, nMels = 0, nFrames = 0, sampleRate = 22050, nFft =
1870
1876
  htk
1871
1877
  );
1872
1878
  }
1873
- function mfccToMel(mfccCoefficients, nMfcc = 0, nFrames = 0, nMels = 128, options = {}) {
1879
+ function mfccToMel(mfccCoefficients, nMfcc = 0, nFrames = 0, nMels = 128, lifter = 0, options = {}) {
1874
1880
  if (!(mfccCoefficients instanceof Float32Array)) {
1875
1881
  const request = mfccCoefficients;
1876
1882
  return mfccToMel(
@@ -1878,6 +1884,7 @@ function mfccToMel(mfccCoefficients, nMfcc = 0, nFrames = 0, nMels = 128, option
1878
1884
  request.nMfcc,
1879
1885
  request.nFrames,
1880
1886
  request.nMels,
1887
+ request.lifter,
1881
1888
  request
1882
1889
  );
1883
1890
  }
@@ -1891,9 +1898,9 @@ function mfccToMel(mfccCoefficients, nMfcc = 0, nFrames = 0, nMels = 128, option
1891
1898
  options
1892
1899
  );
1893
1900
  validatePositiveIntegers2("mfccToMel", { nMels });
1894
- return requireModule13().mfccToMel(mfccCoefficients, nMfcc, nFrames, nMels);
1901
+ return requireModule13().mfccToMel(mfccCoefficients, nMfcc, nFrames, nMels, lifter);
1895
1902
  }
1896
- function mfccToAudio(mfccCoefficients, nMfcc = 0, nFrames = 0, nMels = 128, sampleRate = 22050, nFft = 2048, hopLength = 512, fmin = 0, fmax = 0, nIter = 32, htk = false, options = {}) {
1903
+ function mfccToAudio(mfccCoefficients, nMfcc = 0, nFrames = 0, nMels = 128, sampleRate = 22050, nFft = 2048, hopLength = 512, fmin = 0, fmax = 0, nIter = 32, htk = false, lifter = 0, options = {}) {
1897
1904
  if (!(mfccCoefficients instanceof Float32Array)) {
1898
1905
  const request = mfccCoefficients;
1899
1906
  return mfccToAudio(
@@ -1908,6 +1915,7 @@ function mfccToAudio(mfccCoefficients, nMfcc = 0, nFrames = 0, nMels = 128, samp
1908
1915
  request.fmax,
1909
1916
  request.nIter,
1910
1917
  request.htk,
1918
+ request.lifter,
1911
1919
  request
1912
1920
  );
1913
1921
  }
@@ -1934,7 +1942,8 @@ function mfccToAudio(mfccCoefficients, nMfcc = 0, nFrames = 0, nMels = 128, samp
1934
1942
  fmin,
1935
1943
  fmax,
1936
1944
  nIter,
1937
- htk
1945
+ htk,
1946
+ lifter
1938
1947
  );
1939
1948
  }
1940
1949
  function chroma(samples, sampleRate = 22050, nFft = 2048, hopLength = 512, options = {}) {
@@ -2011,6 +2020,23 @@ var SectionType = {
2011
2020
  };
2012
2021
 
2013
2022
  // src/analysis_helpers.ts
2023
+ var PITCH_CLASS_NAMES = [
2024
+ "C",
2025
+ "C#",
2026
+ "D",
2027
+ "D#",
2028
+ "E",
2029
+ "F",
2030
+ "F#",
2031
+ "G",
2032
+ "G#",
2033
+ "A",
2034
+ "A#",
2035
+ "B"
2036
+ ];
2037
+ function pitchClassName(value) {
2038
+ return PITCH_CLASS_NAMES[value] ?? "C";
2039
+ }
2014
2040
  function convertKeyCandidate(wasm) {
2015
2041
  return {
2016
2042
  key: {
@@ -2081,6 +2107,8 @@ function convertChordAnalysisResult(wasm) {
2081
2107
  chords: wasm.chords.map((c) => ({
2082
2108
  root: c.root,
2083
2109
  bass: c.bass,
2110
+ rootName: pitchClassName(c.root),
2111
+ bassName: pitchClassName(c.bass),
2084
2112
  quality: c.quality,
2085
2113
  start: c.start,
2086
2114
  end: c.end,
@@ -2119,6 +2147,8 @@ function convertAnalysisResult(wasm) {
2119
2147
  chords: wasm.chords.map((c) => ({
2120
2148
  root: c.root,
2121
2149
  bass: c.bass,
2150
+ rootName: pitchClassName(c.root),
2151
+ bassName: pitchClassName(c.bass),
2122
2152
  quality: c.quality,
2123
2153
  start: c.start,
2124
2154
  end: c.end,
@@ -2267,7 +2297,7 @@ function chordFunctionalAnalysis(samples, keyRoot, keyMode, sampleRate = 22050,
2267
2297
  function analyze(samples, sampleRate = 22050, options = {}) {
2268
2298
  const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
2269
2299
  validateAnalysisInput("analyze", request.samples, request.sampleRate ?? 22050, request);
2270
- const result = requireModule14().analyze(request.samples, request.sampleRate ?? 22050);
2300
+ const result = requireModule14().analyze(request.samples, request.sampleRate ?? 22050, request);
2271
2301
  return convertAnalysisResult(result);
2272
2302
  }
2273
2303
  function analyzeImpulseResponse(samples, sampleRate = 48e3, nOctaveBands = 6) {
@@ -2441,7 +2471,8 @@ var Audio = class _Audio {
2441
2471
  * Node/Python surfaces).
2442
2472
  */
2443
2473
  static fromBuffer(samples, sampleRate = 48e3) {
2444
- return new _Audio(samples, sampleRate);
2474
+ validateAudioBuffer(samples, sampleRate);
2475
+ return new _Audio(samples.slice(), sampleRate);
2445
2476
  }
2446
2477
  /**
2447
2478
  * Create an Audio instance by decoding audio bytes in memory.
@@ -2640,7 +2671,7 @@ var Audio = class _Audio {
2640
2671
  rmsEnergy(frameLength = 2048, hopLength = 512) {
2641
2672
  return rmsEnergy(this._samples, this._sampleRate, frameLength, hopLength);
2642
2673
  }
2643
- pitchYin(frameLength = 2048, hopLength = 512, fmin = 65, fmax = 2093, threshold = 0.3, fillNa = false) {
2674
+ pitchYin(frameLength = 2048, hopLength = 512, fmin = 65, fmax = 2093, threshold = 0.1, fillNa = false) {
2644
2675
  return pitchYin(
2645
2676
  this._samples,
2646
2677
  this._sampleRate,
@@ -2652,7 +2683,7 @@ var Audio = class _Audio {
2652
2683
  fillNa
2653
2684
  );
2654
2685
  }
2655
- pitchPyin(frameLength = 2048, hopLength = 512, fmin = 65, fmax = 2093, threshold = 0.3, fillNa = false) {
2686
+ pitchPyin(frameLength = 2048, hopLength = 512, fmin = 65, fmax = 2093, threshold = 0.1, fillNa = false) {
2656
2687
  return pitchPyin(
2657
2688
  this._samples,
2658
2689
  this._sampleRate,
@@ -3080,6 +3111,17 @@ function meteringRmsDb(samples, sampleRate = 22050, options = {}) {
3080
3111
  assertSamples("meteringRmsDb", request.samples, request.validate !== false);
3081
3112
  return requireModule15().meteringRmsDb(request.samples, request.sampleRate ?? 22050);
3082
3113
  }
3114
+ function meteringSilenceRatio(samples, sampleRate = 22050, thresholdDb = -45, frameLength = 1024, hopLength = 256, options = {}) {
3115
+ const request = samples instanceof Float32Array ? { samples, sampleRate, thresholdDb, frameLength, hopLength, ...options } : samples;
3116
+ assertSamples("meteringSilenceRatio", request.samples, request.validate !== false);
3117
+ return requireModule15().meteringSilenceRatio(
3118
+ request.samples,
3119
+ request.sampleRate ?? 22050,
3120
+ request.thresholdDb ?? -45,
3121
+ request.frameLength ?? 1024,
3122
+ request.hopLength ?? 256
3123
+ );
3124
+ }
3083
3125
  function meteringCrestFactorDb(samples, sampleRate = 22050, options = {}) {
3084
3126
  const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
3085
3127
  assertSamples("meteringCrestFactorDb", request.samples, request.validate !== false);
@@ -3100,11 +3142,15 @@ function meteringTruePeakDb(samples, sampleRate = 22050, oversampleFactor = 4, o
3100
3142
  function meteringDetectClipping(samples, sampleRate = 22050, options = {}) {
3101
3143
  const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
3102
3144
  assertSamples("meteringDetectClipping", request.samples, request.validate !== false);
3145
+ const minRegionSamples = request.minRegionSamples ?? 1;
3146
+ if (!Number.isInteger(minRegionSamples) || minRegionSamples < 0) {
3147
+ throw new RangeError("meteringDetectClipping: minRegionSamples must be a non-negative integer");
3148
+ }
3103
3149
  return requireModule15().meteringDetectClipping(
3104
3150
  request.samples,
3105
3151
  request.sampleRate ?? 22050,
3106
3152
  request.threshold ?? 0.999,
3107
- request.minRegionSamples ?? 1
3153
+ minRegionSamples
3108
3154
  );
3109
3155
  }
3110
3156
  function meteringDynamicRange(samples, sampleRate = 22050, options = {}) {
@@ -3587,7 +3633,11 @@ var Project = class _Project {
3587
3633
  assertProjectMidiEvents("Project.setMidiEvents", events);
3588
3634
  this.native.setMidiEvents(clipId, events);
3589
3635
  }
3590
- /** Import an in-memory SMF buffer; returns the first added clip id. */
3636
+ /**
3637
+ * Import an in-memory SMF buffer; returns the first added clip id.
3638
+ * Malformed or partially truncated tracks are rejected instead of installing
3639
+ * a silently shortened clip.
3640
+ */
3591
3641
  importSmf(data) {
3592
3642
  return this.native.importSmf(data);
3593
3643
  }
@@ -3624,7 +3674,10 @@ var Project = class _Project {
3624
3674
  setProgramOnChannel(clipId, group, channel, program, bank = -1) {
3625
3675
  this.native.setProgramOnChannel(clipId, group, channel, program, bank);
3626
3676
  }
3627
- /** Destructively bake a MIDI-FX chain into a clip's stored MIDI events. */
3677
+ /**
3678
+ * Destructively bake a MIDI-FX chain into all stored events. Large clips are
3679
+ * drained without truncation; failure leaves the original clip unchanged.
3680
+ */
3628
3681
  bakeMidiFx(clipId, configJson) {
3629
3682
  this.native.bakeMidiFx(clipId, configJson);
3630
3683
  }
@@ -3634,9 +3687,9 @@ var Project = class _Project {
3634
3687
  }
3635
3688
  /**
3636
3689
  * Pre-flight check for hanging / unmatched notes in a MIDI clip: reports
3637
- * whether every note-on has a matching note-off (FIFO per channel+note).
3638
- * Useful before bouncing to catch a stuck note. Throws if `clipId` is unknown
3639
- * or not a MIDI clip.
3690
+ * whether every note-on in the exported half-open playback window has a
3691
+ * matching note-off (FIFO per group+channel+note). Useful before bouncing to
3692
+ * catch a stuck note. Throws if `clipId` is unknown or not a MIDI clip.
3640
3693
  */
3641
3694
  validateMidiNotes(clipId) {
3642
3695
  return this.native.validateMidiNotes(clipId);
@@ -4218,6 +4271,10 @@ var RealtimeEngine = class {
4218
4271
  options.maxValue ?? 1
4219
4272
  );
4220
4273
  }
4274
+ /** Bind a 7/14-bit CC, RPN, or NRPN descriptor to a live parameter. */
4275
+ bindMidiCcBinding(binding) {
4276
+ this.native.bindMidiCcBinding(binding);
4277
+ }
4221
4278
  clearMidiCcBindings() {
4222
4279
  this.native.clearMidiCcBindings();
4223
4280
  }
@@ -4342,6 +4399,7 @@ var RealtimeEngine = class {
4342
4399
  seekPpq(ppq, renderFrame = -1) {
4343
4400
  this.native.seekPpq(ppq, renderFrame);
4344
4401
  }
4402
+ /** Set a finite tempo in the range (0, 100000] BPM. */
4345
4403
  setTempo(bpm) {
4346
4404
  this.native.setTempo(bpm);
4347
4405
  }
@@ -4396,6 +4454,7 @@ var RealtimeEngine = class {
4396
4454
  setLoopFromMarkers(startMarkerId, endMarkerId) {
4397
4455
  this.native.setLoopFromMarkers(startMarkerId, endMarkerId);
4398
4456
  }
4457
+ /** Set a metronome config; click lengths are limited to one second. */
4399
4458
  setMetronome(config) {
4400
4459
  this.native.setMetronome(config);
4401
4460
  }
@@ -4603,6 +4662,7 @@ var RealtimeEngine = class {
4603
4662
  setCaptureSource(source) {
4604
4663
  this.native.setCaptureSource(source);
4605
4664
  }
4665
+ /** Positive values delay capture relative to the punch window. */
4606
4666
  setRecordOffsetSamples(offsetSamples) {
4607
4667
  this.native.setRecordOffsetSamples(offsetSamples);
4608
4668
  }
@@ -4980,7 +5040,10 @@ var Mixer = class _Mixer {
4980
5040
  const module2 = getSonareModule();
4981
5041
  return new _Mixer(module2.createMixerFromSceneJson(json, sampleRate, blockSize), blockSize);
4982
5042
  }
4983
- /** Rebuild and compile the routing graph from the current scene topology. */
5043
+ /**
5044
+ * Rebuild and compile the routing graph without resetting its absolute
5045
+ * automation sample position or queued strip automation.
5046
+ */
4984
5047
  compile() {
4985
5048
  this.mixer.compile();
4986
5049
  }
@@ -5139,6 +5202,10 @@ var Mixer = class _Mixer {
5139
5202
  setVcaGroupGainDb(id, gainDb) {
5140
5203
  this.mixer.setVcaGroupGainDb(id, gainDb);
5141
5204
  }
5205
+ /** Replace an existing VCA group's strip membership. */
5206
+ setVcaGroupMembers(id, members) {
5207
+ this.mixer.setVcaGroupMembers(id, members);
5208
+ }
5142
5209
  /** Remove a VCA group by id. */
5143
5210
  removeVcaGroup(id) {
5144
5211
  this.mixer.removeVcaGroup(id);
@@ -5278,6 +5345,10 @@ var Mixer = class _Mixer {
5278
5345
  }
5279
5346
  return this.mixer.meterTap(stripIndex, meterTapCode(tap));
5280
5347
  }
5348
+ /** Read the post-insert meter for a compiled bus, including master. */
5349
+ busMeter(busId) {
5350
+ return this.mixer.busMeter(busId);
5351
+ }
5281
5352
  /**
5282
5353
  * Schedule sample-accurate fader automation on a strip.
5283
5354
  *
@@ -5637,7 +5708,12 @@ var EQ_PHASE_MODES = {
5637
5708
  var StreamingMasteringChain = class {
5638
5709
  constructor(config) {
5639
5710
  const module2 = getSonareModule();
5640
- this.chain = module2.createStreamingMasteringChain(config);
5711
+ const { loudnessStaticGainDb, loudnessStaticGainPeakDb, ...chainConfig } = config;
5712
+ this.chain = module2.createStreamingMasteringChain({
5713
+ __flatParams: flattenChainConfig(chainConfig),
5714
+ loudnessStaticGainDb,
5715
+ loudnessStaticGainPeakDb
5716
+ });
5641
5717
  }
5642
5718
  /**
5643
5719
  * Initialize processors for the given sample rate and block layout.
@@ -6273,6 +6349,7 @@ export {
6273
6349
  meteringPhaseScope,
6274
6350
  meteringPhaseScopeDecimated,
6275
6351
  meteringRmsDb,
6352
+ meteringSilenceRatio,
6276
6353
  meteringSpectrum,
6277
6354
  meteringSpectrumFrame,
6278
6355
  meteringStereoCorrelation,