@libraz/libsonare 1.5.2 → 1.5.4

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.
Files changed (48) hide show
  1. package/README.md +69 -725
  2. package/dist/index.d.ts +1155 -183
  3. package/dist/index.js +4924 -3935
  4. package/dist/index.js.map +1 -1
  5. package/dist/sonare.js +1 -1
  6. package/dist/sonare.wasm +0 -0
  7. package/dist/worklet.d.ts +29 -1
  8. package/dist/worklet.js +1141 -970
  9. package/dist/worklet.js.map +1 -1
  10. package/package.json +15 -3
  11. package/src/_chain_config.ts +46 -0
  12. package/src/audio.ts +24 -4
  13. package/src/codes.ts +27 -4
  14. package/src/effects_mastering.ts +25 -1
  15. package/src/effects_transform.ts +292 -46
  16. package/src/effects_voice_change.ts +46 -53
  17. package/src/feature_core.ts +316 -12
  18. package/src/feature_music.ts +371 -4
  19. package/src/feature_pitch.ts +61 -0
  20. package/src/feature_resample.ts +17 -2
  21. package/src/feature_spectral.ts +349 -2
  22. package/src/feature_spectrogram.ts +336 -0
  23. package/src/index.ts +130 -1
  24. package/src/mastering_chain.ts +305 -50
  25. package/src/mastering_core.ts +232 -16
  26. package/src/mastering_dynamics.ts +66 -10
  27. package/src/mastering_repair.ts +119 -7
  28. package/src/metering.ts +370 -83
  29. package/src/mixer.ts +9 -2
  30. package/src/mixing_oneshot.ts +25 -5
  31. package/src/module_state.ts +1 -1
  32. package/src/project_class.ts +30 -6
  33. package/src/project_internal.ts +12 -2
  34. package/src/project_types.ts +25 -2
  35. package/src/public_types_mastering.ts +114 -4
  36. package/src/public_types_spectral.ts +7 -0
  37. package/src/quick_analysis.ts +325 -117
  38. package/src/realtime_engine.ts +8 -0
  39. package/src/realtime_voice_changer.ts +79 -3
  40. package/src/sonare.js.d.ts +35 -0
  41. package/src/stream_analyzer.ts +20 -1
  42. package/src/stream_types.ts +12 -1
  43. package/src/validation.ts +17 -2
  44. package/src/worklet/engine-clips.ts +67 -2
  45. package/src/worklet/engine-processor.ts +33 -5
  46. package/src/worklet/engine.ts +7 -3
  47. package/src/worklet/guards.ts +3 -0
  48. package/src/worklet/messages.ts +27 -0
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@libraz/libsonare",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "type": "module",
5
5
  "packageManager": "yarn@4.15.0",
6
- "description": "Audio analysis library for music information retrieval",
6
+ "description": "Audio analysis, mastering, mixing, and MIDI synthesis in WebAssembly",
7
7
  "main": "dist/index.js",
8
8
  "types": "dist/index.d.ts",
9
9
  "exports": {
@@ -35,6 +35,7 @@
35
35
  "format": "biome format --write src/ tests/",
36
36
  "test": "vitest run",
37
37
  "test:browser": "node scripts/audio-worklet-smoke.mjs",
38
+ "test:browser:audit": "node scripts/audit-boundary-smoke.mjs",
38
39
  "test:watch": "vitest",
39
40
  "prepublishOnly": "yarn clean && cp ../../LICENSE LICENSE && yarn build && yarn lint && yarn test"
40
41
  },
@@ -46,6 +47,17 @@
46
47
  "bpm",
47
48
  "key",
48
49
  "tempo",
50
+ "chords",
51
+ "audio-processing",
52
+ "dsp",
53
+ "mastering",
54
+ "mixing",
55
+ "loudness",
56
+ "lufs",
57
+ "midi",
58
+ "synthesizer",
59
+ "soundfont",
60
+ "room-acoustics",
49
61
  "wasm",
50
62
  "webassembly"
51
63
  ],
@@ -58,7 +70,7 @@
58
70
  "bugs": {
59
71
  "url": "https://github.com/libraz/libsonare/issues"
60
72
  },
61
- "homepage": "https://github.com/libraz/libsonare#readme",
73
+ "homepage": "https://libsonare.libraz.net",
62
74
  "engines": {
63
75
  "node": ">=18.0.0"
64
76
  },
