@libraz/libsonare 1.5.1 → 1.5.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@libraz/libsonare",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "type": "module",
5
5
  "packageManager": "yarn@4.15.0",
6
6
  "description": "Audio analysis library for music information retrieval",
@@ -180,6 +180,111 @@ export function vqt(
180
180
  return requireModule().vqt(samples, sampleRate, hopLength, fmin, nBins, binsPerOctave, gamma);
181
181
  }
182
182
 
183
+ function validateCqtInverse(
184
+ fnName: string,
185
+ magnitude: Float32Array,
186
+ nBins: number,
187
+ nFrames: number,
188
+ sampleRate: number,
189
+ hopLength: number,
190
+ fmin: number,
191
+ binsPerOctave: number,
192
+ nIter: number,
193
+ options: GuardedOptions,
194
+ ): void {
195
+ assertSampleRate(fnName, sampleRate);
196
+ validatePositiveIntegers(fnName, { nBins, nFrames, hopLength, binsPerOctave, nIter });
197
+ if (nIter > 256) {
198
+ throw new RangeError(`${fnName}: nIter must be at most 256`);
199
+ }
200
+ validateFrequencyBounds(fnName, fmin);
201
+ if (fmin === 0) {
202
+ throw new RangeError(`${fnName}: fmin must be positive`);
203
+ }
204
+ if (magnitude.length !== nBins * nFrames) {
205
+ throw new RangeError(`${fnName}: magnitude length must equal nBins * nFrames`);
206
+ }
207
+ assertSamples(fnName, magnitude, options.validate !== false);
208
+ }
209
+
210
+ /** Reconstruct mono audio from row-major CQT magnitude via Griffin-Lim. */
211
+ export function cqtToAudio(
212
+ magnitude: Float32Array,
213
+ nBins: number,
214
+ nFrames: number,
215
+ sampleRate = 22050,
216
+ hopLength = 512,
217
+ fmin = 32.70319566257483,
218
+ binsPerOctave = 12,
219
+ nIter = 32,
220
+ options: GuardedOptions = {},
221
+ ): Float32Array {
222
+ validateCqtInverse(
223
+ 'cqtToAudio',
224
+ magnitude,
225
+ nBins,
226
+ nFrames,
227
+ sampleRate,
228
+ hopLength,
229
+ fmin,
230
+ binsPerOctave,
231
+ nIter,
232
+ options,
233
+ );
234
+ return requireModule().cqtToAudio(
235
+ magnitude,
236
+ nBins,
237
+ nFrames,
238
+ sampleRate,
239
+ hopLength,
240
+ fmin,
241
+ binsPerOctave,
242
+ nIter,
243
+ );
244
+ }
245
+
246
+ /** Reconstruct mono audio from row-major VQT magnitude via Griffin-Lim. */
247
+ export function vqtToAudio(
248
+ magnitude: Float32Array,
249
+ nBins: number,
250
+ nFrames: number,
251
+ sampleRate = 22050,
252
+ hopLength = 512,
253
+ fmin = 32.70319566257483,
254
+ binsPerOctave = 12,
255
+ gamma = 0,
256
+ nIter = 32,
257
+ options: GuardedOptions = {},
258
+ ): Float32Array {
259
+ validateCqtInverse(
260
+ 'vqtToAudio',
261
+ magnitude,
262
+ nBins,
263
+ nFrames,
264
+ sampleRate,
265
+ hopLength,
266
+ fmin,
267
+ binsPerOctave,
268
+ nIter,
269
+ options,
270
+ );
271
+ assertFiniteScalar('vqtToAudio', gamma, 'gamma');
272
+ if (gamma < 0) {
273
+ throw new RangeError('vqtToAudio: gamma must be non-negative');
274
+ }
275
+ return requireModule().vqtToAudio(
276
+ magnitude,
277
+ nBins,
278
+ nFrames,
279
+ sampleRate,
280
+ hopLength,
281
+ fmin,
282
+ binsPerOctave,
283
+ gamma,
284
+ nIter,
285
+ );
286
+ }
287
+
183
288
  /**
184
289
  * Detect song-structure sections (intro/verse/chorus/...).
185
290
  *
package/src/features.ts CHANGED
@@ -33,6 +33,7 @@ export {
33
33
  analyzeMelody,
34
34
  analyzeSections,
35
35
  cqt,
36
+ cqtToAudio,
36
37
  fourierTempogram,
37
38
  hybridCqt,
38
39
  lufs,
@@ -44,6 +45,7 @@ export {
44
45
  shortTermLufs,
45
46
  tempogramRatio,
46
47
  vqt,
48
+ vqtToAudio,
47
49
  } from './feature_music';
48
50
  export { pitchPyin, pitchYin } from './feature_pitch';
49
51
  export { resample } from './feature_resample';
package/src/index.ts CHANGED
@@ -125,6 +125,7 @@ export {
125
125
  chromaCens,
126
126
  chromaCqt,
127
127
  cqt,
128
+ cqtToAudio,
128
129
  cyclicTempogram,
129
130
  dbToAmplitude,
130
131
  dbToPower,
@@ -193,6 +194,7 @@ export {
193
194
  trimSilence,
194
195
  vectorNormalize,
195
196
  vqt,
197
+ vqtToAudio,
196
198
  zeroCrossingRate,
197
199
  zeroCrossings,
198
200
  } from './features';
@@ -445,6 +447,7 @@ export type {
445
447
  EngineTrackLane,
446
448
  EngineTrackSend,
447
449
  EngineTransportState,
450
+ ExternalMidiEvent,
448
451
  MidiCcBindOptions,
449
452
  } from './realtime_engine';
450
453
  export { EXPECTED_ENGINE_ABI_VERSION, engineCapabilities, RealtimeEngine } from './realtime_engine';
@@ -129,6 +129,16 @@ export interface MasteringProcessorCatalogEntry {
129
129
  realtimeInsertable: boolean;
130
130
  /** True for processors with no mono implementation (stereo-only). */
