@libraz/libsonare 1.0.3 → 1.1.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 CHANGED
@@ -2,11 +2,19 @@
2
2
 
3
3
  [![CI](https://img.shields.io/github/actions/workflow/status/libraz/libsonare/ci.yml?branch=main&label=CI)](https://github.com/libraz/libsonare/actions)
4
4
  [![npm](https://img.shields.io/npm/v/@libraz/libsonare)](https://www.npmjs.com/package/@libraz/libsonare)
5
- [![PyPI](https://img.shields.io/pypi/v/libsonare)](https://pypi.org/project/libsonare/)
5
+ [![npm downloads](https://img.shields.io/npm/dm/@libraz/libsonare)](https://www.npmjs.com/package/@libraz/libsonare)
6
+ [![types](https://img.shields.io/npm/types/@libraz/libsonare)](https://www.npmjs.com/package/@libraz/libsonare)
6
7
  [![License](https://img.shields.io/github/license/libraz/libsonare)](https://github.com/libraz/libsonare/blob/main/LICENSE)
8
+ [![PyPI](https://img.shields.io/pypi/v/libsonare?label=PyPI)](https://pypi.org/project/libsonare/)
7
9
 
8
10
  Fast, dependency-free audio analysis library for browser and Node.js via WebAssembly.
9
11
 
12
+ > **Audio input:** This package expects already-decoded `Float32Array` mono
13
+ > samples (it does not bundle a file decoder). Use the Web Audio API in the
14
+ > browser or `node:wasi` / a JS audio decoder in Node to obtain samples.
15
+ > If you need to read WAV/MP3/M4A files directly in Node, use the native
16
+ > N-API package [`@libraz/libsonare-native`](https://github.com/libraz/libsonare/tree/main/bindings/node) instead.
17
+
10
18
  ## Installation
11
19
 
12
20
  ```bash
@@ -32,6 +40,24 @@ console.log(`BPM: ${audio.detectBpm()}`);
32
40
  console.log(`Key: ${audio.detectKey().name}`);
33
41
  ```
34
42
 
43
+ ### Decoding files in the browser
44
+
45
+ ```typescript
46
+ import { init, analyze } from '@libraz/libsonare';
47
+
48
+ await init();
49
+
50
+ const arrayBuffer = await fetch('song.m4a').then((r) => r.arrayBuffer());
51
+ const audioCtx = new AudioContext();
52
+ const decoded = await audioCtx.decodeAudioData(arrayBuffer);
53
+ // Mono downmix for libsonare:
54
+ const samples = decoded.getChannelData(0);
55
+ const result = analyze(samples, decoded.sampleRate);
56
+ ```
57
+
58
+ Web Audio's `decodeAudioData` handles whatever codecs the browser ships with
59
+ (WAV/MP3/M4A/AAC/Opus/FLAC on most modern browsers).
60
+
35
61
  ### Browser (CDN)
36
62
 
37
63
  ```html
@@ -70,10 +96,143 @@ const stats = analyzer.stats();
70
96
  console.log(`BPM: ${stats.estimate.bpm}, Key: ${stats.estimate.key}`);
71
97
  ```
72
98
 
99
+ ### Mastering (WASM)
100
+
101
+ The npm package ships mastering DSP in the default WebAssembly build. Pass
102
+ decoded `Float32Array` samples directly:
103
+
104
+ ```typescript
105
+ import { init, masteringChain, masteringChainStereo } from '@libraz/libsonare';
106
+
107
+ await init();
108
+
109
+ const mastered = masteringChain(samples, sampleRate, {
110
+ eq: { tiltDb: 1.0 },
111
+ dynamics: { compressor: { thresholdDb: -24, ratio: 1.5 } },
112
+ saturation: { tape: { driveDb: 1.0, saturation: 0.2 } },
113
+ loudness: { targetLufs: -14, ceilingDb: -1, truePeakOversample: 4 },
114
+ });
115
+
116
+ const stereo = masteringChainStereo(left, right, sampleRate, {
117
+ stereo: { imager: { width: 1.1 }, monoMaker: { amount: 0.2 } },
118
+ loudness: { targetLufs: -14, ceilingDb: -1, truePeakOversample: 4 },
119
+ });
120
+ ```
121
+
122
+ Named mastering processors use the same names and behavior as the native,
123
+ Python, C, and CLI APIs:
124
+
125
+ ```typescript
126
+ import {
127
+ masteringPairAnalyze,
128
+ masteringPairProcess,
129
+ masteringPairProcessorNames,
130
+ masteringProcess,
131
+ masteringProcessStereo,
132
+ masteringProcessorNames,
133
+ masteringStereoAnalyze,
134
+ } from '@libraz/libsonare';
135
+
136
+ const names = masteringProcessorNames(); // e.g. "dynamics.compressor"
137
+ const compressed = masteringProcess('dynamics.compressor', samples, sampleRate, {
138
+ thresholdDb: -24,
139
+ ratio: 1.5,
140
+ });
141
+
142
+ const widened = masteringProcessStereo('stereo.imager', left, right, sampleRate, {
143
+ width: 1.1,
144
+ });
145
+
146
+ const pairNames = masteringPairProcessorNames(); // e.g. "match.abCrossfade"
147
+ const crossfaded = masteringPairProcess('match.abCrossfade', source, reference, sampleRate, {
148
+ mix: 0.25,
149
+ });
150
+
151
+ const loudnessJson = masteringPairAnalyze(
152
+ 'match.referenceLoudness',
153
+ source,
154
+ reference,
155
+ sampleRate,
156
+ );
157
+ const monoCompatJson = masteringStereoAnalyze(
158
+ 'stereo.monoCompatCheck',
159
+ left,
160
+ right,
161
+ sampleRate,
162
+ );
163
+ ```
164
+
165
+ ### Mastering presets
166
+
167
+ ```typescript
168
+ import { init, masterAudio, masteringPresetNames } from '@libraz/libsonare';
169
+
170
+ await init();
171
+
172
+ masteringPresetNames(); // ['pop', 'edm', 'acoustic', 'hipHop', 'aiMusic', 'speech']
173
+
174
+ const result = masterAudio(samples, sampleRate, 'aiMusic', {
175
+ // optional flat overrides applied on top of the preset (dot notation)
176
+ 'loudness.targetLufs': -13,
177
+ });
178
+ console.log(result.outputLufs, result.appliedGainDb);
179
+ ```
180
+
181
+ ### Progress callback
182
+
183
+ `masteringChainWithProgress` (and its stereo variant) is `masteringChain` with
184
+ an extra `(progress, stage) => void` callback invoked after each enabled stage:
185
+
186
+ ```typescript
187
+ import { init, masteringChainWithProgress } from '@libraz/libsonare';
188
+
189
+ await init();
190
+
191
+ masteringChainWithProgress(
192
+ samples,
193
+ sampleRate,
194
+ { dynamics: { compressor: { thresholdDb: -24 } } },
195
+ (progress, stage) => console.log(`${stage}: ${(progress * 100).toFixed(0)}%`),
196
+ );
197
+ ```
198
+
199
+ ### Streaming mastering chain
200
+
201
+ `StreamingMasteringChain` processes blocks while maintaining per-stage state
202
+ across calls. It only supports modules whose state depends solely on the
203
+ sample rate — it cannot include `repair.denoise` or `loudness` (those require
204
+ offline / look-ahead analysis) and throws at construction if they are enabled.
205
+
206
+ ```typescript
207
+ import { init, StreamingMasteringChain } from '@libraz/libsonare';
208
+
209
+ await init();
210
+
211
+ const chain = new StreamingMasteringChain({
212
+ eq: { tiltDb: 0.5 },
213
+ dynamics: { compressor: { thresholdDb: -20 } },
214
+ });
215
+ chain.prepare(48000, 512, 2);
216
+
217
+ // Mono block
218
+ const monoBlock = new Float32Array(512);
219
+ const processedMono = chain.processMono(monoBlock);
220
+
221
+ // Stereo block (separate L/R Float32Arrays)
222
+ const left = new Float32Array(512);
223
+ const right = new Float32Array(512);
224
+ const { left: outL, right: outR } = chain.processStereo(left, right);
225
+
226
+ chain.reset();
227
+ chain.delete(); // release WASM memory
228
+ ```
229
+
73
230
  ## Features
74
231
 
75
232
  - **Detection**: BPM, key, beats, onsets, chords, sections
76
233
  - **Effects**: HPSS, time stretch, pitch shift, normalize, trim
234
+ - **Mastering**: EQ, compressor, tape/exciter, air band, stereo imaging,
235
+ true-peak limiting, loudness optimization
77
236
  - **Features**: STFT, mel spectrogram, MFCC, chroma, CQT/VQT, spectral features
78
237
  - **Pitch**: YIN, pYIN algorithms
79
238
  - **Streaming**: Real-time analysis with progressive estimates