@libraz/libsonare 1.5.5 → 1.7.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/README.md +109 -20
- package/dist/analysis.d.ts +5809 -0
- package/dist/analysis.js +2574 -0
- package/dist/analysis.js.map +1 -0
- package/dist/index.d.ts +884 -55
- package/dist/index.js +1302 -292
- package/dist/index.js.map +1 -1
- package/dist/schemas/realtime-voice-changer-preset-pack.schema.json +27 -0
- package/dist/schemas/realtime-voice-changer-preset.schema.json +140 -0
- package/dist/sonare-analysis.js +2 -0
- package/dist/sonare-analysis.wasm +0 -0
- package/dist/sonare.js +1 -1
- package/dist/sonare.wasm +0 -0
- package/dist/worker.d.ts +65 -0
- package/dist/worker.js +734 -0
- package/dist/worker.js.map +1 -0
- package/dist/worklet.d.ts +628 -88
- package/dist/worklet.js +1816 -266
- package/dist/worklet.js.map +1 -1
- package/package.json +23 -11
- package/src/_chain_config.ts +5 -3
- package/src/analysis.ts +137 -0
- package/src/analysis_helpers.ts +40 -29
- package/src/audio.ts +7 -2
- package/src/clip_page_streamer.ts +62 -8
- package/src/codes.ts +87 -64
- package/src/effects_mastering.ts +1 -0
- package/src/effects_transform.ts +179 -10
- package/src/errors.ts +1 -0
- package/src/feature_core.ts +140 -2
- package/src/feature_music.ts +25 -3
- package/src/feature_pitch.ts +70 -1
- package/src/feature_spectral.ts +295 -7
- package/src/feature_spectrogram.ts +203 -3
- package/src/features.ts +16 -1
- package/src/index.ts +120 -8
- package/src/mastering_chain.ts +20 -8
- package/src/mastering_core.ts +5 -0
- package/src/mastering_dynamics.ts +7 -1
- package/src/metering.ts +6 -1
- package/src/mixer.ts +3 -3
- package/src/opfs_clip_pages.ts +26 -1
- package/src/project.ts +13 -0
- package/src/project_class.ts +204 -23
- package/src/project_internal.ts +38 -34
- package/src/project_types.ts +114 -11
- package/src/public_types.ts +68 -0
- package/src/public_types_mastering.ts +22 -0
- package/src/public_types_mixing.ts +27 -2
- package/src/public_types_music.ts +9 -0
- package/src/public_types_realtime.ts +23 -5
- package/src/public_types_spectral.ts +33 -0
- package/src/quick_analysis.ts +46 -10
- package/src/realtime_engine.ts +167 -6
- package/src/realtime_voice_changer.ts +51 -77
- package/src/sonare-analysis.js.d.ts +8 -0
- package/src/sonare.js.d.ts +340 -6
- package/src/stream_analyzer.ts +6 -1
- package/src/streaming_processors.ts +15 -0
- package/src/web_midi.ts +46 -11
- package/src/worker.ts +196 -0
- package/src/worker_client.ts +352 -0
- package/src/worker_protocol.ts +59 -0
- package/src/worklet/engine-automation.ts +2 -1
- package/src/worklet/engine-capture-facade.ts +13 -4
- package/src/worklet/engine-clips.ts +12 -3
- package/src/worklet/engine-node.ts +264 -21
- package/src/worklet/engine-offline.ts +7 -2
- package/src/worklet/engine-parameter-facade.ts +55 -5
- package/src/worklet/engine-processor.ts +435 -62
- package/src/worklet/engine-register.ts +9 -1
- package/src/worklet/engine-strips.ts +19 -3
- package/src/worklet/engine-sync.ts +2 -6
- package/src/worklet/engine-tempo-facade.ts +8 -6
- package/src/worklet/engine.ts +390 -13
- package/src/worklet/guards.ts +121 -8
- package/src/worklet/messages.ts +166 -8
- package/src/worklet/protocol.ts +305 -17
- package/src/worklet/voice-changer-processor.ts +12 -15
- package/src/worklet.ts +20 -1
|
@@ -5,74 +5,6 @@ import type {
|
|
|
5
5
|
VoicePresetId,
|
|
6
6
|
} from './public_types';
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* True when `config` is a flat POD (the shape `realtimeVoiceChangerPresetConfig`
|
|
10
|
-
* returns) rather than a preset name or a nested preset. `retuneSemitones` only
|
|
11
|
-
* exists on the flat POD; the nested form spells it `retune.semitones`.
|
|
12
|
-
*/
|
|
13
|
-
function isFlatVoiceChangerPod(config: unknown): config is RealtimeVoiceChangerPodConfig {
|
|
14
|
-
return typeof config === 'object' && config !== null && 'retuneSemitones' in config;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Rewrite the flat 36-field POD into the nested shape the native config parser
|
|
19
|
-
* reads. Passing the flat POD straight to `setConfig` would leave every nested
|
|
20
|
-
* field at its default (only the three root fields are read flat), silently
|
|
21
|
-
* discarding retune/EQ/reverb/etc.
|
|
22
|
-
*/
|
|
23
|
-
function flatVoiceChangerPodToNested(pod: RealtimeVoiceChangerPodConfig): Record<string, unknown> {
|
|
24
|
-
return {
|
|
25
|
-
inputGainDb: pod.inputGainDb,
|
|
26
|
-
outputGainDb: pod.outputGainDb,
|
|
27
|
-
wetMix: pod.wetMix,
|
|
28
|
-
retune: { semitones: pod.retuneSemitones, mix: pod.retuneMix, grainSize: pod.retuneGrainSize },
|
|
29
|
-
formant: {
|
|
30
|
-
factor: pod.formantFactor,
|
|
31
|
-
amount: pod.formantAmount,
|
|
32
|
-
body: pod.formantBody,
|
|
33
|
-
brightness: pod.formantBrightness,
|
|
34
|
-
nasal: pod.formantNasal,
|
|
35
|
-
},
|
|
36
|
-
eq: {
|
|
37
|
-
highpassHz: pod.eqHighpassHz,
|
|
38
|
-
bodyDb: pod.eqBodyDb,
|
|
39
|
-
presenceDb: pod.eqPresenceDb,
|
|
40
|
-
airDb: pod.eqAirDb,
|
|
41
|
-
},
|
|
42
|
-
gate: {
|
|
43
|
-
thresholdDb: pod.gateThresholdDb,
|
|
44
|
-
attackMs: pod.gateAttackMs,
|
|
45
|
-
releaseMs: pod.gateReleaseMs,
|
|
46
|
-
rangeDb: pod.gateRangeDb,
|
|
47
|
-
},
|
|
48
|
-
compressor: {
|
|
49
|
-
thresholdDb: pod.compressorThresholdDb,
|
|
50
|
-
ratio: pod.compressorRatio,
|
|
51
|
-
attackMs: pod.compressorAttackMs,
|
|
52
|
-
releaseMs: pod.compressorReleaseMs,
|
|
53
|
-
makeupGainDb: pod.compressorMakeupGainDb,
|
|
54
|
-
},
|
|
55
|
-
deesser: {
|
|
56
|
-
frequencyHz: pod.deesserFrequencyHz,
|
|
57
|
-
thresholdDb: pod.deesserThresholdDb,
|
|
58
|
-
ratio: pod.deesserRatio,
|
|
59
|
-
rangeDb: pod.deesserRangeDb,
|
|
60
|
-
},
|
|
61
|
-
reverb: {
|
|
62
|
-
mix: pod.reverbMix,
|
|
63
|
-
timeMs: pod.reverbTimeMs,
|
|
64
|
-
damping: pod.reverbDamping,
|
|
65
|
-
seed: pod.reverbSeed,
|
|
66
|
-
},
|
|
67
|
-
limiter: {
|
|
68
|
-
ceilingDb: pod.limiterCeilingDb,
|
|
69
|
-
releaseMs: pod.limiterReleaseMs,
|
|
70
|
-
enableIspLimiter: pod.limiterEnableIspLimiter,
|
|
71
|
-
ispCeilingDbtp: pod.limiterIspCeilingDbtp,
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
8
|
/**
|
|
77
9
|
* Zero-copy realtime buffer pair for {@link RealtimeVoiceChanger} mono
|
|
78
10
|
* processing. The `input` / `output` `Float32Array`s are typed-memory views
|
|
@@ -117,9 +49,22 @@ export interface RealtimeVoiceChangerPlanarBuffer {
|
|
|
117
49
|
export class RealtimeVoiceChanger {
|
|
118
50
|
private changer: import('./sonare.js').WasmRealtimeVoiceChanger;
|
|
119
51
|
|
|
120
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Creates a voice changer. Supplying `sampleRate` prepares it immediately,
|
|
54
|
+
* matching the Node and Python constructors; omitting it preserves the
|
|
55
|
+
* explicit {@link prepare} lifecycle for callers that configure later.
|
|
56
|
+
*/
|
|
57
|
+
constructor(
|
|
58
|
+
config: RealtimeVoiceChangerConfigInput | RealtimeVoiceChangerPodConfig = 'neutral-monitor',
|
|
59
|
+
sampleRate?: number,
|
|
60
|
+
maxBlockSize = 128,
|
|
61
|
+
channels = 1,
|
|
62
|
+
) {
|
|
121
63
|
const module = getSonareModule();
|
|
122
64
|
this.changer = module.createRealtimeVoiceChanger(config as Record<string, unknown> | string);
|
|
65
|
+
if (sampleRate !== undefined) {
|
|
66
|
+
this.changer.prepare(sampleRate, maxBlockSize, channels);
|
|
67
|
+
}
|
|
123
68
|
}
|
|
124
69
|
|
|
125
70
|
prepare(sampleRate: number, maxBlockSize = 128, channels = 1): void {
|
|
@@ -131,11 +76,18 @@ export class RealtimeVoiceChanger {
|
|
|
131
76
|
}
|
|
132
77
|
|
|
133
78
|
setConfig(config: RealtimeVoiceChangerConfigInput | RealtimeVoiceChangerPodConfig): void {
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
79
|
+
// The shared native parser recognizes the flat POD produced by
|
|
80
|
+
// realtimeVoiceChangerPresetConfig, so bindings never duplicate its 36-field mapping.
|
|
81
|
+
this.changer.setConfig(config as Record<string, unknown> | string);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Apply a flat, pre-normalized config without JSON serialization. Intended
|
|
86
|
+
* for AudioWorklet control messages whose sender prepared the POD on the
|
|
87
|
+
* main thread.
|
|
88
|
+
*/
|
|
89
|
+
setPodConfig(config: RealtimeVoiceChangerPodConfig): void {
|
|
90
|
+
this.changer.setPodConfig(config);
|
|
139
91
|
}
|
|
140
92
|
|
|
141
93
|
configJson(): string {
|
|
@@ -146,6 +98,14 @@ export class RealtimeVoiceChanger {
|
|
|
146
98
|
return this.changer.latencySamples();
|
|
147
99
|
}
|
|
148
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Monotonically increases whenever {@link prepare} can replace the native
|
|
103
|
+
* scratch buffers. Cached WASM heap views must be reacquired after it changes.
|
|
104
|
+
*/
|
|
105
|
+
bufferGeneration(): number {
|
|
106
|
+
return this.changer.bufferGeneration();
|
|
107
|
+
}
|
|
108
|
+
|
|
149
109
|
processMono(samples: Float32Array): Float32Array {
|
|
150
110
|
return this.changer.processMono(samples);
|
|
151
111
|
}
|
|
@@ -234,14 +194,20 @@ export class RealtimeVoiceChanger {
|
|
|
234
194
|
createRealtimeMonoBuffer(numSamples: number): RealtimeVoiceChangerMonoBuffer {
|
|
235
195
|
let input = this.getMonoInputBuffer(numSamples);
|
|
236
196
|
let output = this.getMonoOutputBuffer(numSamples);
|
|
197
|
+
let generation = this.bufferGeneration();
|
|
237
198
|
// The cached heap views can detach if WASM linear memory grows (the embind
|
|
238
199
|
// module is built ALLOW_MEMORY_GROWTH). Re-acquire them if detached
|
|
239
200
|
// (byteLength === 0) before use, mirroring the worklet RT path. In the
|
|
240
201
|
// common no-growth case this is a cheap branch with no allocation.
|
|
241
202
|
const reacquireIfDetached = (): void => {
|
|
242
|
-
if (
|
|
203
|
+
if (
|
|
204
|
+
generation !== this.bufferGeneration() ||
|
|
205
|
+
input.byteLength === 0 ||
|
|
206
|
+
output.byteLength === 0
|
|
207
|
+
) {
|
|
243
208
|
input = this.getMonoInputBuffer(numSamples);
|
|
244
209
|
output = this.getMonoOutputBuffer(numSamples);
|
|
210
|
+
generation = this.bufferGeneration();
|
|
245
211
|
}
|
|
246
212
|
};
|
|
247
213
|
return {
|
|
@@ -267,12 +233,18 @@ export class RealtimeVoiceChanger {
|
|
|
267
233
|
): RealtimeVoiceChangerInterleavedBuffer {
|
|
268
234
|
let input = this.getInterleavedInputBuffer(numFrames, numChannels);
|
|
269
235
|
let output = this.getInterleavedOutputBuffer(numFrames, numChannels);
|
|
236
|
+
let generation = this.bufferGeneration();
|
|
270
237
|
// Re-acquire detached views after WASM memory growth (see
|
|
271
238
|
// createRealtimeMonoBuffer for rationale).
|
|
272
239
|
const reacquireIfDetached = (): void => {
|
|
273
|
-
if (
|
|
240
|
+
if (
|
|
241
|
+
generation !== this.bufferGeneration() ||
|
|
242
|
+
input.byteLength === 0 ||
|
|
243
|
+
output.byteLength === 0
|
|
244
|
+
) {
|
|
274
245
|
input = this.getInterleavedInputBuffer(numFrames, numChannels);
|
|
275
246
|
output = this.getInterleavedOutputBuffer(numFrames, numChannels);
|
|
247
|
+
generation = this.bufferGeneration();
|
|
276
248
|
}
|
|
277
249
|
};
|
|
278
250
|
return {
|
|
@@ -303,17 +275,19 @@ export class RealtimeVoiceChanger {
|
|
|
303
275
|
numChannels: number,
|
|
304
276
|
): RealtimeVoiceChangerPlanarBuffer {
|
|
305
277
|
let channels: Float32Array[] = [];
|
|
278
|
+
let generation = this.bufferGeneration();
|
|
306
279
|
const acquire = (): void => {
|
|
307
280
|
channels = [];
|
|
308
281
|
for (let ch = 0; ch < numChannels; ch++) {
|
|
309
282
|
channels.push(this.getPlanarChannelBuffer(ch, numFrames));
|
|
310
283
|
}
|
|
284
|
+
generation = this.bufferGeneration();
|
|
311
285
|
};
|
|
312
286
|
acquire();
|
|
313
287
|
// Re-acquire detached views after WASM memory growth (see
|
|
314
288
|
// createRealtimeMonoBuffer for rationale).
|
|
315
289
|
const reacquireIfDetached = (): void => {
|
|
316
|
-
if ((channels[0]?.byteLength ?? 0) === 0) {
|
|
290
|
+
if (generation !== this.bufferGeneration() || (channels[0]?.byteLength ?? 0) === 0) {
|
|
317
291
|
acquire();
|
|
318
292
|
}
|
|
319
293
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SonareModule } from './sonare.js';
|
|
2
|
+
|
|
3
|
+
declare const createSonareAnalysis: (options?: {
|
|
4
|
+
locateFile?: (path: string, prefix: string) => string;
|
|
5
|
+
wasmBinary?: ArrayBuffer | Uint8Array;
|
|
6
|
+
}) => Promise<SonareModule>;
|
|
7
|
+
|
|
8
|
+
export default createSonareAnalysis;
|