@@ -0,0 +1,46 @@
1
+ import type { MasteringChainConfig } from './public_types';
2
+
3
+ type ChainSection = { [key: string]: number | boolean | ChainSection | undefined };
4
+
5
+ /**
6
+ * Flattens a nested {@link MasteringChainConfig} into the dot-notation
7
+ * `{ "module.processor.param": value }` map the WASM core consumes. Internal
8
+ * helper shared by the mastering-chain / master-audio entry points; mirrors the
9
+ * Node facade so a nested config produces identical overrides on both surfaces.
10
+ */
11
+ export function flattenChainConfig(config: MasteringChainConfig): Record<string, number | boolean> {
12
+ const out: Record<string, number | boolean> = {};
13
+ const walk = (node: ChainSection, prefix: string): void => {
14
+ for (const [key, value] of Object.entries(node)) {
15
+ const path = prefix ? `${prefix}.${key}` : key;
16
+ if (typeof value === 'number' || typeof value === 'boolean') {
17
+ out[path] = value;
18
+ } else if (value !== null && typeof value === 'object') {
19
+ walk(value, path);
20
+ }
21
+ }
22
+ };
23
+ walk(config as ChainSection, '');
24
+
25
+ // Compatibility aliases for the original WASM-only shorthand. Normalize at
26
+ // this boundary so every native entry point receives the core parser's one
27
+ // canonical vocabulary; public types can migrate to the nested spelling
28
+ // without preserving a second C++ parser indefinitely.
29
+ const aliases: Record<string, string> = {
30
+ 'repair.denoise': 'repair.denoise.enabled',
31
+ 'repair.nFft': 'repair.denoise.nFft',
32
+ 'repair.hopLength': 'repair.denoise.hopLength',
33
+ 'repair.ddAlpha': 'repair.denoise.ddAlpha',
34
+ 'repair.gainFloor': 'repair.denoise.gainFloor',
35
+ 'eq.tiltDb': 'eq.tilt.tiltDb',
36
+ 'eq.pivotHz': 'eq.tilt.pivotHz',
37
+ };
38
+ for (const [legacy, canonical] of Object.entries(aliases)) {
39
+ const value = out[legacy];
40
+ if (value !== undefined) {
41
+ out[canonical] = value;
42
+ delete out[legacy];
43
+ }
44
+ }
45
+ return out;
46
+ }
package/src/audio.ts CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  masteringChain,
8
8
  masteringProcess,
9
9
  normalize,
10
+ noteMove,
10
11
  noteStretch,
11
12
  percussive,
12
13
  pitchCorrectToMidi,
@@ -332,6 +333,10 @@ export class Audio {
332
333
  return noteStretch(this._samples, this._sampleRate, options);
333
334
  }
334
335
 
336
+ noteMove(options: import('./public_types.js').NoteMoveOptions = {}): Float32Array {
337
+ return noteMove(this._samples, this._sampleRate, options);
338
+ }
339
+
335
340
  voiceChange(options: VoiceChangeOptions = {}): Float32Array {
336
341
  return voiceChange(this._samples, this._sampleRate, options);
337
342
  }
@@ -344,15 +349,30 @@ export class Audio {
344
349
  return mastering(this._samples, this._sampleRate, options);
345
350
  }
346
351
 
