@omote/core 0.9.6 → 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 CHANGED
@@ -678,6 +678,13 @@ declare class PlaybackPipeline extends EventEmitter<PlaybackPipelineEvents> {
678
678
  private neutralTransitionFrame;
679
679
  private neutralTransitionStart;
680
680
  private neutralAnimationId;
681
+ private static readonly RAMP_IN_HALFLIFE;
682
+ private static readonly RAMP_IN_DURATION_MS;
683
+ private rampInSmoother;
684
+ private rampInActive;
685
+ private rampInLastTime;
686
+ private rampInStartTime;
687
+ private readonly _rampInBuffer;
681
688
  private _currentFrame;
682
689
  private _currentRawFrame;
683
690
  private _emotion;
package/dist/index.d.ts CHANGED
@@ -678,6 +678,13 @@ declare class PlaybackPipeline extends EventEmitter<PlaybackPipelineEvents> {
678
678
  private neutralTransitionFrame;
679
679
  private neutralTransitionStart;
680
680
  private neutralAnimationId;
681
+ private static readonly RAMP_IN_HALFLIFE;
682
+ private static readonly RAMP_IN_DURATION_MS;
683
+ private rampInSmoother;
684
+ private rampInActive;
685
+ private rampInLastTime;
686
+ private rampInStartTime;
687
+ private readonly _rampInBuffer;
681
688
  private _currentFrame;
682
689
  private _currentRawFrame;
683
690
  private _emotion;
package/dist/index.js CHANGED
@@ -2316,7 +2316,7 @@ function applyProfile(raw, profile, out) {
2316
2316
 
2317
2317
  // src/audio/PlaybackPipeline.ts
2318
2318
  var logger5 = createLogger("PlaybackPipeline");
2319
- var PlaybackPipeline = class extends EventEmitter {
2319
+ var _PlaybackPipeline = class _PlaybackPipeline extends EventEmitter {
2320
2320
  constructor(config) {
2321
2321
  super();
2322
2322
  this.config = config;
@@ -2335,6 +2335,10 @@ var PlaybackPipeline = class extends EventEmitter {
2335
2335
  this.neutralTransitionFrame = null;
2336
2336
  this.neutralTransitionStart = 0;
2337
2337
  this.neutralAnimationId = null;
2338
+ this.rampInActive = false;
2339
+ this.rampInLastTime = 0;
2340
+ this.rampInStartTime = 0;
2341
+ this._rampInBuffer = new Float32Array(52);
2338
2342
  // Current frame refs
2339
2343
  this._currentFrame = null;
2340
2344
  this._currentRawFrame = null;
@@ -2361,6 +2365,7 @@ var PlaybackPipeline = class extends EventEmitter {
2361
2365
  modelId: config.lam.modelId,
2362
2366
  neutralTransitionEnabled: this.neutralTransitionEnabled
2363
2367
  });
2368
+ this.rampInSmoother = new BlendshapeSmoother({ halflife: _PlaybackPipeline.RAMP_IN_HALFLIFE });
2364
2369
  this.scheduler = new AudioScheduler({
2365
2370
  sampleRate: this.sampleRate,
2366
2371
  initialLookaheadSec: audioDelayMs / 1e3
@@ -2428,6 +2433,10 @@ var PlaybackPipeline = class extends EventEmitter {
2428
2433
  this.frameLoopCount = 0;
2429
2434
  this._currentFrame = null;
2430
2435
  this._currentRawFrame = null;
2436
+ this.rampInSmoother.reset();
2437
+ this.rampInActive = true;
2438
+ this.rampInLastTime = 0;
2439
+ this.rampInStartTime = 0;
2431
2440
  this.cancelNeutralTransition();
2432
2441
  this.scheduler.warmup();
2433
2442
  this.sessionStartTime = getClock().now();
@@ -2564,17 +2573,36 @@ var PlaybackPipeline = class extends EventEmitter {
2564
2573
  }
2565
2574
  }
2566
2575
  if (lamFrame) {
2567
- const scaled = applyProfile(lamFrame, this.profile, this._profileBuffer);
2576
+ let effectiveFrame = lamFrame;
2577
+ if (this.rampInActive) {
2578
+ const now = getClock().now();
2579
+ if (this.rampInLastTime === 0) {
2580
+ this.rampInStartTime = now;
2581
+ this.rampInLastTime = now;
2582
+ }
2583
+ this.rampInSmoother.setTarget(lamFrame);
2584
+ const dt = (now - this.rampInLastTime) / 1e3;
2585
+ this.rampInLastTime = now;
2586
+ if (dt > 0) {
2587
+ const smoothed = this.rampInSmoother.update(dt);
2588
+ this._rampInBuffer.set(smoothed);
2589
+ effectiveFrame = this._rampInBuffer;
2590
+ }
2591
+ if (now - this.rampInStartTime > _PlaybackPipeline.RAMP_IN_DURATION_MS) {
2592
+ this.rampInActive = false;
2593
+ }
2594
+ }
2595
+ const scaled = applyProfile(effectiveFrame, this.profile, this._profileBuffer);
2568
2596
  this._currentFrame = scaled;
2569
- this._currentRawFrame = lamFrame;
2597
+ this._currentRawFrame = effectiveFrame;
2570
2598
  const fullFrame = {
2571
2599
  blendshapes: scaled,
2572
- rawBlendshapes: lamFrame,
2600
+ rawBlendshapes: effectiveFrame,
2573
2601
  timestamp: currentTime,
2574
2602
  emotion: this._emotion ?? void 0
2575
2603
  };
2576
2604
  this.emit("frame", fullFrame);
2577
- this.emit("frame:raw", lamFrame);
2605
+ this.emit("frame:raw", effectiveFrame);
2578
2606
  }
2579
2607
  this.frameAnimationId = requestAnimationFrame(updateFrame);
2580
2608
  };
@@ -2674,6 +2702,11 @@ var PlaybackPipeline = class extends EventEmitter {
2674
2702
  this.emit("state", state);
2675
2703
  }
2676
2704
  };
2705
+ // Ramp-in smoother: smooths neutral → first inference frame at start-of-speech
2706
+ _PlaybackPipeline.RAMP_IN_HALFLIFE = 0.05;
2707
+ // 50ms — snappy but smooth
2708
+ _PlaybackPipeline.RAMP_IN_DURATION_MS = 150;
2709
+ var PlaybackPipeline = _PlaybackPipeline;
2677
2710
 
2678
2711
  // src/audio/TTSPlayback.ts
2679
2712
  var logger6 = createLogger("TTSPlayback");