@entros/pulse-sdk 1.5.0 → 1.5.2
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 +2 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +32 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -508,6 +508,26 @@ function extractFormantRatios(samples, sampleRate, frameSize, hopSize) {
|
|
|
508
508
|
return { f1f2, f2f3 };
|
|
509
509
|
}
|
|
510
510
|
|
|
511
|
+
// src/yield.ts
|
|
512
|
+
function yieldToMainThread() {
|
|
513
|
+
return new Promise((resolve) => {
|
|
514
|
+
if (typeof MessageChannel !== "undefined") {
|
|
515
|
+
const channel = new MessageChannel();
|
|
516
|
+
channel.port1.onmessage = () => {
|
|
517
|
+
channel.port1.close();
|
|
518
|
+
resolve();
|
|
519
|
+
};
|
|
520
|
+
channel.port2.postMessage(null);
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
if (typeof setTimeout !== "undefined") {
|
|
524
|
+
setTimeout(resolve, 0);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
resolve();
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
|
|
511
531
|
// src/extraction/speaker.ts
|
|
512
532
|
function getFrameSize(sampleRate) {
|
|
513
533
|
const MIN_F0 = 50;
|
|
@@ -541,6 +561,7 @@ async function getMeyda() {
|
|
|
541
561
|
}
|
|
542
562
|
return meydaModule.default ?? meydaModule;
|
|
543
563
|
}
|
|
564
|
+
var F0_YIELD_EVERY_N_FRAMES = 16;
|
|
544
565
|
async function detectF0Contour(samples, sampleRate) {
|
|
545
566
|
const detect = await getPitchDetector(sampleRate);
|
|
546
567
|
const frameSize = getFrameSize(sampleRate);
|
|
@@ -567,6 +588,9 @@ async function detectF0Contour(samples, sampleRate) {
|
|
|
567
588
|
sum += (frame[j] ?? 0) * (frame[j] ?? 0);
|
|
568
589
|
}
|
|
569
590
|
amplitudes.push(Math.sqrt(sum / frame.length));
|
|
591
|
+
if (i > 0 && i < numFrames - 1 && i % F0_YIELD_EVERY_N_FRAMES === 0) {
|
|
592
|
+
await yieldToMainThread();
|
|
593
|
+
}
|
|
570
594
|
}
|
|
571
595
|
return { f0, amplitudes, periods };
|
|
572
596
|
}
|
|
@@ -740,6 +764,7 @@ async function extractSpeakerFeaturesDetailed(audio) {
|
|
|
740
764
|
normalizedSamples = samples;
|
|
741
765
|
}
|
|
742
766
|
const { f0, amplitudes: normalizedAmplitudes, periods } = await detectF0Contour(normalizedSamples, sampleRate);
|
|
767
|
+
await yieldToMainThread();
|
|
743
768
|
const amplitudes = [];
|
|
744
769
|
for (let i = 0; i < numFrames; i++) {
|
|
745
770
|
const start = i * hopSize;
|
|
@@ -764,6 +789,7 @@ async function extractSpeakerFeaturesDetailed(audio) {
|
|
|
764
789
|
const hnrStats = condense(hnrValues);
|
|
765
790
|
const hnrEntropy = entropy(hnrValues);
|
|
766
791
|
const hnrFeatures = [hnrStats.mean, hnrStats.variance, hnrStats.skewness, hnrStats.kurtosis, hnrEntropy];
|
|
792
|
+
await yieldToMainThread();
|
|
767
793
|
const { f1f2, f2f3 } = extractFormantRatios(normalizedSamples, sampleRate, frameSize, hopSize);
|
|
768
794
|
const f1f2Stats = condense(f1f2);
|
|
769
795
|
const f2f3Stats = condense(f2f3);
|
|
@@ -777,6 +803,7 @@ async function extractSpeakerFeaturesDetailed(audio) {
|
|
|
777
803
|
f2f3Stats.skewness,
|
|
778
804
|
f2f3Stats.kurtosis
|
|
779
805
|
];
|
|
806
|
+
await yieldToMainThread();
|
|
780
807
|
const ltasFeatures = await computeLTAS(samples, sampleRate);
|
|
781
808
|
const voicingFeatures = [voicedRatio];
|
|
782
809
|
const ampStats = condense(amplitudes);
|
|
@@ -4211,10 +4238,13 @@ async function extractFeatures(data) {
|
|
|
4211
4238
|
const { features: audioFeatures, f0Contour } = await extractSpeakerFeaturesDetailed(
|
|
4212
4239
|
data.audio
|
|
4213
4240
|
);
|
|
4241
|
+
await yieldToMainThread();
|
|
4214
4242
|
const hasMotion = data.motion.length >= MIN_MOTION_SAMPLES;
|
|
4215
4243
|
const hasTouch = data.touch.length >= MIN_TOUCH_SAMPLES;
|
|
4216
4244
|
const motionFeatures = hasMotion && hasTouch ? extractMouseDynamics(data.touch) : hasMotion ? extractMotionFeatures(data.motion) : extractMouseDynamics(data.touch);
|
|
4245
|
+
await yieldToMainThread();
|
|
4217
4246
|
const touchFeatures = extractTouchFeatures(data.touch);
|
|
4247
|
+
await yieldToMainThread();
|
|
4218
4248
|
const accelMagnitude = hasMotion && f0Contour.length > 0 ? extractAccelerationMagnitude(data.motion, f0Contour.length) : [];
|
|
4219
4249
|
return {
|
|
4220
4250
|
raw: fuseRawFeatures(audioFeatures, motionFeatures, touchFeatures),
|
|
@@ -4228,6 +4258,7 @@ var MIN_MOTION_SAMPLES = 10;
|
|
|
4228
4258
|
var MIN_TOUCH_SAMPLES = 10;
|
|
4229
4259
|
async function extractFingerprintAndValidate(sensorData, config, walletAddress, onProgress) {
|
|
4230
4260
|
onProgress?.("Extracting features...");
|
|
4261
|
+
await yieldToMainThread();
|
|
4231
4262
|
const {
|
|
4232
4263
|
raw: features,
|
|
4233
4264
|
normalized: normalizedFeatures,
|
|
@@ -4242,6 +4273,7 @@ async function extractFingerprintAndValidate(sensorData, config, walletAddress,
|
|
|
4242
4273
|
const tbh = await generateTBH(fingerprint);
|
|
4243
4274
|
let signedReceipt;
|
|
4244
4275
|
onProgress?.("Validating...");
|
|
4276
|
+
await yieldToMainThread();
|
|
4245
4277
|
if (config.relayerUrl && walletAddress) {
|
|
4246
4278
|
try {
|
|
4247
4279
|
const baseUrl = new URL(config.relayerUrl);
|