347
- masteringChain(config: MasteringChainConfig): MasteringChainResult {
348
- return masteringChain(this._samples, this._sampleRate, config);
352
+ masteringChain(
353
+ config: MasteringChainConfig = {},
354
+ onProgress?: ProgressCallback,
355
+ ): MasteringChainResult {
356
+ return masteringChain({
357
+ samples: this._samples,
358
+ sampleRate: this._sampleRate,
359
+ config,
360
+ onProgress,
361
+ });
349
362
  }
350
363
 
351
364
  masterAudio(
352
365
  presetName: MasteringPreset = 'pop',
353
- overrides: Record<string, number | boolean> | null = null,
366
+ overrides: MasteringChainConfig | null = null,
367
+ onProgress?: ProgressCallback,
354
368
  ): MasteringChainResult {
355
- return masterAudio(this._samples, this._sampleRate, presetName, overrides ?? {});
369
+ return masterAudio({
370
+ samples: this._samples,
371
+ sampleRate: this._sampleRate,
372
+ preset: presetName,
373
+ overrides: overrides ?? {},
374
+ onProgress,
375
+ });
356
376
  }
357
377
 
358
378
  masteringProcess(
package/src/codes.ts CHANGED
@@ -20,6 +20,8 @@ export function panLawCode(panLaw: PanLaw | number): number {
20
20
  return panLaw;
21
21
  }
22
22
  switch (panLaw) {
23
+ case 'const3dB':
24
+ return 0;
23
25
  case 'const4.5dB':
24
26
  return 1;
25
27
  case 'const6dB':
@@ -27,7 +29,7 @@ export function panLawCode(panLaw: PanLaw | number): number {
27
29
  case 'linear0dB':
28
30
  return 3;
29
31
  default:
30
- return 0;
32
+ throw new Error(`Invalid pan law: ${panLaw}`);
31
33
  }
32
34
  }
33
35
 
@@ -36,6 +38,8 @@ export function panModeCode(panMode: PanMode | number): number {
36
38
  return panMode;
37
39
  }
38
40
  switch (panMode) {
41
+ case 'balance':
42
+ return 0;
39
43
  case 'stereoPan':
40
44
  case 'stereo-pan':
41
45
  return 1;
@@ -43,19 +47,38 @@ export function panModeCode(panMode: PanMode | number): number {
43
47
  case 'dual-pan':
44
48
  return 2;
45
49
  default:
46
- return 0;
50
+ throw new Error(`Invalid pan mode: ${panMode}`);
47
51
  }
48
52
  }
49
53
 
50
54
  export function meterTapCode(tap: MeterTap | number): number {
51
- return tap === 'preFader' || tap === 0 ? 0 : 1;
55
+ if (typeof tap === 'number') {
56
+ return tap;
57
+ }
58
+ switch (tap) {
59
+ case 'preFader':
60
+ return 0;
61
+ case 'postFader':
62
+ return 1;
63
+ default:
64
+ throw new Error(`Invalid meter tap: ${tap}`);
65
+ }
52
66
  }
53
67
 
54
68
  export function sendTimingCode(timing: SendTiming | number): number {
55
69
  // Mirrors SonareSendTiming: post-fader is 0 (so an omitted/zeroed value is
56
70
  // post-fader), pre-fader is 1. A raw number is passed through as the C ABI int.
71
+ // An unknown string is rejected rather than silently routed to post-fader,
72
+ // matching the sibling enum-code helpers and Node's sendTimingValue.
57
73
  if (typeof timing === 'number') {
58
74
  return timing;
59
75
  }
60
- return timing === 'preFader' ? 1 : 0;
76
+ switch (timing) {
77
+ case 'postFader':
78
+ return 0;
79
+ case 'preFader':
80
+ return 1;
81
+ default:
82
+ throw new Error(`Invalid send timing: ${timing}`);
83
+ }
61
84
  }
@@ -2,6 +2,7 @@ export {
2
2
  harmonic,
3
3
  hpss,
4
4
  normalize,
5
+ noteMove,
5
6
  noteStretch,
6
7
  percussive,
7
8
  pitchCorrectTimevarying,
@@ -11,7 +12,12 @@ export {
11
12
  spectralEdit,
12
13
  timeStretch,
13
14
  } from './effects_transform';
14
- export type { VoiceChangeOptions, VoiceChangeRealtimeOptions } from './effects_voice_change';
15
+ export type {
16
+ VoiceChangeOptions,
17
+ VoiceChangeRealtimeOptions,
18
+ VoiceChangeRealtimeRequest,
19
+ VoiceChangeRequest,
20
+ } from './effects_voice_change';
15
21
  export { voiceChange, voiceChangeRealtime } from './effects_voice_change';
16
22
  export {
17
23
  masterAudio,
@@ -27,7 +33,14 @@ export {
27
33
  export type {
28
34
  MasteringChannelPolicy,
29
35
  MasteringInsertParamInfo,
36
+ MasteringPairAnalyzeRequest,
37
+ MasteringPairProcessRequest,
30
38
  MasteringProcessorCatalogEntry,
39
+ MasteringProcessRequest,
40
+ MasteringProcessStereoRequest,
41
+ MasteringSamplesParamsRequest,
42
+ MasteringStereoAnalyzeRequest,
43
+ MasteringStreamingPreviewRequest,
31
44
  } from './mastering_core';
32
45
  export {
33
46
  mastering,
@@ -53,6 +66,9 @@ export type {
53
66
  CompressorOptions,
54
67
  DynamicsResult,
55
68
  GateOptions,
69
+ MasteringDynamicsCompressorRequest,
70
+ MasteringDynamicsGateRequest,
71
+ MasteringDynamicsTransientShaperRequest,
56
72
  TransientShaperOptions,
57
73
  } from './mastering_dynamics';
58
74
  export {
@@ -70,6 +86,13 @@ export type {
70
86
  DenoiseClassicalNoiseEstimator,
71
87
  DenoiseClassicalOptions,
72
88
  DereverbClassicalOptions,
89
+ MasteringRepairDeclickRequest,
90
+ MasteringRepairDeclipRequest,
91
+ MasteringRepairDecrackleRequest,
92
+ MasteringRepairDehumRequest,
93
+ MasteringRepairDenoiseClassicalRequest,
94
+ MasteringRepairDereverbClassicalRequest,
95
+ MasteringRepairTrimSilenceRequest,
73
96
  TrimSilenceMode,
74
97
  TrimSilenceOptions,
75
98
  } from './mastering_repair';
@@ -82,4 +105,5 @@ export {
82
105
  masteringRepairDereverbClassical,
83
106
  masteringRepairTrimSilence,
84
107
  } from './mastering_repair';
108
+ export type { MixStereoRequest } from './mixing_oneshot';
85
109
  export { mixingScenePresetJson, mixingScenePresetNames, mixStereo } from './mixing_oneshot';