@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.
Files changed (80) hide show
  1. package/README.md +109 -20
  2. package/dist/analysis.d.ts +5809 -0
  3. package/dist/analysis.js +2574 -0
  4. package/dist/analysis.js.map +1 -0
  5. package/dist/index.d.ts +884 -55
  6. package/dist/index.js +1302 -292
  7. package/dist/index.js.map +1 -1
  8. package/dist/schemas/realtime-voice-changer-preset-pack.schema.json +27 -0
  9. package/dist/schemas/realtime-voice-changer-preset.schema.json +140 -0
  10. package/dist/sonare-analysis.js +2 -0
  11. package/dist/sonare-analysis.wasm +0 -0
  12. package/dist/sonare.js +1 -1
  13. package/dist/sonare.wasm +0 -0
  14. package/dist/worker.d.ts +65 -0
  15. package/dist/worker.js +734 -0
  16. package/dist/worker.js.map +1 -0
  17. package/dist/worklet.d.ts +628 -88
  18. package/dist/worklet.js +1816 -266
  19. package/dist/worklet.js.map +1 -1
  20. package/package.json +23 -11
  21. package/src/_chain_config.ts +5 -3
  22. package/src/analysis.ts +137 -0
  23. package/src/analysis_helpers.ts +40 -29
  24. package/src/audio.ts +7 -2
  25. package/src/clip_page_streamer.ts +62 -8
  26. package/src/codes.ts +87 -64
  27. package/src/effects_mastering.ts +1 -0
  28. package/src/effects_transform.ts +179 -10
  29. package/src/errors.ts +1 -0
  30. package/src/feature_core.ts +140 -2
  31. package/src/feature_music.ts +25 -3
  32. package/src/feature_pitch.ts +70 -1
  33. package/src/feature_spectral.ts +295 -7
  34. package/src/feature_spectrogram.ts +203 -3
  35. package/src/features.ts +16 -1
  36. package/src/index.ts +120 -8
  37. package/src/mastering_chain.ts +20 -8
  38. package/src/mastering_core.ts +5 -0
  39. package/src/mastering_dynamics.ts +7 -1
  40. package/src/metering.ts +6 -1
  41. package/src/mixer.ts +3 -3
  42. package/src/opfs_clip_pages.ts +26 -1
  43. package/src/project.ts +13 -0
  44. package/src/project_class.ts +204 -23
  45. package/src/project_internal.ts +38 -34
  46. package/src/project_types.ts +114 -11
  47. package/src/public_types.ts +68 -0
  48. package/src/public_types_mastering.ts +22 -0
  49. package/src/public_types_mixing.ts +27 -2
  50. package/src/public_types_music.ts +9 -0
  51. package/src/public_types_realtime.ts +23 -5
  52. package/src/public_types_spectral.ts +33 -0
  53. package/src/quick_analysis.ts +46 -10
  54. package/src/realtime_engine.ts +167 -6
  55. package/src/realtime_voice_changer.ts +51 -77
  56. package/src/sonare-analysis.js.d.ts +8 -0
  57. package/src/sonare.js.d.ts +340 -6
  58. package/src/stream_analyzer.ts +6 -1
  59. package/src/streaming_processors.ts +15 -0
  60. package/src/web_midi.ts +46 -11
  61. package/src/worker.ts +196 -0
  62. package/src/worker_client.ts +352 -0
  63. package/src/worker_protocol.ts +59 -0
  64. package/src/worklet/engine-automation.ts +2 -1
  65. package/src/worklet/engine-capture-facade.ts +13 -4
  66. package/src/worklet/engine-clips.ts +12 -3
  67. package/src/worklet/engine-node.ts +264 -21
  68. package/src/worklet/engine-offline.ts +7 -2
  69. package/src/worklet/engine-parameter-facade.ts +55 -5
  70. package/src/worklet/engine-processor.ts +435 -62
  71. package/src/worklet/engine-register.ts +9 -1
  72. package/src/worklet/engine-strips.ts +19 -3
  73. package/src/worklet/engine-sync.ts +2 -6
  74. package/src/worklet/engine-tempo-facade.ts +8 -6
  75. package/src/worklet/engine.ts +390 -13
  76. package/src/worklet/guards.ts +121 -8
  77. package/src/worklet/messages.ts +166 -8
  78. package/src/worklet/protocol.ts +305 -17
  79. package/src/worklet/voice-changer-processor.ts +12 -15
  80. package/src/worklet.ts +20 -1
