@omote/core 0.9.5 → 0.9.7
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/dist/index.d.mts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +46 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +46 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -806,18 +806,19 @@ var _A2EProcessor = class _A2EProcessor {
|
|
|
806
806
|
*/
|
|
807
807
|
async flush() {
|
|
808
808
|
if (this.disposed || this.writeOffset === 0) return;
|
|
809
|
+
const actualSamples = this.writeOffset;
|
|
809
810
|
const padded = new Float32Array(this.chunkSize);
|
|
810
|
-
padded.set(this.buffer.subarray(0,
|
|
811
|
+
padded.set(this.buffer.subarray(0, actualSamples), 0);
|
|
811
812
|
const chunkTimestamp = this.bufferStartTime > 0 ? this.bufferStartTime : void 0;
|
|
812
813
|
logger4.info("flush: routing through drain pipeline", {
|
|
813
|
-
actualSamples
|
|
814
|
+
actualSamples,
|
|
814
815
|
chunkTimestamp: chunkTimestamp?.toFixed(3),
|
|
815
816
|
pendingChunks: this.pendingChunks.length,
|
|
816
817
|
inferenceRunning: this.inferenceRunning
|
|
817
818
|
});
|
|
818
819
|
this.writeOffset = 0;
|
|
819
820
|
this.bufferStartTime = 0;
|
|
820
|
-
this.pendingChunks.push({ chunk: padded, timestamp: chunkTimestamp });
|
|
821
|
+
this.pendingChunks.push({ chunk: padded, timestamp: chunkTimestamp, actualSamples });
|
|
821
822
|
this.drainPendingChunks();
|
|
822
823
|
}
|
|
823
824
|
/**
|
|
@@ -975,14 +976,15 @@ var _A2EProcessor = class _A2EProcessor {
|
|
|
975
976
|
logger4.info("drainPendingChunks starting", { pendingChunks: this.pendingChunks.length });
|
|
976
977
|
const processNext = async () => {
|
|
977
978
|
while (this.pendingChunks.length > 0 && !this.disposed) {
|
|
978
|
-
const { chunk, timestamp } = this.pendingChunks.shift();
|
|
979
|
+
const { chunk, timestamp, actualSamples } = this.pendingChunks.shift();
|
|
979
980
|
try {
|
|
980
981
|
const t0 = getClock().now();
|
|
981
982
|
const result = await this.backend.infer(chunk, this.identityIndex);
|
|
982
983
|
const inferMs = Math.round(getClock().now() - t0);
|
|
983
|
-
const
|
|
984
|
+
const effectiveSamples = actualSamples ?? chunk.length;
|
|
985
|
+
const actualDuration = effectiveSamples / this.sampleRate;
|
|
984
986
|
const actualFrameCount = Math.ceil(actualDuration * FRAME_RATE);
|
|
985
|
-
const framesToQueue = Math.min(actualFrameCount, result.blendshapes.length);
|
|
987
|
+
const framesToQueue = Math.min(Math.max(1, actualFrameCount), result.blendshapes.length);
|
|
986
988
|
logger4.info("Inference complete", {
|
|
987
989
|
inferMs,
|
|
988
990
|
modelFrames: result.blendshapes.length,
|
|
@@ -1235,7 +1237,7 @@ function applyProfile(raw, profile, out) {
|
|
|
1235
1237
|
|
|
1236
1238
|
// src/audio/PlaybackPipeline.ts
|
|
1237
1239
|
var logger5 = createLogger("PlaybackPipeline");
|
|
1238
|
-
var
|
|
1240
|
+
var _PlaybackPipeline = class _PlaybackPipeline extends EventEmitter {
|
|
1239
1241
|
constructor(config) {
|
|
1240
1242
|
super();
|
|
1241
1243
|
this.config = config;
|
|
@@ -1254,6 +1256,10 @@ var PlaybackPipeline = class extends EventEmitter {
|
|
|
1254
1256
|
this.neutralTransitionFrame = null;
|
|
1255
1257
|
this.neutralTransitionStart = 0;
|
|
1256
1258
|
this.neutralAnimationId = null;
|
|
1259
|
+
this.rampInActive = false;
|
|
1260
|
+
this.rampInLastTime = 0;
|
|
1261
|
+
this.rampInStartTime = 0;
|
|
1262
|
+
this._rampInBuffer = new Float32Array(52);
|
|
1257
1263
|
// Current frame refs
|
|
1258
1264
|
this._currentFrame = null;
|
|
1259
1265
|
this._currentRawFrame = null;
|
|
@@ -1280,6 +1286,7 @@ var PlaybackPipeline = class extends EventEmitter {
|
|
|
1280
1286
|
modelId: config.lam.modelId,
|
|
1281
1287
|
neutralTransitionEnabled: this.neutralTransitionEnabled
|
|
1282
1288
|
});
|
|
1289
|
+
this.rampInSmoother = new BlendshapeSmoother({ halflife: _PlaybackPipeline.RAMP_IN_HALFLIFE });
|
|
1283
1290
|
this.scheduler = new AudioScheduler({
|
|
1284
1291
|
sampleRate: this.sampleRate,
|
|
1285
1292
|
initialLookaheadSec: audioDelayMs / 1e3
|
|
@@ -1347,6 +1354,10 @@ var PlaybackPipeline = class extends EventEmitter {
|
|
|
1347
1354
|
this.frameLoopCount = 0;
|
|
1348
1355
|
this._currentFrame = null;
|
|
1349
1356
|
this._currentRawFrame = null;
|
|
1357
|
+
this.rampInSmoother.reset();
|
|
1358
|
+
this.rampInActive = true;
|
|
1359
|
+
this.rampInLastTime = 0;
|
|
1360
|
+
this.rampInStartTime = 0;
|
|
1350
1361
|
this.cancelNeutralTransition();
|
|
1351
1362
|
this.scheduler.warmup();
|
|
1352
1363
|
this.sessionStartTime = getClock().now();
|
|
@@ -1483,17 +1494,36 @@ var PlaybackPipeline = class extends EventEmitter {
|
|
|
1483
1494
|
}
|
|
1484
1495
|
}
|
|
1485
1496
|
if (lamFrame) {
|
|
1486
|
-
|
|
1497
|
+
let effectiveFrame = lamFrame;
|
|
1498
|
+
if (this.rampInActive) {
|
|
1499
|
+
const now = getClock().now();
|
|
1500
|
+
if (this.rampInLastTime === 0) {
|
|
1501
|
+
this.rampInStartTime = now;
|
|
1502
|
+
this.rampInLastTime = now;
|
|
1503
|
+
}
|
|
1504
|
+
this.rampInSmoother.setTarget(lamFrame);
|
|
1505
|
+
const dt = (now - this.rampInLastTime) / 1e3;
|
|
1506
|
+
this.rampInLastTime = now;
|
|
1507
|
+
if (dt > 0) {
|
|
1508
|
+
const smoothed = this.rampInSmoother.update(dt);
|
|
1509
|
+
this._rampInBuffer.set(smoothed);
|
|
1510
|
+
effectiveFrame = this._rampInBuffer;
|
|
1511
|
+
}
|
|
1512
|
+
if (now - this.rampInStartTime > _PlaybackPipeline.RAMP_IN_DURATION_MS) {
|
|
1513
|
+
this.rampInActive = false;
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
const scaled = applyProfile(effectiveFrame, this.profile, this._profileBuffer);
|
|
1487
1517
|
this._currentFrame = scaled;
|
|
1488
|
-
this._currentRawFrame =
|
|
1518
|
+
this._currentRawFrame = effectiveFrame;
|
|
1489
1519
|
const fullFrame = {
|
|
1490
1520
|
blendshapes: scaled,
|
|
1491
|
-
rawBlendshapes:
|
|
1521
|
+
rawBlendshapes: effectiveFrame,
|
|
1492
1522
|
timestamp: currentTime,
|
|
1493
1523
|
emotion: this._emotion ?? void 0
|
|
1494
1524
|
};
|
|
1495
1525
|
this.emit("frame", fullFrame);
|
|
1496
|
-
this.emit("frame:raw",
|
|
1526
|
+
this.emit("frame:raw", effectiveFrame);
|
|
1497
1527
|
}
|
|
1498
1528
|
this.frameAnimationId = requestAnimationFrame(updateFrame);
|
|
1499
1529
|
};
|
|
@@ -1593,6 +1623,11 @@ var PlaybackPipeline = class extends EventEmitter {
|
|
|
1593
1623
|
this.emit("state", state);
|
|
1594
1624
|
}
|
|
1595
1625
|
};
|
|
1626
|
+
// Ramp-in smoother: smooths neutral → first inference frame at start-of-speech
|
|
1627
|
+
_PlaybackPipeline.RAMP_IN_HALFLIFE = 0.05;
|
|
1628
|
+
// 50ms — snappy but smooth
|
|
1629
|
+
_PlaybackPipeline.RAMP_IN_DURATION_MS = 150;
|
|
1630
|
+
var PlaybackPipeline = _PlaybackPipeline;
|
|
1596
1631
|
|
|
1597
1632
|
// src/audio/TTSPlayback.ts
|
|
1598
1633
|
var logger6 = createLogger("TTSPlayback");
|