131
131
  stereoOnly: boolean;
132
+ /**
133
+ * Reported latency for the default 48 kHz / 512-sample probe configuration.
134
+ * Zero for offline processors; configuration-dependent values are estimates.
135
+ */
136
+ latencySamples: number;
137
+ /**
138
+ * Audible decay length for the same default prepared probe. Zero for
139
+ * offline, dry-only, and no-tail processors.
140
+ */
141
+ tailSamples: number;
132
142
  /**
133
143
  * How the mixer wraps the processor on a >2-channel (surround) bus insert:
134
144
  * "multichannel" (one full-buffer call) or "stereoPairOnly" (front L/R pair,
package/src/mixer.ts CHANGED
@@ -515,7 +515,7 @@ export class Mixer {
515
515
  }
516
516
 
517
517
  /**
518
- * Maximum processor tail length (samples) in the compiled mixer graph. Lazily
518
+ * Longest audible serial processor-tail path to the master, in samples. Lazily
519
519
  * compiles the routing graph if the topology is dirty.
520
520
  */
521
521
  tailSamples(): number {
@@ -140,6 +140,7 @@ export interface KeyCandidate {
140
140
  export interface ChordDetectionOptions extends ValidateOptions {
141
141
  minDuration?: number;
142
142
  smoothingWindow?: number;
143
+ /** Final-template correlation threshold in [0, 1]; below it emits Unknown / N.C. */
143
144
  threshold?: number;
144
145
  useTriadsOnly?: boolean;
145
146
  nFft?: number;
@@ -195,6 +195,7 @@ export interface WasmStreamConfigDefaults {
195
195
  emitEveryNFrames: number;
196
196
  magnitudeDownsample: number;
197
197
  maxPendingFrames: number;
198
+ maxProgressionEntries: number;
198
199
  keyUpdateIntervalSec: number;
199
200
  bpmUpdateIntervalSec: number;
200
201
  window: number;
@@ -1906,6 +1907,27 @@ export interface SonareModule {
1906
1907
  binsPerOctave: number,
1907
1908
  gamma: number,
1908
1909
  ) => WasmCqtResult;
1910
+ cqtToAudio: (
1911
+ magnitude: Float32Array,
1912
+ nBins: number,
1913
+ nFrames: number,
1914
+ sampleRate: number,
1915
+ hopLength: number,
1916
+ fmin: number,
1917
+ binsPerOctave: number,
1918
+ nIter: number,
1919
+ ) => Float32Array;
1920
+ vqtToAudio: (
1921
+ magnitude: Float32Array,
1922
+ nBins: number,
1923
+ nFrames: number,
1924
+ sampleRate: number,
1925
+ hopLength: number,
1926
+ fmin: number,
1927
+ binsPerOctave: number,
1928
+ gamma: number,
1929
+ nIter: number,
1930
+ ) => Float32Array;
1909
1931
  analyzeSections: (
1910
1932
  samples: Float32Array,
1911
1933
  sampleRate: number,
@@ -2028,6 +2050,7 @@ export interface SonareModule {
2028
2050
  emitEveryNFrames: number,
2029
2051
  magnitudeDownsample: number,
2030
2052
  maxPendingFrames: number,
2053
+ maxProgressionEntries: number,
2031
2054
  keyUpdateIntervalSec: number,
2032
2055
  bpmUpdateIntervalSec: number,
2033
2056
  window: number,
@@ -2304,6 +2327,8 @@ export interface WasmAnalyzerStats {
2304
2327
  durationSeconds: number;
2305
2328
  pendingFrames: number;
2306
2329
  droppedOutputFrames: number;
2330
+ droppedChordProgressionEntries: number;
2331
+ droppedBarProgressionEntries: number;
2307
2332
  estimate: WasmProgressiveEstimate;
2308
2333
  }
2309
2334
 
@@ -72,6 +72,7 @@ export class StreamAnalyzer {
72
72
  config.emitEveryNFrames ?? defaults.emitEveryNFrames,
73
73
  config.magnitudeDownsample ?? defaults.magnitudeDownsample,
74
74
  config.maxPendingFrames ?? defaults.maxPendingFrames,
75
+ config.maxProgressionEntries ?? defaults.maxProgressionEntries,
75
76
  config.keyUpdateIntervalSec ?? defaults.keyUpdateIntervalSec,
76
77
  config.bpmUpdateIntervalSec ?? defaults.bpmUpdateIntervalSec,
77
78
  config.window ?? defaults.window,
@@ -89,7 +90,8 @@ export class StreamAnalyzer {
89
90
  }
90
91
 
91
92
  /**
92
- * Process audio samples with explicit sample offset.
93
+ * Process audio samples with a contiguous explicit sample offset. A gap,
94
+ * seek, or switch from `process()` requires `reset()` first.
93
95
  *
94
96
  * @param samples - Audio samples (mono, float32)
95
97
  * @param sampleOffset - Cumulative sample count at start of this chunk
@@ -166,6 +168,8 @@ export class StreamAnalyzer {
166
168
  durationSeconds: s.durationSeconds,
167
169
  pendingFrames: s.pendingFrames,
168
170
  droppedOutputFrames: s.droppedOutputFrames,
171
+ droppedChordProgressionEntries: s.droppedChordProgressionEntries,
172
+ droppedBarProgressionEntries: s.droppedBarProgressionEntries,
169
173
  estimate: {
170
174
  bpm: s.estimate.bpm,
171
175
  bpmConfidence: s.estimate.bpmConfidence,
@@ -66,6 +66,8 @@ export interface AnalyzerStats {
66
66
  durationSeconds: number;
67
67
  pendingFrames: number;
68
68
  droppedOutputFrames: number;
69
+ droppedChordProgressionEntries: number;
70
+ droppedBarProgressionEntries: number;
69
71
  estimate: ProgressiveEstimate;
70
72
  }
71
73
 
@@ -163,6 +165,8 @@ export interface StreamConfig {
163
165
  magnitudeDownsample?: number;
164
166
  /** Maximum unread frames; overflow drops the oldest frame. */
165
167
  maxPendingFrames?: number;
168
+ /** Maximum retained chord and bar progression entries; overflow drops oldest. */
169
+ maxProgressionEntries?: number;
166
170
  keyUpdateIntervalSec?: number;
167
171
  bpmUpdateIntervalSec?: number;
168
172
  window?: number;