in src/core/LipsyncFeature.js [256:339]
async _onViseme({mark}) {
Object.entries(this._visemeLayers).forEach(([layerName, animName]) => {
// Make sure the layer can be manipulated
const {isActive, visemeMap} = this._managedLayers[layerName].animations[
animName
];
if (!isActive) {
return;
}
// Take variables from the viseme if they exist and default to the layer
const {
name: viseme,
isActive: isVisemeActive,
decayRate,
blendTime,
easingFn,
overrideWeight,
} = {
...this._managedLayers[layerName],
...visemeMap[mark.value],
};
const visemeNames = this._host.AnimationFeature.getAnimationBlendNames(
layerName,
animName
);
// Make sure the new viseme has an active freeBlend weight
if (!isVisemeActive || !visemeNames.includes(viseme)) {
return;
}
// Find the peak weight for the viseme and the amount of time it should
// take to reach it
let weight = 1;
const duration = mark.duration / 1000;
if (duration < blendTime) {
const lerpFactor = blendTime > 0 ? duration / blendTime : 1;
weight =
overrideWeight !== undefined
? overrideWeight
: MathUtils.lerp(0, 1, lerpFactor);
}
const blendInTime = Math.min(duration, blendTime);
// Find the amount and time viseme will be held for
const holdTime = duration - blendTime;
if (holdTime < 0) {
// Perform in -> out animation
this._animateSimpleViseme(
layerName,
animName,
viseme,
weight,
blendInTime,
blendTime,
easingFn
);
} else {
const lerpFactor =
decayRate.seconds > 0 ? holdTime / decayRate.seconds : 1;
// Perform in -> hold -> out animation
const decayWeight = MathUtils.lerp(
weight,
weight * decayRate.amount,
Math.min(1, lerpFactor)
);
this._animateHeldViseme(
layerName,
animName,
viseme,
weight,
decayWeight,
blendInTime,
holdTime,
blendTime,
easingFn
);
}
});
}