package/dist/worker.js ADDED
@@ -0,0 +1,734 @@
1
+ // src/errors.ts
2
+ var SonareError = class extends Error {
3
+ constructor(code, codeName, message) {
4
+ super(message);
5
+ this.name = "SonareError";
6
+ this.code = code;
7
+ this.codeName = codeName;
8
+ }
9
+ };
10
+
11
+ // src/module_state.ts
12
+ var wrappedModule = null;
13
+ function nativeExceptionPtr(error) {
14
+ if (typeof error === "number") {
15
+ return error;
16
+ }
17
+ if (error !== null && typeof error === "object") {
18
+ const ptr = error.excPtr;
19
+ if (typeof ptr === "number") {
20
+ return ptr;
21
+ }
22
+ }
23
+ return null;
24
+ }
25
+ function makeSonareError(raw, thrown) {
26
+ let code = 99 /* Unknown */;
27
+ let codeName = "Unknown";
28
+ let message = `libsonare native exception (${thrown})`;
29
+ try {
30
+ const info = raw.sonareExceptionInfo?.(thrown);
31
+ if (info) {
32
+ code = info.code ?? code;
33
+ codeName = info.codeName ?? codeName;
34
+ message = info.message || message;
35
+ }
36
+ } catch {
37
+ }
38
+ return new SonareError(code, codeName, message);
39
+ }
40
+ function wrapModuleErrors(raw) {
41
+ const cache = /* @__PURE__ */ new Map();
42
+ const objectCache = /* @__PURE__ */ new WeakMap();
43
+ const convert = (error) => {
44
+ const ptr = nativeExceptionPtr(error);
45
+ if (ptr !== null) {
46
+ throw makeSonareError(raw, ptr);
47
+ }
48
+ throw error;
49
+ };
50
+ const wrapNativeObject = (value) => {
51
+ if (value === null || typeof value !== "object") {
52
+ return value;
53
+ }
54
+ if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer || value instanceof Promise) {
55
+ return value;
56
+ }
57
+ const objectValue = value;
58
+ const cached = objectCache.get(objectValue);
59
+ if (cached) {
60
+ return cached;
61
+ }
62
+ const methodCache = /* @__PURE__ */ new Map();
63
+ const wrapped = new Proxy(objectValue, {
64
+ get(target, prop, receiver) {
65
+ const member = Reflect.get(target, prop, receiver);
66
+ if (typeof member !== "function") {
67
+ return member;
68
+ }
69
+ const cachedMethod = methodCache.get(prop);
70
+ if (cachedMethod) {
71
+ return cachedMethod;
72
+ }
73
+ const method = member;
74
+ const wrappedMethod = (...args) => {
75
+ try {
76
+ return wrapNativeObject(Reflect.apply(method, target, args));
77
+ } catch (error) {
78
+ return convert(error);
79
+ }
80
+ };
81
+ methodCache.set(prop, wrappedMethod);
82
+ return wrappedMethod;
83
+ }
84
+ });
85
+ objectCache.set(objectValue, wrapped);
86
+ return wrapped;
87
+ };
88
+ const wrapFunction = (value) => {
89
+ const fnCache = /* @__PURE__ */ new Map();
90
+ return new Proxy(value, {
91
+ get(target, prop, receiver) {
92
+ const member = Reflect.get(target, prop, receiver);
93
+ if (typeof member !== "function") {
94
+ return member;
95
+ }
96
+ const cachedMember = fnCache.get(prop);
97
+ if (cachedMember) {
98
+ return cachedMember;
99
+ }
100
+ const fn = member;
101
+ const wrappedMember = (...args) => {
102
+ try {
103
+ return wrapNativeObject(Reflect.apply(fn, target, args));
104
+ } catch (error) {
105
+ return convert(error);
106
+ }
107
+ };
108
+ fnCache.set(prop, wrappedMember);
109
+ return wrappedMember;
110
+ },
111
+ apply(t, thisArg, args) {
112
+ try {
113
+ return wrapNativeObject(Reflect.apply(t, thisArg, args));
114
+ } catch (error) {
115
+ return convert(error);
116
+ }
117
+ },
118
+ construct(t, args, newTarget) {
119
+ try {
120
+ return wrapNativeObject(Reflect.construct(t, args, newTarget));
121
+ } catch (error) {
122
+ return convert(error);
123
+ }
124
+ }
125
+ });
126
+ };
127
+ return new Proxy(raw, {
128
+ get(target, prop, receiver) {
129
+ const value = Reflect.get(target, prop, receiver);
130
+ if (typeof value !== "function") {
131
+ return value;
132
+ }
133
+ const cached = cache.get(prop);
134
+ if (cached) {
135
+ return cached;
136
+ }
137
+ const wrapped = wrapFunction(value);
138
+ cache.set(prop, wrapped);
139
+ return wrapped;
140
+ }
141
+ });
142
+ }
143
+ function setSonareModule(module2) {
144
+ wrappedModule = wrapModuleErrors(module2);
145
+ }
146
+ function getSonareModule() {
147
+ if (!wrappedModule) {
148
+ throw new Error("Module not initialized. Call init() first.");
149
+ }
150
+ return wrappedModule;
151
+ }
152
+
153
+ // src/validation.ts
154
+ var MIN_AUDIO_SAMPLE_RATE = 8e3;
155
+ var MAX_AUDIO_SAMPLE_RATE = 384e3;
156
+ function assertNonEmptySamples(fnName, samples, argName = "samples") {
157
+ if (samples.length === 0) {
158
+ throw new RangeError(`${fnName}: ${argName} must not be empty`);
159
+ }
160
+ }
161
+ function assertFiniteSamples(fnName, samples, validate, argName = "samples") {
162
+ if (!validate) {
163
+ return;
164
+ }
165
+ for (let i = 0; i < samples.length; i++) {
166
+ const v = samples[i];
167
+ if (!Number.isFinite(v)) {
168
+ throw new RangeError(`${fnName}: ${argName} contains NaN or Inf at index ${i}`);
169
+ }
170
+ }
171
+ }
172
+ function assertSamples(fnName, samples, validate, argName = "samples") {
173
+ assertNonEmptySamples(fnName, samples, argName);
174
+ assertFiniteSamples(fnName, samples, validate, argName);
175
+ }
176
+ function assertSampleRate(fnName, sampleRate) {
177
+ if (!Number.isInteger(sampleRate) || sampleRate < MIN_AUDIO_SAMPLE_RATE || sampleRate > MAX_AUDIO_SAMPLE_RATE) {
178
+ throw new RangeError(
179
+ `${fnName}: sampleRate out of supported range [${MIN_AUDIO_SAMPLE_RATE}, ${MAX_AUDIO_SAMPLE_RATE}]`
180
+ );
181
+ }
182
+ }
183
+
184
+ // src/_chain_config.ts
185
+ function flattenChainConfig(config) {
186
+ const out = {};
187
+ const walk = (node, prefix) => {
188
+ for (const [key, value] of Object.entries(node)) {
189
+ const path = prefix ? `${prefix}.${key}` : key;
190
+ if (typeof value === "number" || typeof value === "boolean") {
191
+ out[path] = value;
192
+ } else if (value !== null && typeof value === "object") {
193
+ walk(value, path);
194
+ } else if (value !== void 0) {
195
+ throw new TypeError(`Mastering override '${path}' must be a number or boolean.`);
196
+ }
197
+ }
198
+ };
199
+ walk(config, "");
200
+ return out;
201
+ }
202
+
203
+ // src/mastering_chain.ts
204
+ function requireModule() {
205
+ return getSonareModule();
206
+ }
207
+ function masterAudioRequest(requestOrSamples, sampleRate, preset, overrides, onProgress) {
208
+ if (requestOrSamples instanceof Float32Array) {
209
+ return {
210
+ samples: requestOrSamples,
211
+ sampleRate,
212
+ preset,
213
+ overrides: overrides ?? {},
214
+ onProgress
215
+ };
216
+ }
217
+ return requestOrSamples;
218
+ }
219
+ function masterAudioStereoRequest(requestOrLeft, right, sampleRate, preset, overrides, onProgress) {
220
+ if (requestOrLeft instanceof Float32Array) {
221
+ return {
222
+ left: requestOrLeft,
223
+ right,
224
+ sampleRate,
225
+ preset,
226
+ overrides: overrides ?? {},
227
+ onProgress
228
+ };
229
+ }
230
+ return requestOrLeft;
231
+ }
232
+ function masterAudio(samples, sampleRate = 22050, presetName = "pop", overrides = {}, onProgress) {
233
+ const request = masterAudioRequest(samples, sampleRate, presetName, overrides, onProgress);
234
+ const flat = flattenChainConfig(request.overrides ?? {});
235
+ if (request.onProgress || request.cancel) {
236
+ return requireModule().masterAudioWithProgress(
237
+ request.preset ?? "pop",
238
+ request.samples,
239
+ request.sampleRate ?? 22050,
240
+ flat,
241
+ request.onProgress ?? (() => {
242
+ }),
243
+ request.cancel ?? (() => false)
244
+ );
245
+ }
246
+ return requireModule().masterAudio(
247
+ request.preset ?? "pop",
248
+ request.samples,
249
+ request.sampleRate ?? 22050,
250
+ flat
251
+ );
252
+ }
253
+ function masterAudioStereo(left, right = void 0, sampleRate = 22050, presetName = "pop", overrides = {}, onProgress) {
254
+ const request = masterAudioStereoRequest(
255
+ left,
256
+ right,
257
+ sampleRate,
258
+ presetName,
259
+ overrides,
260
+ onProgress
261
+ );
262
+ const flat = flattenChainConfig(request.overrides ?? {});
263
+ if (request.left.length !== request.right.length) {
264
+ throw new Error("Stereo channel lengths must match.");
265
+ }
266
+ if (request.onProgress || request.cancel) {
267
+ return requireModule().masterAudioStereoWithProgress(
268
+ request.preset ?? "pop",
269
+ request.left,
270
+ request.right,
271
+ request.sampleRate ?? 22050,
272
+ flat,
273
+ request.onProgress ?? (() => {
274
+ }),
275
+ request.cancel ?? (() => false)
276
+ );
277
+ }
278
+ return requireModule().masterAudioStereo(
279
+ request.preset ?? "pop",
280
+ request.left,
281
+ request.right,
282
+ request.sampleRate ?? 22050,
283
+ flat
284
+ );
285
+ }
286
+
287
+ // src/codes.ts
288
+ function resolveOrdinalInRange(value, min, max, enumName) {
289
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < min || value > max) {
290
+ throw new RangeError(`Invalid ${enumName}: ${String(value)}`);
291
+ }
292
+ return value;
293
+ }
294
+ function resolveEnumOrdinal(value, values, enumName) {
295
+ if (typeof value === "number") {
296
+ const ordinals = Object.values(values);
297
+ const ordinal = resolveOrdinalInRange(
298
+ value,
299
+ Math.min(...ordinals),
300
+ Math.max(...ordinals),
301
+ enumName
302
+ );
303
+ if (!ordinals.includes(ordinal)) {
304
+ throw new RangeError(`Invalid ${enumName}: ${String(value)}`);
305
+ }
306
+ return ordinal;
307
+ }
308
+ if (typeof value === "string") {
309
+ const ordinal = values[value];
310
+ if (ordinal !== void 0) {
311
+ return ordinal;
312
+ }
313
+ }
314
+ throw new RangeError(`Invalid ${enumName}: ${String(value)}`);
315
+ }
316
+
317
+ // src/public_types_music.ts
318
+ var PitchClass = {
319
+ C: 0,
320
+ Cs: 1,
321
+ D: 2,
322
+ Ds: 3,
323
+ E: 4,
324
+ F: 5,
325
+ Fs: 6,
326
+ G: 7,
327
+ Gs: 8,
328
+ A: 9,
329
+ As: 10,
330
+ B: 11
331
+ };
332
+ var Mode = {
333
+ Major: 0,
334
+ Minor: 1,
335
+ Dorian: 2,
336
+ Phrygian: 3,
337
+ Lydian: 4,
338
+ Mixolydian: 5,
339
+ Locrian: 6
340
+ };
341
+ var KeyProfile = {
342
+ KrumhanslSchmuckler: 0,
343
+ Temperley: 1,
344
+ Shaath: 2,
345
+ FaraldoEDMT: 3,
346
+ FaraldoEDMA: 4,
347
+ FaraldoEDMM: 5,
348
+ BellmanBudge: 6
349
+ };
350
+
351
+ // src/analysis_helpers.ts
352
+ var PITCH_CLASS_NAMES = [
353
+ "C",
354
+ "C#",
355
+ "D",
356
+ "D#",
357
+ "E",
358
+ "F",
359
+ "F#",
360
+ "G",
361
+ "G#",
362
+ "A",
363
+ "A#",
364
+ "B"
365
+ ];
366
+ function pitchClassName(value) {
367
+ return PITCH_CLASS_NAMES[value] ?? "C";
368
+ }
369
+ var KEY_MODE_VALUES = {
370
+ major: Mode.Major,
371
+ minor: Mode.Minor,
372
+ dorian: Mode.Dorian,
373
+ phrygian: Mode.Phrygian,
374
+ lydian: Mode.Lydian,
375
+ mixolydian: Mode.Mixolydian,
376
+ locrian: Mode.Locrian
377
+ };
378
+ var KEY_PROFILE_VALUES = {
379
+ ks: KeyProfile.KrumhanslSchmuckler,
380
+ krumhansl: KeyProfile.KrumhanslSchmuckler,
381
+ temperley: KeyProfile.Temperley,
382
+ shaath: KeyProfile.Shaath,
383
+ keyfinder: KeyProfile.Shaath,
384
+ "faraldo-edmt": KeyProfile.FaraldoEDMT,
385
+ edmt: KeyProfile.FaraldoEDMT,
386
+ "faraldo-edma": KeyProfile.FaraldoEDMA,
387
+ edma: KeyProfile.FaraldoEDMA,
388
+ "faraldo-edmm": KeyProfile.FaraldoEDMM,
389
+ edmm: KeyProfile.FaraldoEDMM,
390
+ "bellman-budge": KeyProfile.BellmanBudge,
391
+ bellman: KeyProfile.BellmanBudge
392
+ };
393
+ function keyModeValues(modes) {
394
+ if (!modes) {
395
+ return [];
396
+ }
397
+ if (modes === "major-minor") {
398
+ return [Mode.Major, Mode.Minor];
399
+ }
400
+ if (modes === "all" || modes === "modal") {
401
+ return [
402
+ Mode.Major,
403
+ Mode.Minor,
404
+ Mode.Dorian,
405
+ Mode.Phrygian,
406
+ Mode.Lydian,
407
+ Mode.Mixolydian,
408
+ Mode.Locrian
409
+ ];
410
+ }
411
+ return modes.map((mode) => resolveEnumOrdinal(mode, KEY_MODE_VALUES, "key mode"));
412
+ }
413
+ function keyProfileValue(profile) {
414
+ if (profile === void 0) {
415
+ return -1;
416
+ }
417
+ return resolveEnumOrdinal(profile, KEY_PROFILE_VALUES, "key profile");
418
+ }
419
+ function convertChordAnalysisResult(wasm) {
420
+ return {
421
+ chords: wasm.chords.map((c) => ({
422
+ root: c.root,
423
+ bass: c.bass,
424
+ rootName: pitchClassName(c.root),
425
+ bassName: pitchClassName(c.bass),
426
+ quality: c.quality,
427
+ start: c.start,
428
+ end: c.end,
429
+ confidence: c.confidence,
430
+ name: c.name
431
+ }))
432
+ };
433
+ }
434
+ function chordChromaMethodValue(method) {
435
+ if (method === "stft") {
436
+ return 0;
437
+ }
438
+ if (method === "nnls") {
439
+ return 1;
440
+ }
441
+ throw new Error(`Invalid chord chroma method: ${method}`);
442
+ }
443
+ function convertAnalysisResult(wasm) {
444
+ const beatTimes = new Float32Array(wasm.beats.length);
445
+ for (let i = 0; i < wasm.beats.length; i++) {
446
+ beatTimes[i] = wasm.beats[i].time;
447
+ }
448
+ return {
449
+ bpm: wasm.bpm,
450
+ bpmConfidence: wasm.bpmConfidence,
451
+ bpmCandidates: wasm.bpmCandidates.map((candidate) => ({
452
+ value: candidate.value,
453
+ confidence: candidate.confidence,
454
+ relation: candidate.relation
455
+ })),
456
+ key: {
457
+ root: wasm.key.root,
458
+ mode: wasm.key.mode,
459
+ confidence: wasm.key.confidence,
460
+ name: wasm.key.name,
461
+ shortName: wasm.key.shortName
462
+ },
463
+ timeSignature: wasm.timeSignature,
464
+ timeSignatureCandidates: wasm.timeSignatureCandidates,
465
+ beatTimes,
466
+ beats: wasm.beats,
467
+ chords: wasm.chords.map((c) => ({
468
+ root: c.root,
469
+ bass: c.bass,
470
+ rootName: pitchClassName(c.root),
471
+ bassName: pitchClassName(c.bass),
472
+ quality: c.quality,
473
+ start: c.start,
474
+ end: c.end,
475
+ confidence: c.confidence,
476
+ name: c.name
477
+ })),
478
+ sections: wasm.sections.map((s) => ({
479
+ type: s.type,
480
+ start: s.start,
481
+ end: s.end,
482
+ energyLevel: s.energyLevel,
483
+ confidence: s.confidence,
484
+ name: s.name
485
+ })),
486
+ timbre: wasm.timbre,
487
+ dynamics: wasm.dynamics,
488
+ rhythm: wasm.rhythm,
489
+ melody: wasm.melody,
490
+ form: wasm.form
491
+ };
492
+ }
493
+
494
+ // src/quick_analysis.ts
495
+ function requireModule2() {
496
+ return getSonareModule();
497
+ }
498
+ function validateAnalysisInput(fnName, samples, sampleRate, options = {}) {
499
+ assertSampleRate(fnName, sampleRate);
500
+ assertSamples(fnName, samples, options.validate !== false);
501
+ }
502
+ function detectBpm(samples, sampleRate = 22050, options = {}) {
503
+ const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
504
+ validateAnalysisInput("detectBpm", request.samples, request.sampleRate ?? 22050, request);
505
+ return requireModule2().detectBpm(request.samples, request.sampleRate ?? 22050);
506
+ }
507
+ function detectKey(samples, sampleRate = 22050, options = {}) {
508
+ const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
509
+ validateAnalysisInput("detectKey", request.samples, request.sampleRate ?? 22050, request);
510
+ const result = requireModule2()._detectKeyWithOptions(
511
+ request.samples,
512
+ request.sampleRate ?? 22050,
513
+ request.nFft ?? 4096,
514
+ request.hopLength ?? 512,
515
+ request.useHpss ?? false,
516
+ request.loudnessWeighted ?? false,
517
+ request.highPassHz ?? 0,
518
+ keyModeValues(request.modes),
519
+ keyProfileValue(request.profile),
520
+ request.genreHint ?? ""
521
+ );
522
+ return {
523
+ root: result.root,
524
+ mode: result.mode,
525
+ confidence: result.confidence,
526
+ name: result.name,
527
+ shortName: result.shortName
528
+ };
529
+ }
530
+ function detectChords(samples, sampleRate = 22050, options = {}) {
531
+ const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
532
+ validateAnalysisInput("detectChords", request.samples, request.sampleRate ?? 22050, request);
533
+ const result = requireModule2().detectChords(
534
+ request.samples,
535
+ request.sampleRate ?? 22050,
536
+ request.minDuration ?? 0.3,
537
+ request.smoothingWindow ?? 2,
538
+ request.threshold ?? 0.5,
539
+ request.useTriadsOnly ?? false,
540
+ request.nFft ?? 2048,
541
+ request.hopLength ?? 512,
542
+ request.useBeatSync ?? true,
543
+ request.useHmm ?? false,
544
+ request.hmmBeamWidth ?? 24,
545
+ request.useKeyContext ?? false,
546
+ request.keyRoot ?? PitchClass.C,
547
+ request.keyMode ?? Mode.Major,
548
+ request.detectInversions ?? false,
549
+ chordChromaMethodValue(request.chromaMethod ?? "stft")
550
+ );
551
+ return convertChordAnalysisResult(result);
552
+ }
553
+ function analyzeWithProgress(samples, sampleRate = 22050, onProgress) {
554
+ const request = samples instanceof Float32Array ? { samples, sampleRate, onProgress } : samples;
555
+ validateAnalysisInput(
556
+ "analyzeWithProgress",
557
+ request.samples,
558
+ request.sampleRate ?? 22050,
559
+ request
560
+ );
561
+ const result = requireModule2().analyzeWithProgress(
562
+ request.samples,
563
+ request.sampleRate ?? 22050,
564
+ request.onProgress ?? (() => {
565
+ }),
566
+ request.cancel ?? (() => false)
567
+ );
568
+ return convertAnalysisResult(result);
569
+ }
570
+
571
+ // src/index.ts
572
+ var module = null;
573
+ var initPromise = null;
574
+ async function init(options) {
575
+ if (module) {
576
+ return;
577
+ }
578
+ if (initPromise) {
579
+ return initPromise;
580
+ }
581
+ initPromise = (async () => {
582
+ try {
583
+ const createModule = options?.moduleFactory ?? (await import("./sonare.js")).default;
584
+ module = await createModule(options);
585
+ setSonareModule(module);
586
+ } catch (error) {
587
+ initPromise = null;
588
+ throw error;
589
+ }
590
+ })();
591
+ return initPromise;
592
+ }
593
+
594
+ // src/worker.ts
595
+ function transferableBuffers(value, seen = /* @__PURE__ */ new Set()) {
596
+ const buffers = [];
597
+ const seenBuffers = /* @__PURE__ */ new Set();
598
+ const visit = (item) => {
599
+ if (item === null || item === void 0 || typeof item !== "object") {
600
+ return;
601
+ }
602
+ if (ArrayBuffer.isView(item)) {
603
+ const buffer = item.buffer;
604
+ if (buffer instanceof ArrayBuffer && !seenBuffers.has(buffer)) {
605
+ seenBuffers.add(buffer);
606
+ buffers.push(buffer);
607
+ }
608
+ return;
609
+ }
610
+ if (item instanceof ArrayBuffer) {
611
+ if (!seenBuffers.has(item)) {
612
+ seenBuffers.add(item);
613
+ buffers.push(item);
614
+ }
615
+ return;
616
+ }
617
+ if (seen.has(item)) {
618
+ return;
619
+ }
620
+ seen.add(item);
621
+ if (Array.isArray(item)) {
622
+ item.forEach(visit);
623
+ return;
624
+ }
625
+ Object.values(item).forEach(visit);
626
+ };
627
+ visit(value);
628
+ return buffers;
629
+ }
630
+ function errorMessage(error) {
631
+ if (error instanceof SonareError) {
632
+ return {
633
+ name: error.name,
634
+ message: error.message,
635
+ code: error.code,
636
+ codeName: error.codeName
637
+ };
638
+ }
639
+ if (error instanceof Error) {
640
+ return { name: error.name, message: error.message };
641
+ }
642
+ return { name: "Error", message: String(error) };
643
+ }
644
+ function cancelledError() {
645
+ return new SonareError(8 /* Cancelled */, "Cancelled", "Operation cancelled");
646
+ }
647
+ function installOfflineWorkerEndpoint(endpoint2) {
648
+ const cancelled = /* @__PURE__ */ new Set();
649
+ const run = async (message) => {
650
+ const cancelFlag = message.cancelBuffer ? new Int32Array(message.cancelBuffer) : void 0;
651
+ const isCancelled = () => cancelled.has(message.id) || cancelFlag !== void 0 && Atomics.load(cancelFlag, 0) !== 0;
652
+ const onProgress = (progress, stage) => {
653
+ endpoint2.postMessage({ type: "sonare:offline-progress", id: message.id, progress, stage });
654
+ return isCancelled() ? false : void 0;
655
+ };
656
+ try {
657
+ await init();
658
+ if (isCancelled()) {
659
+ throw cancelledError();
660
+ }
661
+ let result;
662
+ switch (message.operation) {
663
+ case "analyze":
664
+ result = analyzeWithProgress({
665
+ ...message.request,
666
+ onProgress
667
+ });
668
+ break;
669
+ case "detectBpm":
670
+ result = detectBpm(message.request);
671
+ break;
672
+ case "detectKey":
673
+ result = detectKey(message.request);
674
+ break;
675
+ case "detectChords":
676
+ result = detectChords(message.request);
677
+ break;
678
+ case "masterAudio":
679
+ result = masterAudio({
680
+ ...message.request,
681
+ onProgress
682
+ });
683
+ break;
684
+ case "masterAudioStereo":
685
+ result = masterAudioStereo({
686
+ ...message.request,
687
+ onProgress
688
+ });
689
+ break;
690
+ }
691
+ if (isCancelled()) {
692
+ throw cancelledError();
693
+ }
694
+ endpoint2.postMessage(
695
+ { type: "sonare:offline-result", id: message.id, result },
696
+ transferableBuffers(result)
697
+ );
698
+ } catch (error) {
699
+ endpoint2.postMessage({
700
+ type: "sonare:offline-error",
701
+ id: message.id,
702
+ error: errorMessage(error)
703
+ });
704
+ } finally {
705
+ cancelled.delete(message.id);
706
+ }
707
+ };
708
+ endpoint2.addEventListener("message", (event) => {
709
+ const message = event.data;
710
+ if (message.type === "sonare:offline-cancel") {
711
+ cancelled.add(message.id);
712
+ return;
713
+ }
714
+ void run(message);
715
+ });
716
+ }
717
+ function browserWorkerEndpoint() {
718
+ const scope = globalThis;
719
+ if (scope.document !== void 0 || !scope.postMessage || !scope.addEventListener) {
720
+ return null;
721
+ }
722
+ return {
723
+ postMessage: (message, transfer) => scope.postMessage?.(message, transfer),
724
+ addEventListener: (type, listener) => scope.addEventListener?.(type, listener)
725
+ };
726
+ }
727
+ var endpoint = browserWorkerEndpoint();
728
+ if (endpoint) {
729
+ installOfflineWorkerEndpoint(endpoint);
730
+ }
731
+ export {
732
+ installOfflineWorkerEndpoint
733
+ };
734
+ //# sourceMappingURL=worker.js.map