@libraz/libsonare 1.5.5 → 1.6.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 +5730 -0
- package/dist/analysis.js +2464 -0
- package/dist/analysis.js.map +1 -0
- package/dist/index.d.ts +759 -35
- package/dist/index.js +904 -209
- 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 +707 -0
- package/dist/worker.js.map +1 -0
- package/dist/worklet.d.ts +574 -86
- package/dist/worklet.js +1634 -235
- 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 +6 -0
- package/src/clip_page_streamer.ts +62 -8
- package/src/codes.ts +51 -64
- package/src/effects_mastering.ts +1 -0
- package/src/errors.ts +1 -0
- package/src/feature_core.ts +140 -2
- package/src/feature_music.ts +17 -2
- package/src/feature_pitch.ts +70 -1
- package/src/feature_spectral.ts +231 -5
- package/src/feature_spectrogram.ts +159 -0
- package/src/features.ts +16 -1
- package/src/index.ts +101 -7
- 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/opfs_clip_pages.ts +26 -1
- package/src/project.ts +7 -0
- package/src/project_class.ts +62 -8
- package/src/project_internal.ts +24 -29
- package/src/project_types.ts +69 -10
- package/src/public_types.ts +68 -0
- package/src/public_types_mastering.ts +22 -0
- package/src/public_types_mixing.ts +11 -2
- package/src/public_types_music.ts +9 -0
- package/src/public_types_spectral.ts +33 -0
- package/src/quick_analysis.ts +25 -7
- package/src/realtime_engine.ts +153 -3
- package/src/realtime_voice_changer.ts +51 -77
- package/src/sonare-analysis.js.d.ts +8 -0
- package/src/sonare.js.d.ts +276 -6
- package/src/streaming_processors.ts +15 -0
- package/src/web_midi.ts +36 -4
- 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 +212 -4
- package/src/worklet/engine-offline.ts +7 -2
- package/src/worklet/engine-parameter-facade.ts +26 -5
- package/src/worklet/engine-processor.ts +383 -42
- package/src/worklet/engine-register.ts +8 -0
- package/src/worklet/engine-strips.ts +17 -1
- package/src/worklet/engine-sync.ts +2 -6
- package/src/worklet/engine-tempo-facade.ts +8 -6
- package/src/worklet/engine.ts +380 -13
- package/src/worklet/guards.ts +22 -1
- package/src/worklet/messages.ts +125 -7
- package/src/worklet/protocol.ts +301 -17
- package/src/worklet/voice-changer-processor.ts +12 -15
- package/src/worklet.ts +20 -1
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
|
|
|
8
8
|
ErrorCode2[ErrorCode2["OutOfMemory"] = 5] = "OutOfMemory";
|
|
9
9
|
ErrorCode2[ErrorCode2["NotSupported"] = 6] = "NotSupported";
|
|
10
10
|
ErrorCode2[ErrorCode2["InvalidState"] = 7] = "InvalidState";
|
|
11
|
+
ErrorCode2[ErrorCode2["Cancelled"] = 8] = "Cancelled";
|
|
11
12
|
ErrorCode2[ErrorCode2["Unknown"] = 99] = "Unknown";
|
|
12
13
|
return ErrorCode2;
|
|
13
14
|
})(ErrorCode || {});
|
|
@@ -405,6 +406,8 @@ function flattenChainConfig(config) {
|
|
|
405
406
|
out[path] = value;
|
|
406
407
|
} else if (value !== null && typeof value === "object") {
|
|
407
408
|
walk(value, path);
|
|
409
|
+
} else if (value !== void 0) {
|
|
410
|
+
throw new TypeError(`Mastering override '${path}' must be a number or boolean.`);
|
|
408
411
|
}
|
|
409
412
|
}
|
|
410
413
|
};
|
|
@@ -446,12 +449,14 @@ function masterAudioStereoRequest(requestOrLeft, right, sampleRate, preset, over
|
|
|
446
449
|
}
|
|
447
450
|
function masteringChain(samples, sampleRate = 22050, config = {}, onProgress) {
|
|
448
451
|
const request = samples instanceof Float32Array ? { samples, sampleRate, config, onProgress } : samples;
|
|
449
|
-
if (request.onProgress) {
|
|
452
|
+
if (request.onProgress || request.cancel) {
|
|
450
453
|
return requireModule3().masteringChainWithProgress(
|
|
451
454
|
request.samples,
|
|
452
455
|
request.sampleRate ?? 22050,
|
|
453
456
|
canonicalChainConfig(request.config ?? {}),
|
|
454
|
-
request.onProgress
|
|
457
|
+
request.onProgress ?? (() => {
|
|
458
|
+
}),
|
|
459
|
+
request.cancel ?? (() => false)
|
|
455
460
|
);
|
|
456
461
|
}
|
|
457
462
|
return requireModule3().masteringChain(
|
|
@@ -465,13 +470,15 @@ function masteringChainStereo(left, right, sampleRate = 22050, config = {}, onPr
|
|
|
465
470
|
if (request.left.length !== request.right.length) {
|
|
466
471
|
throw new Error("Stereo channel lengths must match.");
|
|
467
472
|
}
|
|
468
|
-
if (request.onProgress) {
|
|
473
|
+
if (request.onProgress || request.cancel) {
|
|
469
474
|
return requireModule3().masteringChainStereoWithProgress(
|
|
470
475
|
request.left,
|
|
471
476
|
request.right,
|
|
472
477
|
request.sampleRate ?? 22050,
|
|
473
478
|
canonicalChainConfig(request.config ?? {}),
|
|
474
|
-
request.onProgress
|
|
479
|
+
request.onProgress ?? (() => {
|
|
480
|
+
}),
|
|
481
|
+
request.cancel ?? (() => false)
|
|
475
482
|
);
|
|
476
483
|
}
|
|
477
484
|
return requireModule3().masteringChainStereo(
|
|
@@ -490,7 +497,8 @@ function masteringChainWithProgress(samples, sampleRate = 22050, config = {}, on
|
|
|
490
497
|
request.samples,
|
|
491
498
|
request.sampleRate ?? 22050,
|
|
492
499
|
canonicalChainConfig(request.config ?? {}),
|
|
493
|
-
request.onProgress
|
|
500
|
+
request.onProgress,
|
|
501
|
+
request.cancel ?? (() => false)
|
|
494
502
|
);
|
|
495
503
|
}
|
|
496
504
|
function masteringChainStereoWithProgress(left, right, sampleRate = 22050, config = {}, onProgress) {
|
|
@@ -506,7 +514,8 @@ function masteringChainStereoWithProgress(left, right, sampleRate = 22050, confi
|
|
|
506
514
|
request.right,
|
|
507
515
|
request.sampleRate ?? 22050,
|
|
508
516
|
canonicalChainConfig(request.config ?? {}),
|
|
509
|
-
request.onProgress
|
|
517
|
+
request.onProgress,
|
|
518
|
+
request.cancel ?? (() => false)
|
|
510
519
|
);
|
|
511
520
|
}
|
|
512
521
|
function masteringPresetNames() {
|
|
@@ -515,13 +524,15 @@ function masteringPresetNames() {
|
|
|
515
524
|
function masterAudio(samples, sampleRate = 22050, presetName = "pop", overrides = {}, onProgress) {
|
|
516
525
|
const request = masterAudioRequest(samples, sampleRate, presetName, overrides, onProgress);
|
|
517
526
|
const flat = flattenChainConfig(request.overrides ?? {});
|
|
518
|
-
if (request.onProgress) {
|
|
527
|
+
if (request.onProgress || request.cancel) {
|
|
519
528
|
return requireModule3().masterAudioWithProgress(
|
|
520
529
|
request.preset ?? "pop",
|
|
521
530
|
request.samples,
|
|
522
531
|
request.sampleRate ?? 22050,
|
|
523
532
|
flat,
|
|
524
|
-
request.onProgress
|
|
533
|
+
request.onProgress ?? (() => {
|
|
534
|
+
}),
|
|
535
|
+
request.cancel ?? (() => false)
|
|
525
536
|
);
|
|
526
537
|
}
|
|
527
538
|
return requireModule3().masterAudio(
|
|
@@ -544,14 +555,16 @@ function masterAudioStereo(left, right = void 0, sampleRate = 22050, presetName
|
|
|
544
555
|
if (request.left.length !== request.right.length) {
|
|
545
556
|
throw new Error("Stereo channel lengths must match.");
|
|
546
557
|
}
|
|
547
|
-
if (request.onProgress) {
|
|
558
|
+
if (request.onProgress || request.cancel) {
|
|
548
559
|
return requireModule3().masterAudioStereoWithProgress(
|
|
549
560
|
request.preset ?? "pop",
|
|
550
561
|
request.left,
|
|
551
562
|
request.right,
|
|
552
563
|
request.sampleRate ?? 22050,
|
|
553
564
|
flat,
|
|
554
|
-
request.onProgress
|
|
565
|
+
request.onProgress ?? (() => {
|
|
566
|
+
}),
|
|
567
|
+
request.cancel ?? (() => false)
|
|
555
568
|
);
|
|
556
569
|
}
|
|
557
570
|
return requireModule3().masterAudioStereo(
|
|
@@ -572,7 +585,8 @@ function masterAudioWithProgress(samples, sampleRate = 22050, presetName = "pop"
|
|
|
572
585
|
request.samples,
|
|
573
586
|
request.sampleRate ?? 22050,
|
|
574
587
|
flattenChainConfig(request.overrides ?? {}),
|
|
575
|
-
request.onProgress
|
|
588
|
+
request.onProgress,
|
|
589
|
+
request.cancel ?? (() => false)
|
|
576
590
|
);
|
|
577
591
|
}
|
|
578
592
|
function masterAudioStereoWithProgress(left, right = void 0, sampleRate = 22050, presetName = "pop", overrides = null, onProgress) {
|
|
@@ -596,7 +610,8 @@ function masterAudioStereoWithProgress(left, right = void 0, sampleRate = 22050,
|
|
|
596
610
|
request.right,
|
|
597
611
|
request.sampleRate ?? 22050,
|
|
598
612
|
flattenChainConfig(request.overrides ?? {}),
|
|
599
|
-
request.onProgress
|
|
613
|
+
request.onProgress,
|
|
614
|
+
request.cancel ?? (() => false)
|
|
600
615
|
);
|
|
601
616
|
}
|
|
602
617
|
|
|
@@ -759,7 +774,10 @@ function masteringDynamicsCompressor(samples, sampleRate, options = {}) {
|
|
|
759
774
|
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
760
775
|
assertSamples("masteringDynamicsCompressor", request.samples, request.validate !== false);
|
|
761
776
|
const detector = typeof request.detector === "string" ? COMPRESSOR_DETECTOR_MAP[request.detector] : request.detector;
|
|
762
|
-
const opts =
|
|
777
|
+
const opts = Object.assign(
|
|
778
|
+
Object.create(Object.getPrototypeOf(request)),
|
|
779
|
+
request
|
|
780
|
+
);
|
|
763
781
|
if (detector !== void 0) {
|
|
764
782
|
opts.detector = detector;
|
|
765
783
|
}
|
|
@@ -848,6 +866,36 @@ function mixStereo(leftChannels, rightChannels, sampleRate = 48e3, options = {})
|
|
|
848
866
|
function requireModule8() {
|
|
849
867
|
return getSonareModule();
|
|
850
868
|
}
|
|
869
|
+
function tone(frequency = 440, sampleRate = 22050, duration = 1, phase = 0, amplitude = 1) {
|
|
870
|
+
const request = typeof frequency === "number" ? { frequency, sampleRate, duration, phase, amplitude } : frequency;
|
|
871
|
+
return requireModule8().tone(
|
|
872
|
+
request.frequency ?? 440,
|
|
873
|
+
request.sampleRate ?? 22050,
|
|
874
|
+
request.duration ?? 1,
|
|
875
|
+
request.phase ?? 0,
|
|
876
|
+
request.amplitude ?? 1
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
function chirp(fmin = 440, fmax = 880, sampleRate = 22050, duration = 1, linear = true) {
|
|
880
|
+
const request = typeof fmin === "number" ? { fmin, fmax, sampleRate, duration, linear } : fmin;
|
|
881
|
+
return requireModule8().chirp(
|
|
882
|
+
request.fmin ?? 440,
|
|
883
|
+
request.fmax ?? 880,
|
|
884
|
+
request.sampleRate ?? 22050,
|
|
885
|
+
request.duration ?? 1,
|
|
886
|
+
request.linear ?? true
|
|
887
|
+
);
|
|
888
|
+
}
|
|
889
|
+
function clicks(times, sampleRate = 22050, length = 0, frequency = 1e3, clickDuration = 0.1) {
|
|
890
|
+
const request = times instanceof Float32Array ? { times, sampleRate, length, frequency, clickDuration } : times;
|
|
891
|
+
return requireModule8().clicks(
|
|
892
|
+
request.times,
|
|
893
|
+
request.sampleRate ?? 22050,
|
|
894
|
+
request.length ?? 0,
|
|
895
|
+
request.frequency ?? 1e3,
|
|
896
|
+
request.clickDuration ?? 0.1
|
|
897
|
+
);
|
|
898
|
+
}
|
|
851
899
|
function hzToMel(hz) {
|
|
852
900
|
return requireModule8().hzToMel(hz);
|
|
853
901
|
}
|
|
@@ -944,6 +992,12 @@ function fixFrames(frames, xMin = 0, xMax = -1, pad = true) {
|
|
|
944
992
|
}
|
|
945
993
|
return requireModule8().fixFrames(frames, xMin, xMax, pad);
|
|
946
994
|
}
|
|
995
|
+
function onsetBacktrack(events, energy) {
|
|
996
|
+
if (!(events instanceof Int32Array)) {
|
|
997
|
+
return onsetBacktrack(events.events, events.energy);
|
|
998
|
+
}
|
|
999
|
+
return requireModule8().onsetBacktrack(events, energy);
|
|
1000
|
+
}
|
|
947
1001
|
function peakPick(values, preMax, postMax, preAvg, postAvg, delta, wait) {
|
|
948
1002
|
if (!(values instanceof Float32Array)) {
|
|
949
1003
|
const r = values;
|
|
@@ -988,12 +1042,28 @@ function tonnetz(chromagram, nChroma, nFrames) {
|
|
|
988
1042
|
}
|
|
989
1043
|
return requireModule8().tonnetz(chromagram, nChroma, nFrames);
|
|
990
1044
|
}
|
|
991
|
-
function tempogram(onsetEnvelope2, sampleRate = 22050, hopLength = 512, winLength = 384, mode = "autocorrelation") {
|
|
1045
|
+
function tempogram(onsetEnvelope2, sampleRate = 22050, hopLength = 512, winLength = 384, mode = "autocorrelation", center = true, norm = true) {
|
|
992
1046
|
if (!(onsetEnvelope2 instanceof Float32Array)) {
|
|
993
1047
|
const r = onsetEnvelope2;
|
|
994
|
-
return tempogram(
|
|
1048
|
+
return tempogram(
|
|
1049
|
+
r.onsetEnvelope,
|
|
1050
|
+
r.sampleRate,
|
|
1051
|
+
r.hopLength,
|
|
1052
|
+
r.winLength,
|
|
1053
|
+
r.mode,
|
|
1054
|
+
r.center,
|
|
1055
|
+
r.norm
|
|
1056
|
+
);
|
|
995
1057
|
}
|
|
996
|
-
return requireModule8().tempogram(
|
|
1058
|
+
return requireModule8().tempogram(
|
|
1059
|
+
onsetEnvelope2,
|
|
1060
|
+
sampleRate,
|
|
1061
|
+
hopLength,
|
|
1062
|
+
winLength,
|
|
1063
|
+
mode,
|
|
1064
|
+
center,
|
|
1065
|
+
norm
|
|
1066
|
+
);
|
|
997
1067
|
}
|
|
998
1068
|
function cyclicTempogram(onsetEnvelope2, sampleRate = 22050, hopLength = 512, winLength = 384, bpmMin = 60, nBins = 60) {
|
|
999
1069
|
if (!(onsetEnvelope2 instanceof Float32Array)) {
|
|
@@ -1327,7 +1397,7 @@ function onsetStrengthMulti(samples, sampleRate = 22050, nFft = 2048, hopLength
|
|
|
1327
1397
|
validatePositiveIntegers("onsetStrengthMulti", { nFft, hopLength, nMels, nBands });
|
|
1328
1398
|
return requireModule9().onsetStrengthMulti(samples, sampleRate, nFft, hopLength, nMels, nBands);
|
|
1329
1399
|
}
|
|
1330
|
-
function fourierTempogram(onsetEnvelope2, sampleRate = 22050, hopLength = 512, winLength = 384, options = {}) {
|
|
1400
|
+
function fourierTempogram(onsetEnvelope2, sampleRate = 22050, hopLength = 512, winLength = 384, center = true, norm = true, options = {}) {
|
|
1331
1401
|
if (!(onsetEnvelope2 instanceof Float32Array)) {
|
|
1332
1402
|
const request = onsetEnvelope2;
|
|
1333
1403
|
return fourierTempogram(
|
|
@@ -1335,13 +1405,22 @@ function fourierTempogram(onsetEnvelope2, sampleRate = 22050, hopLength = 512, w
|
|
|
1335
1405
|
request.sampleRate,
|
|
1336
1406
|
request.hopLength,
|
|
1337
1407
|
request.winLength,
|
|
1408
|
+
request.center,
|
|
1409
|
+
request.norm,
|
|
1338
1410
|
request
|
|
1339
1411
|
);
|
|
1340
1412
|
}
|
|
1341
1413
|
assertSampleRate("fourierTempogram", sampleRate);
|
|
1342
1414
|
assertSamples("fourierTempogram", onsetEnvelope2, options.validate !== false, "onsetEnvelope");
|
|
1343
1415
|
validatePositiveIntegers("fourierTempogram", { hopLength, winLength });
|
|
1344
|
-
return requireModule9().fourierTempogram(
|
|
1416
|
+
return requireModule9().fourierTempogram(
|
|
1417
|
+
onsetEnvelope2,
|
|
1418
|
+
sampleRate,
|
|
1419
|
+
hopLength,
|
|
1420
|
+
winLength,
|
|
1421
|
+
center,
|
|
1422
|
+
norm
|
|
1423
|
+
);
|
|
1345
1424
|
}
|
|
1346
1425
|
function tempogramRatio(tempogramData, winLength = 384, sampleRate = 22050, hopLength = 512, factors, options = {}) {
|
|
1347
1426
|
if (!(tempogramData instanceof Float32Array)) {
|
|
@@ -1392,6 +1471,21 @@ function shortTermLufs(samples, sampleRate = 22050, options = {}) {
|
|
|
1392
1471
|
function requireModule10() {
|
|
1393
1472
|
return getSonareModule();
|
|
1394
1473
|
}
|
|
1474
|
+
function piptrack(samples, sampleRate = 22050, nFft = 2048, hopLength = 512, fmin = 150, fmax = 4e3, threshold = 0.1) {
|
|
1475
|
+
if (!(samples instanceof Float32Array)) {
|
|
1476
|
+
const request = samples;
|
|
1477
|
+
return piptrack(
|
|
1478
|
+
request.samples,
|
|
1479
|
+
request.sampleRate,
|
|
1480
|
+
request.nFft,
|
|
1481
|
+
request.hopLength,
|
|
1482
|
+
request.fmin,
|
|
1483
|
+
request.fmax,
|
|
1484
|
+
request.threshold
|
|
1485
|
+
);
|
|
1486
|
+
}
|
|
1487
|
+
return requireModule10().piptrack(samples, sampleRate, nFft, hopLength, fmin, fmax, threshold);
|
|
1488
|
+
}
|
|
1395
1489
|
function pitchYin(samples, sampleRate = 22050, frameLength = 2048, hopLength = 512, fmin = 65, fmax = 2093, threshold = 0.1, fillNa = false) {
|
|
1396
1490
|
if (!(samples instanceof Float32Array)) {
|
|
1397
1491
|
const request = samples;
|
|
@@ -1442,6 +1536,13 @@ function pitchPyin(samples, sampleRate = 22050, frameLength = 2048, hopLength =
|
|
|
1442
1536
|
fillNa
|
|
1443
1537
|
);
|
|
1444
1538
|
}
|
|
1539
|
+
function noteSegments(request) {
|
|
1540
|
+
return requireModule10().noteSegments(request.f0Hz, request.voicedProb, request.frameRate, {
|
|
1541
|
+
segmentationThresholdCents: request.segmentationThresholdCents,
|
|
1542
|
+
minNoteMs: request.minNoteMs,
|
|
1543
|
+
referenceHz: request.referenceHz
|
|
1544
|
+
});
|
|
1545
|
+
}
|
|
1445
1546
|
|
|
1446
1547
|
// src/feature_resample.ts
|
|
1447
1548
|
function requireModule11() {
|
|
@@ -1458,6 +1559,15 @@ function resample(samples, srcSr, targetSr) {
|
|
|
1458
1559
|
function requireModule12() {
|
|
1459
1560
|
return getSonareModule();
|
|
1460
1561
|
}
|
|
1562
|
+
function validateSegmentMatrix(fnName, data, rows, cols, dataName) {
|
|
1563
|
+
assertPositiveInteger(fnName, rows, "rows");
|
|
1564
|
+
assertPositiveInteger(fnName, cols, "cols");
|
|
1565
|
+
assertSamples(fnName, data, true, dataName);
|
|
1566
|
+
const expected = rows * cols;
|
|
1567
|
+
if (!Number.isSafeInteger(expected) || data.length !== expected) {
|
|
1568
|
+
throw new RangeError(`${fnName}: ${dataName} length must equal rows * cols`);
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1461
1571
|
function spectralCentroid(samples, sampleRate = 22050, nFft = 2048, hopLength = 512) {
|
|
1462
1572
|
if (!(samples instanceof Float32Array)) {
|
|
1463
1573
|
return spectralCentroid(samples.samples, samples.sampleRate, samples.nFft, samples.hopLength);
|
|
@@ -1602,11 +1712,17 @@ function ebur128LoudnessRange(samples, sampleRate = 22050) {
|
|
|
1602
1712
|
}
|
|
1603
1713
|
return requireModule12().ebur128LoudnessRange(samples, sampleRate);
|
|
1604
1714
|
}
|
|
1605
|
-
function spectralBandwidth(samples, sampleRate = 22050, nFft = 2048, hopLength = 512) {
|
|
1715
|
+
function spectralBandwidth(samples, sampleRate = 22050, nFft = 2048, hopLength = 512, p = 2) {
|
|
1606
1716
|
if (!(samples instanceof Float32Array)) {
|
|
1607
|
-
return spectralBandwidth(
|
|
1717
|
+
return spectralBandwidth(
|
|
1718
|
+
samples.samples,
|
|
1719
|
+
samples.sampleRate,
|
|
1720
|
+
samples.nFft,
|
|
1721
|
+
samples.hopLength,
|
|
1722
|
+
samples.p
|
|
1723
|
+
);
|
|
1608
1724
|
}
|
|
1609
|
-
return requireModule12().spectralBandwidth(samples, sampleRate, nFft, hopLength);
|
|
1725
|
+
return requireModule12().spectralBandwidth(samples, sampleRate, nFft, hopLength, p);
|
|
1610
1726
|
}
|
|
1611
1727
|
function spectralRolloff(samples, sampleRate = 22050, nFft = 2048, hopLength = 512, rollPercent = 0.85) {
|
|
1612
1728
|
if (!(samples instanceof Float32Array)) {
|
|
@@ -1626,6 +1742,18 @@ function spectralFlatness(samples, sampleRate = 22050, nFft = 2048, hopLength =
|
|
|
1626
1742
|
}
|
|
1627
1743
|
return requireModule12().spectralFlatness(samples, sampleRate, nFft, hopLength);
|
|
1628
1744
|
}
|
|
1745
|
+
function spectralFlux(samples, sampleRate = 22050, nFft = 2048, hopLength = 512, lag = 1) {
|
|
1746
|
+
if (!(samples instanceof Float32Array)) {
|
|
1747
|
+
return spectralFlux(
|
|
1748
|
+
samples.samples,
|
|
1749
|
+
samples.sampleRate,
|
|
1750
|
+
samples.nFft,
|
|
1751
|
+
samples.hopLength,
|
|
1752
|
+
samples.lag
|
|
1753
|
+
);
|
|
1754
|
+
}
|
|
1755
|
+
return requireModule12().spectralFlux(samples, sampleRate, nFft, hopLength, lag);
|
|
1756
|
+
}
|
|
1629
1757
|
function zeroCrossingRate(samples, sampleRate = 22050, frameLength = 2048, hopLength = 512) {
|
|
1630
1758
|
if (!(samples instanceof Float32Array)) {
|
|
1631
1759
|
return zeroCrossingRate(
|
|
@@ -1643,6 +1771,107 @@ function rmsEnergy(samples, sampleRate = 22050, frameLength = 2048, hopLength =
|
|
|
1643
1771
|
}
|
|
1644
1772
|
return requireModule12().rmsEnergy(samples, sampleRate, frameLength, hopLength);
|
|
1645
1773
|
}
|
|
1774
|
+
function segmentCrossSimilarity(request) {
|
|
1775
|
+
validateSegmentMatrix("segmentCrossSimilarity", request.x, request.xRows, request.xCols, "x");
|
|
1776
|
+
validateSegmentMatrix("segmentCrossSimilarity", request.y, request.yRows, request.yCols, "y");
|
|
1777
|
+
if (request.xRows !== request.yRows) {
|
|
1778
|
+
throw new RangeError("segmentCrossSimilarity: feature dimensions must match");
|
|
1779
|
+
}
|
|
1780
|
+
assertNonNegativeInteger("segmentCrossSimilarity", request.k ?? 0, "k");
|
|
1781
|
+
return requireModule12().segmentCrossSimilarity(
|
|
1782
|
+
request.x,
|
|
1783
|
+
request.xRows,
|
|
1784
|
+
request.xCols,
|
|
1785
|
+
request.y,
|
|
1786
|
+
request.yRows,
|
|
1787
|
+
request.yCols,
|
|
1788
|
+
request.k ?? 0,
|
|
1789
|
+
request.metric ?? "cosine",
|
|
1790
|
+
request.mode ?? "connectivity"
|
|
1791
|
+
);
|
|
1792
|
+
}
|
|
1793
|
+
function segmentRecurrenceMatrix(request) {
|
|
1794
|
+
validateSegmentMatrix(
|
|
1795
|
+
"segmentRecurrenceMatrix",
|
|
1796
|
+
request.data,
|
|
1797
|
+
request.rows,
|
|
1798
|
+
request.cols,
|
|
1799
|
+
"data"
|
|
1800
|
+
);
|
|
1801
|
+
assertNonNegativeInteger("segmentRecurrenceMatrix", request.k ?? 0, "k");
|
|
1802
|
+
assertNonNegativeInteger("segmentRecurrenceMatrix", request.width ?? 1, "width");
|
|
1803
|
+
return requireModule12().segmentRecurrenceMatrix(
|
|
1804
|
+
request.data,
|
|
1805
|
+
request.rows,
|
|
1806
|
+
request.cols,
|
|
1807
|
+
request.k ?? 0,
|
|
1808
|
+
request.width ?? 1,
|
|
1809
|
+
request.sym ?? false,
|
|
1810
|
+
request.metric ?? "euclidean",
|
|
1811
|
+
request.mode ?? "connectivity"
|
|
1812
|
+
);
|
|
1813
|
+
}
|
|
1814
|
+
function segmentRecurrenceToLag(request) {
|
|
1815
|
+
validateSegmentMatrix(
|
|
1816
|
+
"segmentRecurrenceToLag",
|
|
1817
|
+
request.recurrence,
|
|
1818
|
+
request.n,
|
|
1819
|
+
request.n,
|
|
1820
|
+
"recurrence"
|
|
1821
|
+
);
|
|
1822
|
+
return requireModule12().segmentRecurrenceToLag(
|
|
1823
|
+
request.recurrence,
|
|
1824
|
+
request.n,
|
|
1825
|
+
request.pad ?? false
|
|
1826
|
+
);
|
|
1827
|
+
}
|
|
1828
|
+
function segmentLagToRecurrence(request) {
|
|
1829
|
+
validateSegmentMatrix("segmentLagToRecurrence", request.lag, request.rows, request.lags, "lag");
|
|
1830
|
+
return requireModule12().segmentLagToRecurrence(request.lag, request.rows, request.lags);
|
|
1831
|
+
}
|
|
1832
|
+
function segmentSubsegment(request) {
|
|
1833
|
+
validateSegmentMatrix("segmentSubsegment", request.data, request.rows, request.cols, "data");
|
|
1834
|
+
assertPositiveInteger("segmentSubsegment", request.nSegments ?? 4, "nSegments");
|
|
1835
|
+
return requireModule12().segmentSubsegment(
|
|
1836
|
+
request.data,
|
|
1837
|
+
request.rows,
|
|
1838
|
+
request.cols,
|
|
1839
|
+
request.boundaries,
|
|
1840
|
+
request.nSegments ?? 4
|
|
1841
|
+
);
|
|
1842
|
+
}
|
|
1843
|
+
function segmentAgglomerative(request) {
|
|
1844
|
+
validateSegmentMatrix("segmentAgglomerative", request.data, request.rows, request.cols, "data");
|
|
1845
|
+
assertPositiveInteger("segmentAgglomerative", request.k, "k");
|
|
1846
|
+
return requireModule12().segmentAgglomerative(
|
|
1847
|
+
request.data,
|
|
1848
|
+
request.rows,
|
|
1849
|
+
request.cols,
|
|
1850
|
+
request.k,
|
|
1851
|
+
request.linkage ?? "average"
|
|
1852
|
+
);
|
|
1853
|
+
}
|
|
1854
|
+
function segmentPathEnhance(request) {
|
|
1855
|
+
validateSegmentMatrix(
|
|
1856
|
+
"segmentPathEnhance",
|
|
1857
|
+
request.recurrence,
|
|
1858
|
+
request.n,
|
|
1859
|
+
request.n,
|
|
1860
|
+
"recurrence"
|
|
1861
|
+
);
|
|
1862
|
+
assertPositiveInteger("segmentPathEnhance", request.win, "win");
|
|
1863
|
+
assertPositiveInteger("segmentPathEnhance", request.maxRatio ?? 2, "maxRatio");
|
|
1864
|
+
assertNonNegativeInteger("segmentPathEnhance", request.minRatio ?? 0, "minRatio");
|
|
1865
|
+
assertPositiveInteger("segmentPathEnhance", request.nFilters ?? 7, "nFilters");
|
|
1866
|
+
return requireModule12().segmentPathEnhance(
|
|
1867
|
+
request.recurrence,
|
|
1868
|
+
request.n,
|
|
1869
|
+
request.win,
|
|
1870
|
+
request.maxRatio ?? 2,
|
|
1871
|
+
request.minRatio ?? 0,
|
|
1872
|
+
request.nFilters ?? 7
|
|
1873
|
+
);
|
|
1874
|
+
}
|
|
1646
1875
|
|
|
1647
1876
|
// src/feature_spectrogram.ts
|
|
1648
1877
|
function requireModule13() {
|
|
@@ -1821,6 +2050,53 @@ function mfcc(samples, sampleRate = 22050, nFft = 2048, hopLength = 512, nMels =
|
|
|
1821
2050
|
lifter
|
|
1822
2051
|
);
|
|
1823
2052
|
}
|
|
2053
|
+
function melDelta(features, nFeatures, nFrames, width = 9) {
|
|
2054
|
+
const request = features instanceof Float32Array ? { features, nFeatures: nFeatures ?? 0, nFrames: nFrames ?? 0, width } : features;
|
|
2055
|
+
assertPositiveInteger("melDelta", request.nFeatures, "nFeatures");
|
|
2056
|
+
assertPositiveInteger("melDelta", request.nFrames, "nFrames");
|
|
2057
|
+
assertPositiveInteger("melDelta", request.width ?? 9, "width");
|
|
2058
|
+
if ((request.width ?? 9) < 3 || (request.width ?? 9) % 2 === 0) {
|
|
2059
|
+
throw new RangeError("melDelta: width must be an odd integer of at least 3");
|
|
2060
|
+
}
|
|
2061
|
+
if (request.features.length !== request.nFeatures * request.nFrames) {
|
|
2062
|
+
throw new RangeError("melDelta: feature matrix length must equal nFeatures * nFrames");
|
|
2063
|
+
}
|
|
2064
|
+
return requireModule13().melDelta(
|
|
2065
|
+
request.features,
|
|
2066
|
+
request.nFeatures,
|
|
2067
|
+
request.nFrames,
|
|
2068
|
+
request.width ?? 9
|
|
2069
|
+
);
|
|
2070
|
+
}
|
|
2071
|
+
function reassignedSpectrogram(samples, sampleRate = 22050, nFft = 2048, hopLength = 512, refPower = 1e-6, fillNan = false) {
|
|
2072
|
+
if (!(samples instanceof Float32Array)) {
|
|
2073
|
+
const request = samples;
|
|
2074
|
+
return reassignedSpectrogram(
|
|
2075
|
+
request.samples,
|
|
2076
|
+
request.sampleRate,
|
|
2077
|
+
request.nFft,
|
|
2078
|
+
request.hopLength,
|
|
2079
|
+
request.refPower,
|
|
2080
|
+
request.fillNan
|
|
2081
|
+
);
|
|
2082
|
+
}
|
|
2083
|
+
assertSamples("reassignedSpectrogram", samples, true);
|
|
2084
|
+
assertSampleRate("reassignedSpectrogram", sampleRate);
|
|
2085
|
+
assertPositiveInteger("reassignedSpectrogram", nFft, "nFft");
|
|
2086
|
+
assertPositiveInteger("reassignedSpectrogram", hopLength, "hopLength");
|
|
2087
|
+
assertFiniteScalar("reassignedSpectrogram", refPower, "refPower");
|
|
2088
|
+
if (refPower < 0) {
|
|
2089
|
+
throw new RangeError("reassignedSpectrogram: refPower must be non-negative");
|
|
2090
|
+
}
|
|
2091
|
+
return requireModule13().reassignedSpectrogram(
|
|
2092
|
+
samples,
|
|
2093
|
+
sampleRate,
|
|
2094
|
+
nFft,
|
|
2095
|
+
hopLength,
|
|
2096
|
+
refPower,
|
|
2097
|
+
fillNan
|
|
2098
|
+
);
|
|
2099
|
+
}
|
|
1824
2100
|
function melToStft(melPower, nMels = 0, nFrames = 0, sampleRate = 22050, nFft = 2048, fmin = 0, fmax = 0, htk = false, options = {}) {
|
|
1825
2101
|
if (!(melPower instanceof Float32Array)) {
|
|
1826
2102
|
const request = melPower;
|
|
@@ -1876,6 +2152,35 @@ function melToAudio(melPower, nMels = 0, nFrames = 0, sampleRate = 22050, nFft =
|
|
|
1876
2152
|
htk
|
|
1877
2153
|
);
|
|
1878
2154
|
}
|
|
2155
|
+
function griffinLim(magnitude, nBins = 0, nFrames = 0, sampleRate = 22050, nFft = 2048, hopLength = 512, nIter = 32, momentum = 0.99, options = {}) {
|
|
2156
|
+
if (!(magnitude instanceof Float32Array)) {
|
|
2157
|
+
const request = magnitude;
|
|
2158
|
+
return griffinLim(
|
|
2159
|
+
request.magnitude,
|
|
2160
|
+
request.nBins,
|
|
2161
|
+
request.nFrames,
|
|
2162
|
+
request.sampleRate,
|
|
2163
|
+
request.nFft,
|
|
2164
|
+
request.hopLength,
|
|
2165
|
+
request.nIter,
|
|
2166
|
+
request.momentum,
|
|
2167
|
+
request
|
|
2168
|
+
);
|
|
2169
|
+
}
|
|
2170
|
+
assertSampleRate("griffinLim", sampleRate);
|
|
2171
|
+
validateMatrix("griffinLim", magnitude, nBins, nFrames, "magnitude", "nBins", options);
|
|
2172
|
+
validatePositiveIntegers2("griffinLim", { nFft, hopLength, nIter });
|
|
2173
|
+
return requireModule13().griffinLim(
|
|
2174
|
+
magnitude,
|
|
2175
|
+
nBins,
|
|
2176
|
+
nFrames,
|
|
2177
|
+
sampleRate,
|
|
2178
|
+
nFft,
|
|
2179
|
+
hopLength,
|
|
2180
|
+
nIter,
|
|
2181
|
+
momentum
|
|
2182
|
+
);
|
|
2183
|
+
}
|
|
1879
2184
|
function mfccToMel(mfccCoefficients, nMfcc = 0, nFrames = 0, nMels = 128, lifter = 0, options = {}) {
|
|
1880
2185
|
if (!(mfccCoefficients instanceof Float32Array)) {
|
|
1881
2186
|
const request = mfccCoefficients;
|
|
@@ -2134,6 +2439,11 @@ function convertAnalysisResult(wasm) {
|
|
|
2134
2439
|
return {
|
|
2135
2440
|
bpm: wasm.bpm,
|
|
2136
2441
|
bpmConfidence: wasm.bpmConfidence,
|
|
2442
|
+
bpmCandidates: wasm.bpmCandidates.map((candidate) => ({
|
|
2443
|
+
value: candidate.value,
|
|
2444
|
+
confidence: candidate.confidence,
|
|
2445
|
+
relation: candidate.relation
|
|
2446
|
+
})),
|
|
2137
2447
|
key: {
|
|
2138
2448
|
root: wasm.key.root,
|
|
2139
2449
|
mode: wasm.key.mode,
|
|
@@ -2142,6 +2452,7 @@ function convertAnalysisResult(wasm) {
|
|
|
2142
2452
|
shortName: wasm.key.shortName
|
|
2143
2453
|
},
|
|
2144
2454
|
timeSignature: wasm.timeSignature,
|
|
2455
|
+
timeSignatureCandidates: wasm.timeSignatureCandidates,
|
|
2145
2456
|
beatTimes,
|
|
2146
2457
|
beats: wasm.beats,
|
|
2147
2458
|
chords: wasm.chords.map((c) => ({
|
|
@@ -2232,7 +2543,7 @@ function detectKeyCandidates(samples, sampleRate = 22050, options = {}) {
|
|
|
2232
2543
|
function detectOnsets(samples, sampleRate = 22050, options = {}) {
|
|
2233
2544
|
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
2234
2545
|
validateAnalysisInput("detectOnsets", request.samples, request.sampleRate ?? 22050, request);
|
|
2235
|
-
return requireModule14().detectOnsets(request.samples, request.sampleRate ?? 22050);
|
|
2546
|
+
return requireModule14().detectOnsets(request.samples, request.sampleRate ?? 22050, request);
|
|
2236
2547
|
}
|
|
2237
2548
|
function detectBeats(samples, sampleRate = 22050, options = {}) {
|
|
2238
2549
|
const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;
|
|
@@ -2364,7 +2675,9 @@ function analyzeWithProgress(samples, sampleRate = 22050, onProgress) {
|
|
|
2364
2675
|
const result = requireModule14().analyzeWithProgress(
|
|
2365
2676
|
request.samples,
|
|
2366
2677
|
request.sampleRate ?? 22050,
|
|
2367
|
-
request.onProgress
|
|
2678
|
+
request.onProgress ?? (() => {
|
|
2679
|
+
}),
|
|
2680
|
+
request.cancel ?? (() => false)
|
|
2368
2681
|
);
|
|
2369
2682
|
return convertAnalysisResult(result);
|
|
2370
2683
|
}
|
|
@@ -2788,7 +3101,12 @@ self.onmessage = async (event) => {
|
|
|
2788
3101
|
`;
|
|
2789
3102
|
function createOpfsClipPageWorker() {
|
|
2790
3103
|
const blob = new Blob([opfsClipPageWorkerSource], { type: "text/javascript" });
|
|
2791
|
-
|
|
3104
|
+
const url = URL.createObjectURL(blob);
|
|
3105
|
+
try {
|
|
3106
|
+
return new Worker(url);
|
|
3107
|
+
} finally {
|
|
3108
|
+
URL.revokeObjectURL(url);
|
|
3109
|
+
}
|
|
2792
3110
|
}
|
|
2793
3111
|
function createOpfsClipPageProvider(engine, options) {
|
|
2794
3112
|
if (options.numChannels <= 0 || options.numSamples <= 0 || options.pageFrames <= 0) {
|
|
@@ -2828,6 +3146,7 @@ function createOpfsClipPageProvider(engine, options) {
|
|
|
2828
3146
|
}
|
|
2829
3147
|
try {
|
|
2830
3148
|
provider.supply(response.pageIndex, channels);
|
|
3149
|
+
options.onPageSupplied?.(response.pageIndex, channels);
|
|
2831
3150
|
} catch {
|
|
2832
3151
|
entry.resolve(false);
|
|
2833
3152
|
return;
|
|
@@ -2875,6 +3194,13 @@ function createOpfsClipPageProvider(engine, options) {
|
|
|
2875
3194
|
supplyRequest(request) {
|
|
2876
3195
|
return supplyPage(Math.floor(request.sample / options.pageFrames));
|
|
2877
3196
|
},
|
|
3197
|
+
clearPage(pageIndex) {
|
|
3198
|
+
if (closed) {
|
|
3199
|
+
return;
|
|
3200
|
+
}
|
|
3201
|
+
provider.clear(pageIndex);
|
|
3202
|
+
options.onPageCleared?.(pageIndex);
|
|
3203
|
+
},
|
|
2878
3204
|
close() {
|
|
2879
3205
|
if (closed) {
|
|
2880
3206
|
return;
|
|
@@ -2886,6 +3212,7 @@ function createOpfsClipPageProvider(engine, options) {
|
|
|
2886
3212
|
}
|
|
2887
3213
|
pending.clear();
|
|
2888
3214
|
provider.destroy();
|
|
3215
|
+
options.onClose?.();
|
|
2889
3216
|
if (ownsWorker) {
|
|
2890
3217
|
worker.terminate();
|
|
2891
3218
|
}
|
|
@@ -2963,7 +3290,10 @@ var ClipPageStreamer = class {
|
|
|
2963
3290
|
if (!state) {
|
|
2964
3291
|
continue;
|
|
2965
3292
|
}
|
|
2966
|
-
const page = Math.floor(request.sample / state.source.pageFrames);
|
|
3293
|
+
const page = request.pageIndex !== void 0 ? request.pageIndex : Math.floor((request.sample ?? Number.NaN) / state.source.pageFrames);
|
|
3294
|
+
if (!Number.isInteger(page) || page < 0 || page > state.lastPage) {
|
|
3295
|
+
continue;
|
|
3296
|
+
}
|
|
2967
3297
|
frontiers.set(request.clipId, page);
|
|
2968
3298
|
}
|
|
2969
3299
|
const fetches = [];
|
|
@@ -2998,7 +3328,7 @@ var ClipPageStreamer = class {
|
|
|
2998
3328
|
const high = Math.min(state.lastPage, frontier + this.readAheadPages);
|
|
2999
3329
|
for (const page of state.resident.keys()) {
|
|
3000
3330
|
if (page < low || page > high) {
|
|
3001
|
-
|
|
3331
|
+
this.clearPage(state, page);
|
|
3002
3332
|
state.resident.delete(page);
|
|
3003
3333
|
}
|
|
3004
3334
|
}
|
|
@@ -3013,7 +3343,7 @@ var ClipPageStreamer = class {
|
|
|
3013
3343
|
state.source.binding.supplyPage(pageIndex).then(
|
|
3014
3344
|
(ok) => {
|
|
3015
3345
|
if (state.generation !== generation) {
|
|
3016
|
-
|
|
3346
|
+
this.clearPage(state, pageIndex);
|
|
3017
3347
|
} else if (!ok && state.resident.get(pageIndex) === generation) {
|
|
3018
3348
|
state.resident.delete(pageIndex);
|
|
3019
3349
|
}
|
|
@@ -3034,12 +3364,28 @@ var ClipPageStreamer = class {
|
|
|
3034
3364
|
state.generation += 1;
|
|
3035
3365
|
state.lastFrontier = null;
|
|
3036
3366
|
for (const page of state.resident.keys()) {
|
|
3037
|
-
|
|
3367
|
+
this.clearPage(state, page);
|
|
3038
3368
|
}
|
|
3039
3369
|
state.resident.clear();
|
|
3040
3370
|
}
|
|
3371
|
+
clearPage(state, pageIndex) {
|
|
3372
|
+
if (state.source.binding.clearPage) {
|
|
3373
|
+
state.source.binding.clearPage(pageIndex);
|
|
3374
|
+
} else {
|
|
3375
|
+
state.source.binding.provider.clear(pageIndex);
|
|
3376
|
+
}
|
|
3377
|
+
}
|
|
3041
3378
|
};
|
|
3042
|
-
async function attachOpfsClipStream(
|
|
3379
|
+
async function attachOpfsClipStream(streamerOrEngine, engineOrOptions, maybeOptions) {
|
|
3380
|
+
if (!(streamerOrEngine instanceof ClipPageStreamer)) {
|
|
3381
|
+
return streamerOrEngine.attachOpfsClipStream(engineOrOptions);
|
|
3382
|
+
}
|
|
3383
|
+
const streamer = streamerOrEngine;
|
|
3384
|
+
const engine = engineOrOptions;
|
|
3385
|
+
const options = maybeOptions;
|
|
3386
|
+
if (!options) {
|
|
3387
|
+
throw new Error("attachOpfsClipStream requires options.");
|
|
3388
|
+
}
|
|
3043
3389
|
const { clipId, primePages = 1, ...providerOptions } = options;
|
|
3044
3390
|
const binding = createOpfsClipPageProvider(engine, providerOptions);
|
|
3045
3391
|
const lastPage = Math.ceil(providerOptions.numSamples / providerOptions.pageFrames) - 1;
|
|
@@ -3095,7 +3441,11 @@ async function bindMicrophoneInput(context, engine, options = {}) {
|
|
|
3095
3441
|
function assertOversampleFactor(fnName, factor) {
|
|
3096
3442
|
const normalized = factor === 0 ? 4 : factor;
|
|
3097
3443
|
if (!Number.isInteger(normalized) || normalized < 1 || normalized > 16 || (normalized & normalized - 1) !== 0) {
|
|
3098
|
-
throw new
|
|
3444
|
+
throw new SonareError(
|
|
3445
|
+
4 /* InvalidParameter */,
|
|
3446
|
+
"InvalidParameter",
|
|
3447
|
+
`${fnName}: oversampleFactor must be 0 or a power of two from 1 to 16`
|
|
3448
|
+
);
|
|
3099
3449
|
}
|
|
3100
3450
|
}
|
|
3101
3451
|
function requireModule15() {
|
|
@@ -3275,6 +3625,61 @@ function waveformPeakPyramid(samples, channels, options = {}) {
|
|
|
3275
3625
|
return requireModule15().waveformPeakPyramid(request.samples, request.channels, levels);
|
|
3276
3626
|
}
|
|
3277
3627
|
|
|
3628
|
+
// src/codes.ts
|
|
3629
|
+
function resolveEnumOrdinal(value, values, enumName) {
|
|
3630
|
+
if (typeof value === "number") {
|
|
3631
|
+
if (!Number.isSafeInteger(value) || !Object.values(values).includes(value)) {
|
|
3632
|
+
throw new RangeError(`Invalid ${enumName}: ${String(value)}`);
|
|
3633
|
+
}
|
|
3634
|
+
return value;
|
|
3635
|
+
}
|
|
3636
|
+
if (typeof value === "string") {
|
|
3637
|
+
const ordinal = values[value];
|
|
3638
|
+
if (ordinal !== void 0) {
|
|
3639
|
+
return ordinal;
|
|
3640
|
+
}
|
|
3641
|
+
}
|
|
3642
|
+
throw new RangeError(`Invalid ${enumName}: ${String(value)}`);
|
|
3643
|
+
}
|
|
3644
|
+
var AUTOMATION_CURVE_VALUES = {
|
|
3645
|
+
linear: 0,
|
|
3646
|
+
exponential: 1,
|
|
3647
|
+
hold: 2,
|
|
3648
|
+
"s-curve": 3
|
|
3649
|
+
};
|
|
3650
|
+
var PAN_LAW_VALUES = {
|
|
3651
|
+
const3dB: 0,
|
|
3652
|
+
"const4.5dB": 1,
|
|
3653
|
+
const6dB: 2,
|
|
3654
|
+
linear0dB: 3
|
|
3655
|
+
};
|
|
3656
|
+
var PAN_MODE_VALUES = {
|
|
3657
|
+
balance: 0,
|
|
3658
|
+
pan: 0,
|
|
3659
|
+
stereopan: 1,
|
|
3660
|
+
"stereo-pan": 1,
|
|
3661
|
+
dualpan: 2,
|
|
3662
|
+
"dual-pan": 2
|
|
3663
|
+
};
|
|
3664
|
+
var METER_TAP_VALUES = { preFader: 0, postFader: 1 };
|
|
3665
|
+
var SEND_TIMING_VALUES = { postFader: 0, preFader: 1 };
|
|
3666
|
+
function automationCurveCode(curve) {
|
|
3667
|
+
return resolveEnumOrdinal(curve, AUTOMATION_CURVE_VALUES, "automation curve");
|
|
3668
|
+
}
|
|
3669
|
+
function panLawCode(panLaw) {
|
|
3670
|
+
return resolveEnumOrdinal(panLaw, PAN_LAW_VALUES, "pan law");
|
|
3671
|
+
}
|
|
3672
|
+
function panModeCode(panMode) {
|
|
3673
|
+
const normalized = typeof panMode === "string" ? panMode.replace(/_/g, "-").toLowerCase() : panMode;
|
|
3674
|
+
return resolveEnumOrdinal(normalized, PAN_MODE_VALUES, "pan mode");
|
|
3675
|
+
}
|
|
3676
|
+
function meterTapCode(tap) {
|
|
3677
|
+
return resolveEnumOrdinal(tap, METER_TAP_VALUES, "meter tap");
|
|
3678
|
+
}
|
|
3679
|
+
function sendTimingCode(timing) {
|
|
3680
|
+
return resolveEnumOrdinal(timing, SEND_TIMING_VALUES, "send timing");
|
|
3681
|
+
}
|
|
3682
|
+
|
|
3278
3683
|
// src/project_internal.ts
|
|
3279
3684
|
function projectModule() {
|
|
3280
3685
|
const candidate = getSonareModule();
|
|
@@ -3341,37 +3746,17 @@ function assertProjectMidiEvents(fnName, events) {
|
|
|
3341
3746
|
});
|
|
3342
3747
|
}
|
|
3343
3748
|
function projectTrackKindValue(kind) {
|
|
3344
|
-
|
|
3345
|
-
return 0;
|
|
3346
|
-
}
|
|
3347
|
-
if (kind === "midi") {
|
|
3348
|
-
return 1;
|
|
3349
|
-
}
|
|
3350
|
-
if (kind === "aux") {
|
|
3351
|
-
return 2;
|
|
3352
|
-
}
|
|
3353
|
-
return kind;
|
|
3749
|
+
return resolveEnumOrdinal(kind ?? "audio", { audio: 0, midi: 1, aux: 2 }, "project track kind");
|
|
3354
3750
|
}
|
|
3355
3751
|
function projectWarpModeValue(mode) {
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
}
|
|
3362
|
-
if (mode === "tempo-sync") {
|
|
3363
|
-
return 2;
|
|
3364
|
-
}
|
|
3365
|
-
return mode;
|
|
3752
|
+
return resolveEnumOrdinal(
|
|
3753
|
+
mode ?? "off",
|
|
3754
|
+
{ off: 0, repitch: 1, "tempo-sync": 2 },
|
|
3755
|
+
"project warp mode"
|
|
3756
|
+
);
|
|
3366
3757
|
}
|
|
3367
3758
|
function projectLoopModeValue(mode) {
|
|
3368
|
-
|
|
3369
|
-
return 0;
|
|
3370
|
-
}
|
|
3371
|
-
if (mode === "loop") {
|
|
3372
|
-
return 1;
|
|
3373
|
-
}
|
|
3374
|
-
return mode;
|
|
3759
|
+
return resolveEnumOrdinal(mode ?? "off", { off: 0, loop: 1 }, "project loop mode");
|
|
3375
3760
|
}
|
|
3376
3761
|
|
|
3377
3762
|
// src/project_class.ts
|
|
@@ -3544,6 +3929,16 @@ var Project = class _Project {
|
|
|
3544
3929
|
addClip(desc) {
|
|
3545
3930
|
return this.native.addClip(desc);
|
|
3546
3931
|
}
|
|
3932
|
+
/** Import host-separated PCM through the normal audio-track/clip path. */
|
|
3933
|
+
importExternalStems(request) {
|
|
3934
|
+
return this.native.importExternalStems({
|
|
3935
|
+
...request,
|
|
3936
|
+
stems: request.stems.map((stem) => ({
|
|
3937
|
+
...stem,
|
|
3938
|
+
layout: stem.layout === "mono" ? 1 : stem.layout === "stereo" ? 2 : stem.layout
|
|
3939
|
+
}))
|
|
3940
|
+
});
|
|
3941
|
+
}
|
|
3547
3942
|
/** Split captured loop-recording audio into takes and add one clip. */
|
|
3548
3943
|
addLoopRecordingTakes(desc) {
|
|
3549
3944
|
return this.native.addLoopRecordingTakes(desc);
|
|
@@ -3588,7 +3983,11 @@ var Project = class _Project {
|
|
|
3588
3983
|
* Route a track's MIDI to host-instrument `destinationId` (0 = default). The
|
|
3589
3984
|
* compiler stamps every MIDI clip on the track with this id so the engine
|
|
3590
3985
|
* dispatches its events to the instrument registered for that destination.
|
|
3591
|
-
* Routes through an undoable edit command.
|
|
3986
|
+
* Routes through an undoable edit command. Builtin, NativeSynth, and SF2
|
|
3987
|
+
* instruments retain source-track provenance inside a shared destination
|
|
3988
|
+
* voice pool. With only zero-latency instruments bound, live lanes and
|
|
3989
|
+
* channel-strip bounces remain aligned. Configure one live lane per source
|
|
3990
|
+
* track that needs strip processing.
|
|
3592
3991
|
*/
|
|
3593
3992
|
setTrackMidiDestination(trackId, destinationId) {
|
|
3594
3993
|
this.native.setTrackMidiDestination(trackId, destinationId);
|
|
@@ -3825,6 +4224,14 @@ var Project = class _Project {
|
|
|
3825
4224
|
setClipFade(clipId, fadeIn = {}, fadeOut = {}) {
|
|
3826
4225
|
this.native.setClipFade(clipId, fadeIn, fadeOut);
|
|
3827
4226
|
}
|
|
4227
|
+
/** Audio source ids that need decoded PCM after deserialization. */
|
|
4228
|
+
unresolvedAudioSourceIds() {
|
|
4229
|
+
return this.native.unresolvedAudioSourceIds();
|
|
4230
|
+
}
|
|
4231
|
+
/** Register decoded interleaved PCM for an existing audio source (undoable). */
|
|
4232
|
+
setSourceAudio(sourceId, audio, channels, sampleRate) {
|
|
4233
|
+
this.native.setSourceAudio(sourceId, audio, channels, sampleRate);
|
|
4234
|
+
}
|
|
3828
4235
|
/** Replace a clip's take list and active take id (undoable). */
|
|
3829
4236
|
setClipTakes(clipId, takes, activeTakeId = 0) {
|
|
3830
4237
|
this.native.setClipTakes(clipId, takes, activeTakeId);
|
|
@@ -3866,23 +4273,23 @@ var Project = class _Project {
|
|
|
3866
4273
|
setTrackRoute(trackId, channelStripRef, outputTarget) {
|
|
3867
4274
|
this.native.setTrackRoute(trackId, channelStripRef ?? "", outputTarget ?? "");
|
|
3868
4275
|
}
|
|
3869
|
-
/** Append an automation lane
|
|
4276
|
+
/** Append an automation lane; returns its stable target parameter id (undoable). */
|
|
3870
4277
|
addAutomationLane(trackId, desc) {
|
|
3871
4278
|
return this.native.addAutomationLane(trackId, {
|
|
3872
4279
|
targetParamId: desc.targetParamId,
|
|
3873
4280
|
points: desc.points
|
|
3874
4281
|
});
|
|
3875
4282
|
}
|
|
3876
|
-
/** Replace
|
|
3877
|
-
editAutomationLane(trackId,
|
|
3878
|
-
this.native.editAutomationLane(trackId,
|
|
4283
|
+
/** Replace the lane identified by its stable target parameter id (undoable). */
|
|
4284
|
+
editAutomationLane(trackId, targetParamId, desc) {
|
|
4285
|
+
this.native.editAutomationLane(trackId, targetParamId, {
|
|
3879
4286
|
targetParamId: desc.targetParamId,
|
|
3880
4287
|
points: desc.points
|
|
3881
4288
|
});
|
|
3882
4289
|
}
|
|
3883
|
-
/** Remove
|
|
3884
|
-
removeAutomationLane(trackId,
|
|
3885
|
-
this.native.removeAutomationLane(trackId,
|
|
4290
|
+
/** Remove the lane identified by its stable target parameter id (undoable). */
|
|
4291
|
+
removeAutomationLane(trackId, targetParamId) {
|
|
4292
|
+
this.native.removeAutomationLane(trackId, targetParamId);
|
|
3886
4293
|
}
|
|
3887
4294
|
/** Replace the project's key annotation stream (undoable). */
|
|
3888
4295
|
annotateKeys(keys) {
|
|
@@ -3946,6 +4353,18 @@ var Project = class _Project {
|
|
|
3946
4353
|
markerByIndex(index) {
|
|
3947
4354
|
return this.native.markerByIndex(index);
|
|
3948
4355
|
}
|
|
4356
|
+
/** Read a stored project track by 0-based index. */
|
|
4357
|
+
trackByIndex(index) {
|
|
4358
|
+
return this.native.trackByIndex(index);
|
|
4359
|
+
}
|
|
4360
|
+
/** Read a stored project clip by 0-based index. */
|
|
4361
|
+
clipByIndex(index) {
|
|
4362
|
+
return this.native.clipByIndex(index);
|
|
4363
|
+
}
|
|
4364
|
+
/** Read a stored project source by 0-based index. */
|
|
4365
|
+
sourceByIndex(index) {
|
|
4366
|
+
return this.native.sourceByIndex(index);
|
|
4367
|
+
}
|
|
3949
4368
|
/** Number of markers in the project. */
|
|
3950
4369
|
markerCount() {
|
|
3951
4370
|
return this.native.markerCount();
|
|
@@ -4019,6 +4438,7 @@ var MarkerKind = {
|
|
|
4019
4438
|
cuePoint: 3,
|
|
4020
4439
|
keySignature: 4
|
|
4021
4440
|
};
|
|
4441
|
+
var BUILTIN_SYNTH_WAVEFORMS = ["sine", "saw", "sawtooth", "square", "triangle"];
|
|
4022
4442
|
var SYNTH_ENGINE_MODES = [
|
|
4023
4443
|
"default",
|
|
4024
4444
|
"subtractive",
|
|
@@ -4081,82 +4501,6 @@ var SYNTH_MOD_DESTINATIONS = [
|
|
|
4081
4501
|
"pan-units"
|
|
4082
4502
|
];
|
|
4083
4503
|
|
|
4084
|
-
// src/codes.ts
|
|
4085
|
-
function automationCurveCode(curve) {
|
|
4086
|
-
switch (curve) {
|
|
4087
|
-
case "linear":
|
|
4088
|
-
return 0;
|
|
4089
|
-
case "exponential":
|
|
4090
|
-
return 1;
|
|
4091
|
-
case "hold":
|
|
4092
|
-
return 2;
|
|
4093
|
-
case "s-curve":
|
|
4094
|
-
return 3;
|
|
4095
|
-
default:
|
|
4096
|
-
throw new Error(`Invalid automation curve: ${curve}`);
|
|
4097
|
-
}
|
|
4098
|
-
}
|
|
4099
|
-
function panLawCode(panLaw) {
|
|
4100
|
-
if (typeof panLaw === "number") {
|
|
4101
|
-
return panLaw;
|
|
4102
|
-
}
|
|
4103
|
-
switch (panLaw) {
|
|
4104
|
-
case "const3dB":
|
|
4105
|
-
return 0;
|
|
4106
|
-
case "const4.5dB":
|
|
4107
|
-
return 1;
|
|
4108
|
-
case "const6dB":
|
|
4109
|
-
return 2;
|
|
4110
|
-
case "linear0dB":
|
|
4111
|
-
return 3;
|
|
4112
|
-
default:
|
|
4113
|
-
throw new Error(`Invalid pan law: ${panLaw}`);
|
|
4114
|
-
}
|
|
4115
|
-
}
|
|
4116
|
-
function panModeCode(panMode) {
|
|
4117
|
-
if (typeof panMode === "number") {
|
|
4118
|
-
return panMode;
|
|
4119
|
-
}
|
|
4120
|
-
switch (panMode) {
|
|
4121
|
-
case "balance":
|
|
4122
|
-
return 0;
|
|
4123
|
-
case "stereoPan":
|
|
4124
|
-
case "stereo-pan":
|
|
4125
|
-
return 1;
|
|
4126
|
-
case "dualPan":
|
|
4127
|
-
case "dual-pan":
|
|
4128
|
-
return 2;
|
|
4129
|
-
default:
|
|
4130
|
-
throw new Error(`Invalid pan mode: ${panMode}`);
|
|
4131
|
-
}
|
|
4132
|
-
}
|
|
4133
|
-
function meterTapCode(tap) {
|
|
4134
|
-
if (typeof tap === "number") {
|
|
4135
|
-
return tap;
|
|
4136
|
-
}
|
|
4137
|
-
switch (tap) {
|
|
4138
|
-
case "preFader":
|
|
4139
|
-
return 0;
|
|
4140
|
-
case "postFader":
|
|
4141
|
-
return 1;
|
|
4142
|
-
default:
|
|
4143
|
-
throw new Error(`Invalid meter tap: ${tap}`);
|
|
4144
|
-
}
|
|
4145
|
-
}
|
|
4146
|
-
function sendTimingCode(timing) {
|
|
4147
|
-
if (typeof timing === "number") {
|
|
4148
|
-
return timing;
|
|
4149
|
-
}
|
|
4150
|
-
switch (timing) {
|
|
4151
|
-
case "postFader":
|
|
4152
|
-
return 0;
|
|
4153
|
-
case "preFader":
|
|
4154
|
-
return 1;
|
|
4155
|
-
default:
|
|
4156
|
-
throw new Error(`Invalid send timing: ${timing}`);
|
|
4157
|
-
}
|
|
4158
|
-
}
|
|
4159
|
-
|
|
4160
4504
|
// src/realtime_engine.ts
|
|
4161
4505
|
var EXPECTED_ENGINE_ABI_VERSION = 3;
|
|
4162
4506
|
function engineCapabilities() {
|
|
@@ -4175,23 +4519,30 @@ function engineCapabilities() {
|
|
|
4175
4519
|
};
|
|
4176
4520
|
}
|
|
4177
4521
|
var RealtimeEngine = class {
|
|
4178
|
-
constructor(sampleRate = 48e3, maxBlockSize = 128, commandCapacity = 1024, telemetryCapacity = 1024) {
|
|
4522
|
+
constructor(sampleRate = 48e3, maxBlockSize = 128, commandCapacity = 1024, telemetryCapacity = 1024, maxChannels = 64) {
|
|
4179
4523
|
const module2 = getSonareModule();
|
|
4180
|
-
const
|
|
4181
|
-
if (!
|
|
4524
|
+
const capabilities2 = engineCapabilities();
|
|
4525
|
+
if (!capabilities2.abiCompatible) {
|
|
4182
4526
|
throw new Error(
|
|
4183
|
-
`Engine ABI mismatch: wasm=${
|
|
4527
|
+
`Engine ABI mismatch: wasm=${capabilities2.engineAbiVersion}, expected=${capabilities2.expectedEngineAbiVersion}`
|
|
4184
4528
|
);
|
|
4185
4529
|
}
|
|
4186
4530
|
this.native = new module2.RealtimeEngine(
|
|
4187
4531
|
sampleRate,
|
|
4188
4532
|
maxBlockSize,
|
|
4189
4533
|
commandCapacity,
|
|
4190
|
-
telemetryCapacity
|
|
4534
|
+
telemetryCapacity,
|
|
4535
|
+
maxChannels
|
|
4191
4536
|
);
|
|
4192
4537
|
}
|
|
4193
|
-
prepare(sampleRate, maxBlockSize, commandCapacity = 1024, telemetryCapacity = 1024) {
|
|
4194
|
-
this.native.
|
|
4538
|
+
prepare(sampleRate, maxBlockSize, commandCapacity = 1024, telemetryCapacity = 1024, maxChannels = 64) {
|
|
4539
|
+
this.native.prepareWithChannels(
|
|
4540
|
+
sampleRate,
|
|
4541
|
+
maxBlockSize,
|
|
4542
|
+
commandCapacity,
|
|
4543
|
+
telemetryCapacity,
|
|
4544
|
+
maxChannels
|
|
4545
|
+
);
|
|
4195
4546
|
}
|
|
4196
4547
|
/** Queue a sample-accurate parameter change (engine kSetParam). */
|
|
4197
4548
|
setParameter(paramId, value, renderFrame = -1) {
|
|
@@ -4317,6 +4668,9 @@ var RealtimeEngine = class {
|
|
|
4317
4668
|
externalMidiDroppedCount() {
|
|
4318
4669
|
return this.native.externalMidiDroppedCount();
|
|
4319
4670
|
}
|
|
4671
|
+
externalMidiPendingCount() {
|
|
4672
|
+
return this.native.externalMidiPendingCount();
|
|
4673
|
+
}
|
|
4320
4674
|
/**
|
|
4321
4675
|
* Drain queued external-MIDI events, already lowered to MIDI 1.0 byte
|
|
4322
4676
|
* messages ready to write to a Web MIDI output port. Call once per audio
|
|
@@ -4327,6 +4681,25 @@ var RealtimeEngine = class {
|
|
|
4327
4681
|
drainExternalMidi(maxRecords = 1024) {
|
|
4328
4682
|
return this.native.drainExternalMidi(maxRecords);
|
|
4329
4683
|
}
|
|
4684
|
+
/** Scalar, allocation-free external-MIDI drain for AudioWorklet SAB output. */
|
|
4685
|
+
popExternalMidiToScratch() {
|
|
4686
|
+
return this.native.popExternalMidiToScratch();
|
|
4687
|
+
}
|
|
4688
|
+
externalMidiScratchDestinationId() {
|
|
4689
|
+
return this.native.externalMidiScratchDestinationId();
|
|
4690
|
+
}
|
|
4691
|
+
externalMidiScratchRenderFrame() {
|
|
4692
|
+
return this.native.externalMidiScratchRenderFrame();
|
|
4693
|
+
}
|
|
4694
|
+
externalMidiScratchByteWord() {
|
|
4695
|
+
return this.native.externalMidiScratchByteWord();
|
|
4696
|
+
}
|
|
4697
|
+
externalMidiScratchByteCount() {
|
|
4698
|
+
return this.native.externalMidiScratchByteCount();
|
|
4699
|
+
}
|
|
4700
|
+
consumeExternalMidiScratch() {
|
|
4701
|
+
this.native.consumeExternalMidiScratch();
|
|
4702
|
+
}
|
|
4330
4703
|
pushMidiInputNoteOn(group, channel, note, velocity, portTimeSamples = 0) {
|
|
4331
4704
|
this.native.pushMidiInputNoteOn(group, channel, note, velocity, portTimeSamples);
|
|
4332
4705
|
}
|
|
@@ -4351,6 +4724,10 @@ var RealtimeEngine = class {
|
|
|
4351
4724
|
pushMidiCc(destinationId, group, channel, controller, value, renderFrame = -1) {
|
|
4352
4725
|
this.native.pushMidiCc(destinationId, group, channel, controller, value, renderFrame);
|
|
4353
4726
|
}
|
|
4727
|
+
/** Queue one immediate MIDI 1.0 channel-voice UMP word for a destination. */
|
|
4728
|
+
pushMidiUmp(destinationId, word0, renderFrame = -1) {
|
|
4729
|
+
this.native.pushMidiUmp(destinationId, word0, renderFrame);
|
|
4730
|
+
}
|
|
4354
4731
|
/**
|
|
4355
4732
|
* Queue an immediate (live) MIDI SysEx frame to a MIDI destination. `data` is
|
|
4356
4733
|
* the full message including the leading 0xF0 and trailing 0xF7 (1..512
|
|
@@ -4396,6 +4773,10 @@ var RealtimeEngine = class {
|
|
|
4396
4773
|
settleParameters() {
|
|
4397
4774
|
this.native.settleParameters();
|
|
4398
4775
|
}
|
|
4776
|
+
/** Drains queued commands on an offline/control-only engine immediately. */
|
|
4777
|
+
flushControlCommands() {
|
|
4778
|
+
this.native.flushControlCommands();
|
|
4779
|
+
}
|
|
4399
4780
|
seekPpq(ppq, renderFrame = -1) {
|
|
4400
4781
|
this.native.seekPpq(ppq, renderFrame);
|
|
4401
4782
|
}
|
|
@@ -4650,6 +5031,23 @@ var RealtimeEngine = class {
|
|
|
4650
5031
|
popClipPageRequest() {
|
|
4651
5032
|
return this.native.popClipPageRequest();
|
|
4652
5033
|
}
|
|
5034
|
+
/**
|
|
5035
|
+
* Moves one native request into the binding's persistent scalar scratch.
|
|
5036
|
+
* This avoids creating an embind JS object in AudioWorklet process().
|
|
5037
|
+
*/
|
|
5038
|
+
popClipPageRequestToScratch() {
|
|
5039
|
+
return this.native.popClipPageRequestToScratch();
|
|
5040
|
+
}
|
|
5041
|
+
clipPageRequestScratchClipId() {
|
|
5042
|
+
return this.native.clipPageRequestScratchClipId();
|
|
5043
|
+
}
|
|
5044
|
+
clipPageRequestScratchSample() {
|
|
5045
|
+
return this.native.clipPageRequestScratchSample();
|
|
5046
|
+
}
|
|
5047
|
+
/** Cumulative page misses dropped because the native bounded request queue was full. */
|
|
5048
|
+
clipPageRequestOverflowCount() {
|
|
5049
|
+
return this.native.clipPageRequestOverflowCount();
|
|
5050
|
+
}
|
|
4653
5051
|
setCaptureBuffer(numChannels, capacityFrames) {
|
|
4654
5052
|
this.native.setCaptureBuffer(numChannels, capacityFrames);
|
|
4655
5053
|
}
|
|
@@ -4678,6 +5076,10 @@ var RealtimeEngine = class {
|
|
|
4678
5076
|
capturedAudio() {
|
|
4679
5077
|
return this.native.capturedAudio();
|
|
4680
5078
|
}
|
|
5079
|
+
/**
|
|
5080
|
+
* Renders in place, adding engine output to `channels`. Zero each plane first
|
|
5081
|
+
* when it contains no upstream input.
|
|
5082
|
+
*/
|
|
4681
5083
|
process(channels) {
|
|
4682
5084
|
return this.native.process(channels);
|
|
4683
5085
|
}
|
|
@@ -4700,6 +5102,7 @@ var RealtimeEngine = class {
|
|
|
4700
5102
|
}
|
|
4701
5103
|
/**
|
|
4702
5104
|
* Runs the engine in place over the prepared per-channel scratch buffers.
|
|
5105
|
+
* Zero each active span first when it contains no upstream input.
|
|
4703
5106
|
* Allocation-free: safe to call on the AudioWorklet render thread after
|
|
4704
5107
|
* `prepareChannels`.
|
|
4705
5108
|
*/
|
|
@@ -4721,6 +5124,42 @@ var RealtimeEngine = class {
|
|
|
4721
5124
|
drainTelemetry(maxRecords = 1024) {
|
|
4722
5125
|
return this.native.drainTelemetry(maxRecords);
|
|
4723
5126
|
}
|
|
5127
|
+
popTelemetryToScratch() {
|
|
5128
|
+
return this.native.popTelemetryToScratch();
|
|
5129
|
+
}
|
|
5130
|
+
telemetryScratchType() {
|
|
5131
|
+
return this.native.telemetryScratchType();
|
|
5132
|
+
}
|
|
5133
|
+
telemetryScratchError() {
|
|
5134
|
+
return this.native.telemetryScratchError();
|
|
5135
|
+
}
|
|
5136
|
+
telemetryScratchRenderFrame() {
|
|
5137
|
+
return Number(this.native.telemetryScratchRenderFrame());
|
|
5138
|
+
}
|
|
5139
|
+
telemetryScratchTimelineSample() {
|
|
5140
|
+
return Number(this.native.telemetryScratchTimelineSample());
|
|
5141
|
+
}
|
|
5142
|
+
telemetryScratchAudibleTimelineSample() {
|
|
5143
|
+
return Number(this.native.telemetryScratchAudibleTimelineSample());
|
|
5144
|
+
}
|
|
5145
|
+
telemetryScratchGraphLatencySamplesQ8() {
|
|
5146
|
+
return this.native.telemetryScratchGraphLatencySamplesQ8();
|
|
5147
|
+
}
|
|
5148
|
+
telemetryScratchValue() {
|
|
5149
|
+
return this.native.telemetryScratchValue();
|
|
5150
|
+
}
|
|
5151
|
+
popMeterTelemetryToScratch() {
|
|
5152
|
+
return this.native.popMeterTelemetryToScratch();
|
|
5153
|
+
}
|
|
5154
|
+
meterScratchTargetId() {
|
|
5155
|
+
return this.native.meterScratchTargetId();
|
|
5156
|
+
}
|
|
5157
|
+
meterScratchRenderFrame() {
|
|
5158
|
+
return Number(this.native.meterScratchRenderFrame());
|
|
5159
|
+
}
|
|
5160
|
+
meterScratchValue(field) {
|
|
5161
|
+
return this.native.meterScratchValue(field);
|
|
5162
|
+
}
|
|
4724
5163
|
drainMeterTelemetry(maxRecords = 1024) {
|
|
4725
5164
|
return this.native.drainMeterTelemetry(maxRecords);
|
|
4726
5165
|
}
|
|
@@ -4748,6 +5187,30 @@ var RealtimeEngine = class {
|
|
|
4748
5187
|
drainScopeTelemetry(maxRecords = 1024) {
|
|
4749
5188
|
return this.native.drainScopeTelemetry(maxRecords);
|
|
4750
5189
|
}
|
|
5190
|
+
popScopeTelemetryToScratch() {
|
|
5191
|
+
return this.native.popScopeTelemetryToScratch();
|
|
5192
|
+
}
|
|
5193
|
+
scopeScratchTargetId() {
|
|
5194
|
+
return this.native.scopeScratchTargetId();
|
|
5195
|
+
}
|
|
5196
|
+
scopeScratchRenderFrame() {
|
|
5197
|
+
return Number(this.native.scopeScratchRenderFrame());
|
|
5198
|
+
}
|
|
5199
|
+
scopeScratchBandCount() {
|
|
5200
|
+
return this.native.scopeScratchBandCount();
|
|
5201
|
+
}
|
|
5202
|
+
scopeScratchBand(index) {
|
|
5203
|
+
return this.native.scopeScratchBand(index);
|
|
5204
|
+
}
|
|
5205
|
+
scopeScratchPointCount() {
|
|
5206
|
+
return this.native.scopeScratchPointCount();
|
|
5207
|
+
}
|
|
5208
|
+
scopeScratchPointLeft(index) {
|
|
5209
|
+
return this.native.scopeScratchPointLeft(index);
|
|
5210
|
+
}
|
|
5211
|
+
scopeScratchPointRight(index) {
|
|
5212
|
+
return this.native.scopeScratchPointRight(index);
|
|
5213
|
+
}
|
|
4751
5214
|
destroy() {
|
|
4752
5215
|
this.native.delete();
|
|
4753
5216
|
}
|
|
@@ -5449,65 +5912,18 @@ var Mixer = class _Mixer {
|
|
|
5449
5912
|
};
|
|
5450
5913
|
|
|
5451
5914
|
// src/realtime_voice_changer.ts
|
|
5452
|
-
function isFlatVoiceChangerPod(config) {
|
|
5453
|
-
return typeof config === "object" && config !== null && "retuneSemitones" in config;
|
|
5454
|
-
}
|
|
5455
|
-
function flatVoiceChangerPodToNested(pod) {
|
|
5456
|
-
return {
|
|
5457
|
-
inputGainDb: pod.inputGainDb,
|
|
5458
|
-
outputGainDb: pod.outputGainDb,
|
|
5459
|
-
wetMix: pod.wetMix,
|
|
5460
|
-
retune: { semitones: pod.retuneSemitones, mix: pod.retuneMix, grainSize: pod.retuneGrainSize },
|
|
5461
|
-
formant: {
|
|
5462
|
-
factor: pod.formantFactor,
|
|
5463
|
-
amount: pod.formantAmount,
|
|
5464
|
-
body: pod.formantBody,
|
|
5465
|
-
brightness: pod.formantBrightness,
|
|
5466
|
-
nasal: pod.formantNasal
|
|
5467
|
-
},
|
|
5468
|
-
eq: {
|
|
5469
|
-
highpassHz: pod.eqHighpassHz,
|
|
5470
|
-
bodyDb: pod.eqBodyDb,
|
|
5471
|
-
presenceDb: pod.eqPresenceDb,
|
|
5472
|
-
airDb: pod.eqAirDb
|
|
5473
|
-
},
|
|
5474
|
-
gate: {
|
|
5475
|
-
thresholdDb: pod.gateThresholdDb,
|
|
5476
|
-
attackMs: pod.gateAttackMs,
|
|
5477
|
-
releaseMs: pod.gateReleaseMs,
|
|
5478
|
-
rangeDb: pod.gateRangeDb
|
|
5479
|
-
},
|
|
5480
|
-
compressor: {
|
|
5481
|
-
thresholdDb: pod.compressorThresholdDb,
|
|
5482
|
-
ratio: pod.compressorRatio,
|
|
5483
|
-
attackMs: pod.compressorAttackMs,
|
|
5484
|
-
releaseMs: pod.compressorReleaseMs,
|
|
5485
|
-
makeupGainDb: pod.compressorMakeupGainDb
|
|
5486
|
-
},
|
|
5487
|
-
deesser: {
|
|
5488
|
-
frequencyHz: pod.deesserFrequencyHz,
|
|
5489
|
-
thresholdDb: pod.deesserThresholdDb,
|
|
5490
|
-
ratio: pod.deesserRatio,
|
|
5491
|
-
rangeDb: pod.deesserRangeDb
|
|
5492
|
-
},
|
|
5493
|
-
reverb: {
|
|
5494
|
-
mix: pod.reverbMix,
|
|
5495
|
-
timeMs: pod.reverbTimeMs,
|
|
5496
|
-
damping: pod.reverbDamping,
|
|
5497
|
-
seed: pod.reverbSeed
|
|
5498
|
-
},
|
|
5499
|
-
limiter: {
|
|
5500
|
-
ceilingDb: pod.limiterCeilingDb,
|
|
5501
|
-
releaseMs: pod.limiterReleaseMs,
|
|
5502
|
-
enableIspLimiter: pod.limiterEnableIspLimiter,
|
|
5503
|
-
ispCeilingDbtp: pod.limiterIspCeilingDbtp
|
|
5504
|
-
}
|
|
5505
|
-
};
|
|
5506
|
-
}
|
|
5507
5915
|
var RealtimeVoiceChanger = class {
|
|
5508
|
-
|
|
5916
|
+
/**
|
|
5917
|
+
* Creates a voice changer. Supplying `sampleRate` prepares it immediately,
|
|
5918
|
+
* matching the Node and Python constructors; omitting it preserves the
|
|
5919
|
+
* explicit {@link prepare} lifecycle for callers that configure later.
|
|
5920
|
+
*/
|
|
5921
|
+
constructor(config = "neutral-monitor", sampleRate, maxBlockSize = 128, channels = 1) {
|
|
5509
5922
|
const module2 = getSonareModule();
|
|
5510
5923
|
this.changer = module2.createRealtimeVoiceChanger(config);
|
|
5924
|
+
if (sampleRate !== void 0) {
|
|
5925
|
+
this.changer.prepare(sampleRate, maxBlockSize, channels);
|
|
5926
|
+
}
|
|
5511
5927
|
}
|
|
5512
5928
|
prepare(sampleRate, maxBlockSize = 128, channels = 1) {
|
|
5513
5929
|
this.changer.prepare(sampleRate, maxBlockSize, channels);
|
|
@@ -5516,8 +5932,15 @@ var RealtimeVoiceChanger = class {
|
|
|
5516
5932
|
this.changer.reset();
|
|
5517
5933
|
}
|
|
5518
5934
|
setConfig(config) {
|
|
5519
|
-
|
|
5520
|
-
|
|
5935
|
+
this.changer.setConfig(config);
|
|
5936
|
+
}
|
|
5937
|
+
/**
|
|
5938
|
+
* Apply a flat, pre-normalized config without JSON serialization. Intended
|
|
5939
|
+
* for AudioWorklet control messages whose sender prepared the POD on the
|
|
5940
|
+
* main thread.
|
|
5941
|
+
*/
|
|
5942
|
+
setPodConfig(config) {
|
|
5943
|
+
this.changer.setPodConfig(config);
|
|
5521
5944
|
}
|
|
5522
5945
|
configJson() {
|
|
5523
5946
|
return this.changer.configJson();
|
|
@@ -5525,6 +5948,13 @@ var RealtimeVoiceChanger = class {
|
|
|
5525
5948
|
latencySamples() {
|
|
5526
5949
|
return this.changer.latencySamples();
|
|
5527
5950
|
}
|
|
5951
|
+
/**
|
|
5952
|
+
* Monotonically increases whenever {@link prepare} can replace the native
|
|
5953
|
+
* scratch buffers. Cached WASM heap views must be reacquired after it changes.
|
|
5954
|
+
*/
|
|
5955
|
+
bufferGeneration() {
|
|
5956
|
+
return this.changer.bufferGeneration();
|
|
5957
|
+
}
|
|
5528
5958
|
processMono(samples) {
|
|
5529
5959
|
return this.changer.processMono(samples);
|
|
5530
5960
|
}
|
|
@@ -5601,10 +6031,12 @@ var RealtimeVoiceChanger = class {
|
|
|
5601
6031
|
createRealtimeMonoBuffer(numSamples) {
|
|
5602
6032
|
let input = this.getMonoInputBuffer(numSamples);
|
|
5603
6033
|
let output = this.getMonoOutputBuffer(numSamples);
|
|
6034
|
+
let generation = this.bufferGeneration();
|
|
5604
6035
|
const reacquireIfDetached = () => {
|
|
5605
|
-
if (input.byteLength === 0 || output.byteLength === 0) {
|
|
6036
|
+
if (generation !== this.bufferGeneration() || input.byteLength === 0 || output.byteLength === 0) {
|
|
5606
6037
|
input = this.getMonoInputBuffer(numSamples);
|
|
5607
6038
|
output = this.getMonoOutputBuffer(numSamples);
|
|
6039
|
+
generation = this.bufferGeneration();
|
|
5608
6040
|
}
|
|
5609
6041
|
};
|
|
5610
6042
|
return {
|
|
@@ -5626,10 +6058,12 @@ var RealtimeVoiceChanger = class {
|
|
|
5626
6058
|
createRealtimeInterleavedBuffer(numFrames, numChannels) {
|
|
5627
6059
|
let input = this.getInterleavedInputBuffer(numFrames, numChannels);
|
|
5628
6060
|
let output = this.getInterleavedOutputBuffer(numFrames, numChannels);
|
|
6061
|
+
let generation = this.bufferGeneration();
|
|
5629
6062
|
const reacquireIfDetached = () => {
|
|
5630
|
-
if (input.byteLength === 0 || output.byteLength === 0) {
|
|
6063
|
+
if (generation !== this.bufferGeneration() || input.byteLength === 0 || output.byteLength === 0) {
|
|
5631
6064
|
input = this.getInterleavedInputBuffer(numFrames, numChannels);
|
|
5632
6065
|
output = this.getInterleavedOutputBuffer(numFrames, numChannels);
|
|
6066
|
+
generation = this.bufferGeneration();
|
|
5633
6067
|
}
|
|
5634
6068
|
};
|
|
5635
6069
|
return {
|
|
@@ -5656,15 +6090,17 @@ var RealtimeVoiceChanger = class {
|
|
|
5656
6090
|
*/
|
|
5657
6091
|
createRealtimePlanarBuffer(numFrames, numChannels) {
|
|
5658
6092
|
let channels = [];
|
|
6093
|
+
let generation = this.bufferGeneration();
|
|
5659
6094
|
const acquire = () => {
|
|
5660
6095
|
channels = [];
|
|
5661
6096
|
for (let ch = 0; ch < numChannels; ch++) {
|
|
5662
6097
|
channels.push(this.getPlanarChannelBuffer(ch, numFrames));
|
|
5663
6098
|
}
|
|
6099
|
+
generation = this.bufferGeneration();
|
|
5664
6100
|
};
|
|
5665
6101
|
acquire();
|
|
5666
6102
|
const reacquireIfDetached = () => {
|
|
5667
|
-
if ((channels[0]?.byteLength ?? 0) === 0) {
|
|
6103
|
+
if (generation !== this.bufferGeneration() || (channels[0]?.byteLength ?? 0) === 0) {
|
|
5668
6104
|
acquire();
|
|
5669
6105
|
}
|
|
5670
6106
|
};
|
|
@@ -5740,6 +6176,19 @@ var StreamingMasteringChain = class {
|
|
|
5740
6176
|
}
|
|
5741
6177
|
return this.chain.processStereo(left, right);
|
|
5742
6178
|
}
|
|
6179
|
+
/**
|
|
6180
|
+
* Emit delayed audio and finite processor tails after the final mono block.
|
|
6181
|
+
* Call until this returns an empty array. The initial `latencySamples()`
|
|
6182
|
+
* samples of the concatenated stream are delayed and should be discarded for
|
|
6183
|
+
* time-aligned output.
|
|
6184
|
+
*/
|
|
6185
|
+
flushMono() {
|
|
6186
|
+
return this.chain.flushMono();
|
|
6187
|
+
}
|
|
6188
|
+
/** Stereo counterpart of {@link flushMono}. */
|
|
6189
|
+
flushStereo() {
|
|
6190
|
+
return this.chain.flushStereo();
|
|
6191
|
+
}
|
|
5743
6192
|
/** Reset all processor state without rebuilding. */
|
|
5744
6193
|
reset() {
|
|
5745
6194
|
this.chain.reset();
|
|
@@ -6131,6 +6580,214 @@ function iterInputs(access) {
|
|
|
6131
6580
|
return access.inputs instanceof Map ? access.inputs.entries() : access.inputs;
|
|
6132
6581
|
}
|
|
6133
6582
|
|
|
6583
|
+
// src/worker_client.ts
|
|
6584
|
+
var OfflineWorkerTask = class {
|
|
6585
|
+
constructor(result, cancelRequest) {
|
|
6586
|
+
this.result = result;
|
|
6587
|
+
this.cancelRequest = cancelRequest;
|
|
6588
|
+
}
|
|
6589
|
+
cancel() {
|
|
6590
|
+
this.cancelRequest();
|
|
6591
|
+
}
|
|
6592
|
+
// biome-ignore lint/suspicious/noThenProperty: this intentionally implements PromiseLike so callers can await a task and cancel it.
|
|
6593
|
+
then(onfulfilled, onrejected) {
|
|
6594
|
+
return this.result.then(onfulfilled, onrejected);
|
|
6595
|
+
}
|
|
6596
|
+
catch(onrejected) {
|
|
6597
|
+
return this.result.catch(onrejected);
|
|
6598
|
+
}
|
|
6599
|
+
finally(onfinally) {
|
|
6600
|
+
return this.result.finally(onfinally);
|
|
6601
|
+
}
|
|
6602
|
+
};
|
|
6603
|
+
function cloneForWorker(value, copy, transfers, transferred = /* @__PURE__ */ new Set()) {
|
|
6604
|
+
if (value instanceof Float32Array) {
|
|
6605
|
+
const samples = copy ? value.slice() : value;
|
|
6606
|
+
const buffer = samples.buffer;
|
|
6607
|
+
if (!(buffer instanceof ArrayBuffer)) {
|
|
6608
|
+
throw new TypeError(
|
|
6609
|
+
"OfflineWorkerClient only transfers Float32Array values backed by ArrayBuffer"
|
|
6610
|
+
);
|
|
6611
|
+
}
|
|
6612
|
+
if (!transferred.has(buffer)) {
|
|
6613
|
+
transferred.add(buffer);
|
|
6614
|
+
transfers.push(buffer);
|
|
6615
|
+
}
|
|
6616
|
+
return samples;
|
|
6617
|
+
}
|
|
6618
|
+
if (Array.isArray(value)) {
|
|
6619
|
+
return value.map((item) => cloneForWorker(item, copy, transfers, transferred));
|
|
6620
|
+
}
|
|
6621
|
+
if (value !== null && typeof value === "object") {
|
|
6622
|
+
return Object.fromEntries(
|
|
6623
|
+
Object.entries(value).map(([key, item]) => [
|
|
6624
|
+
key,
|
|
6625
|
+
cloneForWorker(item, copy, transfers, transferred)
|
|
6626
|
+
])
|
|
6627
|
+
);
|
|
6628
|
+
}
|
|
6629
|
+
return value;
|
|
6630
|
+
}
|
|
6631
|
+
function cancellationFlag() {
|
|
6632
|
+
if (typeof SharedArrayBuffer === "undefined") {
|
|
6633
|
+
return void 0;
|
|
6634
|
+
}
|
|
6635
|
+
return new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
|
|
6636
|
+
}
|
|
6637
|
+
function workerError(message) {
|
|
6638
|
+
if (message.error.code !== void 0) {
|
|
6639
|
+
return new SonareError(
|
|
6640
|
+
message.error.code,
|
|
6641
|
+
message.error.codeName ?? "Unknown",
|
|
6642
|
+
message.error.message
|
|
6643
|
+
);
|
|
6644
|
+
}
|
|
6645
|
+
const error = new Error(message.error.message);
|
|
6646
|
+
error.name = message.error.name;
|
|
6647
|
+
return error;
|
|
6648
|
+
}
|
|
6649
|
+
var OfflineWorkerClient = class {
|
|
6650
|
+
constructor(options = {}) {
|
|
6651
|
+
this.pending = /* @__PURE__ */ new Map();
|
|
6652
|
+
this.nextId = 1;
|
|
6653
|
+
this.closed = false;
|
|
6654
|
+
this.usesEventTarget = false;
|
|
6655
|
+
this.onMessage = (event) => {
|
|
6656
|
+
const message = event.data;
|
|
6657
|
+
const pending = this.pending.get(message.id);
|
|
6658
|
+
if (!pending) {
|
|
6659
|
+
return;
|
|
6660
|
+
}
|
|
6661
|
+
if (message.type === "sonare:offline-progress") {
|
|
6662
|
+
pending.onProgress?.({ progress: message.progress, stage: message.stage });
|
|
6663
|
+
return;
|
|
6664
|
+
}
|
|
6665
|
+
this.pending.delete(message.id);
|
|
6666
|
+
if (message.type === "sonare:offline-result") {
|
|
6667
|
+
pending.resolve(message.result);
|
|
6668
|
+
return;
|
|
6669
|
+
}
|
|
6670
|
+
pending.reject(workerError(message));
|
|
6671
|
+
};
|
|
6672
|
+
this.onError = (event) => {
|
|
6673
|
+
const error = new Error(event.message || "Offline Worker failed");
|
|
6674
|
+
for (const { reject } of this.pending.values()) {
|
|
6675
|
+
reject(error);
|
|
6676
|
+
}
|
|
6677
|
+
this.pending.clear();
|
|
6678
|
+
};
|
|
6679
|
+
this.onNodeMessage = (data) => {
|
|
6680
|
+
this.onMessage({ data });
|
|
6681
|
+
};
|
|
6682
|
+
this.onNodeError = (error) => {
|
|
6683
|
+
this.onError(
|
|
6684
|
+
error instanceof Error ? { message: error.message } : { message: String(error) }
|
|
6685
|
+
);
|
|
6686
|
+
};
|
|
6687
|
+
this.ownsWorker = options.worker === void 0 || options.terminateWorkerOnDispose === true;
|
|
6688
|
+
if (options.worker) {
|
|
6689
|
+
this.worker = options.worker;
|
|
6690
|
+
} else {
|
|
6691
|
+
if (!options.workerFactory && typeof Worker === "undefined") {
|
|
6692
|
+
throw new Error("OfflineWorkerClient requires a browser Worker implementation");
|
|
6693
|
+
}
|
|
6694
|
+
const url = options.workerUrl === void 0 ? new URL("./worker.js", import.meta.url) : new URL(options.workerUrl, import.meta.url);
|
|
6695
|
+
this.worker = options.workerFactory?.(url) ?? new Worker(url, { type: "module", name: "sonare-offline" });
|
|
6696
|
+
}
|
|
6697
|
+
if (this.worker.addEventListener) {
|
|
6698
|
+
this.usesEventTarget = true;
|
|
6699
|
+
this.worker.addEventListener("message", this.onMessage);
|
|
6700
|
+
this.worker.addEventListener("error", this.onError);
|
|
6701
|
+
} else if (this.worker.on) {
|
|
6702
|
+
this.worker.on("message", this.onNodeMessage);
|
|
6703
|
+
this.worker.on("error", this.onNodeError);
|
|
6704
|
+
} else {
|
|
6705
|
+
throw new TypeError("OfflineWorkerClient requires Worker event listeners");
|
|
6706
|
+
}
|
|
6707
|
+
}
|
|
6708
|
+
/** Dispatch full music analysis to the Worker. */
|
|
6709
|
+
analyze(request, options) {
|
|
6710
|
+
return this.call("analyze", request, options);
|
|
6711
|
+
}
|
|
6712
|
+
/** Dispatch BPM detection to the Worker. */
|
|
6713
|
+
detectBpm(request, options) {
|
|
6714
|
+
return this.call("detectBpm", request, options);
|
|
6715
|
+
}
|
|
6716
|
+
/** Dispatch key detection to the Worker. */
|
|
6717
|
+
detectKey(request, options) {
|
|
6718
|
+
return this.call("detectKey", request, options);
|
|
6719
|
+
}
|
|
6720
|
+
/** Dispatch chord detection to the Worker. */
|
|
6721
|
+
detectChords(request, options) {
|
|
6722
|
+
return this.call("detectChords", request, options);
|
|
6723
|
+
}
|
|
6724
|
+
/** Dispatch mono preset mastering to the Worker. */
|
|
6725
|
+
masterAudio(request, options) {
|
|
6726
|
+
return this.call("masterAudio", request, options);
|
|
6727
|
+
}
|
|
6728
|
+
/** Dispatch stereo preset mastering to the Worker. */
|
|
6729
|
+
masterAudioStereo(request, options) {
|
|
6730
|
+
return this.call("masterAudioStereo", request, options);
|
|
6731
|
+
}
|
|
6732
|
+
/** Stop accepting calls, reject outstanding work, and release the Worker if owned. */
|
|
6733
|
+
dispose() {
|
|
6734
|
+
if (this.closed) {
|
|
6735
|
+
return;
|
|
6736
|
+
}
|
|
6737
|
+
this.closed = true;
|
|
6738
|
+
if (this.usesEventTarget) {
|
|
6739
|
+
this.worker.removeEventListener?.("message", this.onMessage);
|
|
6740
|
+
this.worker.removeEventListener?.("error", this.onError);
|
|
6741
|
+
} else {
|
|
6742
|
+
this.worker.off?.("message", this.onNodeMessage);
|
|
6743
|
+
this.worker.off?.("error", this.onNodeError);
|
|
6744
|
+
}
|
|
6745
|
+
for (const { reject } of this.pending.values()) {
|
|
6746
|
+
reject(new Error("OfflineWorkerClient was disposed"));
|
|
6747
|
+
}
|
|
6748
|
+
this.pending.clear();
|
|
6749
|
+
if (this.ownsWorker) {
|
|
6750
|
+
this.worker.terminate();
|
|
6751
|
+
}
|
|
6752
|
+
}
|
|
6753
|
+
call(operation, request, options = {}) {
|
|
6754
|
+
if (this.closed) {
|
|
6755
|
+
throw new Error("OfflineWorkerClient was disposed");
|
|
6756
|
+
}
|
|
6757
|
+
const id = this.nextId++;
|
|
6758
|
+
const transfers = [];
|
|
6759
|
+
const preparedRequest = cloneForWorker(request, options.copy === true, transfers);
|
|
6760
|
+
const cancelFlag = cancellationFlag();
|
|
6761
|
+
const result = new Promise((resolve, reject) => {
|
|
6762
|
+
this.pending.set(id, {
|
|
6763
|
+
resolve: (value) => resolve(value),
|
|
6764
|
+
reject,
|
|
6765
|
+
onProgress: options.onProgress,
|
|
6766
|
+
cancelFlag
|
|
6767
|
+
});
|
|
6768
|
+
});
|
|
6769
|
+
this.worker.postMessage(
|
|
6770
|
+
{
|
|
6771
|
+
type: "sonare:offline-run",
|
|
6772
|
+
id,
|
|
6773
|
+
operation,
|
|
6774
|
+
request: preparedRequest,
|
|
6775
|
+
...cancelFlag ? { cancelBuffer: cancelFlag.buffer } : {}
|
|
6776
|
+
},
|
|
6777
|
+
transfers
|
|
6778
|
+
);
|
|
6779
|
+
return new OfflineWorkerTask(result, () => {
|
|
6780
|
+
if (!this.pending.has(id)) {
|
|
6781
|
+
return;
|
|
6782
|
+
}
|
|
6783
|
+
if (cancelFlag) {
|
|
6784
|
+
Atomics.store(cancelFlag, 0, 1);
|
|
6785
|
+
}
|
|
6786
|
+
this.worker.postMessage({ type: "sonare:offline-cancel", id });
|
|
6787
|
+
});
|
|
6788
|
+
}
|
|
6789
|
+
};
|
|
6790
|
+
|
|
6134
6791
|
// src/index.ts
|
|
6135
6792
|
var module = null;
|
|
6136
6793
|
var initPromise = null;
|
|
@@ -6162,6 +6819,18 @@ function version() {
|
|
|
6162
6819
|
}
|
|
6163
6820
|
return module.version();
|
|
6164
6821
|
}
|
|
6822
|
+
function capabilities() {
|
|
6823
|
+
if (!module) {
|
|
6824
|
+
throw new Error("Module not initialized. Call init() first.");
|
|
6825
|
+
}
|
|
6826
|
+
return module.capabilities();
|
|
6827
|
+
}
|
|
6828
|
+
function capabilityCatalog() {
|
|
6829
|
+
if (!module) {
|
|
6830
|
+
throw new Error("Module not initialized. Call init() first.");
|
|
6831
|
+
}
|
|
6832
|
+
return JSON.parse(module.capabilityCatalog());
|
|
6833
|
+
}
|
|
6165
6834
|
function abiVersion() {
|
|
6166
6835
|
if (!module) {
|
|
6167
6836
|
throw new Error("Module not initialized. Call init() first.");
|
|
@@ -6190,6 +6859,9 @@ var VOICE_PRESET_ORDINALS = [
|
|
|
6190
6859
|
];
|
|
6191
6860
|
function resolveVoicePresetOrdinal(preset) {
|
|
6192
6861
|
if (typeof preset === "number") {
|
|
6862
|
+
if (!Number.isSafeInteger(preset) || preset < 0 || preset >= VOICE_PRESET_ORDINALS.length) {
|
|
6863
|
+
throw new RangeError(`Unknown voice-character preset ordinal: ${String(preset)}`);
|
|
6864
|
+
}
|
|
6193
6865
|
return preset;
|
|
6194
6866
|
}
|
|
6195
6867
|
const ordinal = VOICE_PRESET_ORDINALS.indexOf(preset);
|
|
@@ -6212,7 +6884,9 @@ function realtimeVoiceChangerPresetConfig(preset) {
|
|
|
6212
6884
|
}
|
|
6213
6885
|
export {
|
|
6214
6886
|
Audio,
|
|
6887
|
+
BUILTIN_SYNTH_WAVEFORMS,
|
|
6215
6888
|
ChordQuality,
|
|
6889
|
+
ClipPageProvider,
|
|
6216
6890
|
ClipPageStreamer,
|
|
6217
6891
|
EXPECTED_ENGINE_ABI_VERSION,
|
|
6218
6892
|
EXPECTED_PROJECT_ABI_VERSION,
|
|
@@ -6221,6 +6895,8 @@ export {
|
|
|
6221
6895
|
MarkerKind,
|
|
6222
6896
|
Mixer,
|
|
6223
6897
|
Mode,
|
|
6898
|
+
OfflineWorkerClient,
|
|
6899
|
+
OfflineWorkerTask,
|
|
6224
6900
|
PitchClass as Pitch,
|
|
6225
6901
|
PitchClass,
|
|
6226
6902
|
Project,
|
|
@@ -6254,10 +6930,14 @@ export {
|
|
|
6254
6930
|
bassChroma,
|
|
6255
6931
|
bindMicrophoneInput,
|
|
6256
6932
|
bindWebMidi,
|
|
6933
|
+
capabilities,
|
|
6934
|
+
capabilityCatalog,
|
|
6935
|
+
chirp,
|
|
6257
6936
|
chordFunctionalAnalysis,
|
|
6258
6937
|
chroma,
|
|
6259
6938
|
chromaCens,
|
|
6260
6939
|
chromaCqt,
|
|
6940
|
+
clicks,
|
|
6261
6941
|
cqt,
|
|
6262
6942
|
cqtToAudio,
|
|
6263
6943
|
createOpfsClipPageProvider,
|
|
@@ -6287,6 +6967,7 @@ export {
|
|
|
6287
6967
|
frameSignal,
|
|
6288
6968
|
framesToSamples,
|
|
6289
6969
|
framesToTime,
|
|
6970
|
+
griffinLim,
|
|
6290
6971
|
harmonic,
|
|
6291
6972
|
hasFfmpegSupport,
|
|
6292
6973
|
hpss,
|
|
@@ -6337,6 +7018,7 @@ export {
|
|
|
6337
7018
|
masteringStereoAnalysisNames,
|
|
6338
7019
|
masteringStereoAnalyze,
|
|
6339
7020
|
masteringStreamingPreview,
|
|
7021
|
+
melDelta,
|
|
6340
7022
|
melSpectrogram,
|
|
6341
7023
|
melToAudio,
|
|
6342
7024
|
melToHz,
|
|
@@ -6369,8 +7051,10 @@ export {
|
|
|
6369
7051
|
nnlsChroma,
|
|
6370
7052
|
normalize,
|
|
6371
7053
|
noteMove,
|
|
7054
|
+
noteSegments,
|
|
6372
7055
|
noteStretch,
|
|
6373
7056
|
noteToHz,
|
|
7057
|
+
onsetBacktrack,
|
|
6374
7058
|
onsetEnvelope,
|
|
6375
7059
|
onsetStrengthMulti,
|
|
6376
7060
|
opfsClipPageWorkerSource,
|
|
@@ -6379,6 +7063,7 @@ export {
|
|
|
6379
7063
|
peakPick,
|
|
6380
7064
|
percussive,
|
|
6381
7065
|
phaseVocoder,
|
|
7066
|
+
piptrack,
|
|
6382
7067
|
pitchCorrectTimevarying,
|
|
6383
7068
|
pitchCorrectToMidi,
|
|
6384
7069
|
pitchCorrectToMidiTimevarying,
|
|
@@ -6395,6 +7080,7 @@ export {
|
|
|
6395
7080
|
realtimeVoiceChangerPresetConfig,
|
|
6396
7081
|
realtimeVoiceChangerPresetJson,
|
|
6397
7082
|
realtimeVoiceChangerPresetNames,
|
|
7083
|
+
reassignedSpectrogram,
|
|
6398
7084
|
remix,
|
|
6399
7085
|
resample,
|
|
6400
7086
|
rmsEnergy,
|
|
@@ -6403,12 +7089,20 @@ export {
|
|
|
6403
7089
|
scaleCorrectionSemitones,
|
|
6404
7090
|
scalePitchClassEnabled,
|
|
6405
7091
|
scaleQuantizeMidi,
|
|
7092
|
+
segmentAgglomerative,
|
|
7093
|
+
segmentCrossSimilarity,
|
|
7094
|
+
segmentLagToRecurrence,
|
|
7095
|
+
segmentPathEnhance,
|
|
7096
|
+
segmentRecurrenceMatrix,
|
|
7097
|
+
segmentRecurrenceToLag,
|
|
7098
|
+
segmentSubsegment,
|
|
6406
7099
|
shortTermLufs,
|
|
6407
7100
|
spectralBandwidth,
|
|
6408
7101
|
spectralCentroid,
|
|
6409
7102
|
spectralContrast,
|
|
6410
7103
|
spectralEdit,
|
|
6411
7104
|
spectralFlatness,
|
|
7105
|
+
spectralFlux,
|
|
6412
7106
|
spectralRolloff,
|
|
6413
7107
|
splitSilence,
|
|
6414
7108
|
stft,
|
|
@@ -6422,6 +7116,7 @@ export {
|
|
|
6422
7116
|
tempogramRatio,
|
|
6423
7117
|
timeStretch,
|
|
6424
7118
|
timeToFrames,
|
|
7119
|
+
tone,
|
|
6425
7120
|
tonnetz,
|
|
6426
7121
|
trim,
|
|
6427
7122
|
trimSilence,
|