live2d-motionsync
Version:
Live2D Motionsync, a lip-sync library for Live2D models.
134 lines (133 loc) • 4.82 kB
JavaScript
var h = Object.defineProperty;
var f = (s, t, o) => t in s ? h(s, t, { enumerable: !0, configurable: !0, writable: !0, value: o }) : s[t] = o;
var n = (s, t, o) => f(s, typeof t != "symbol" ? t + "" : t, o);
import { c, C as u, M as m, f as S } from "./fallback.motionsync3-1oooNFSa.js";
let a;
function p() {
const s = ["click", "keydown", "touchstart", "mousedown", "pointerdown"];
a = new AudioContext();
const t = () => {
a.state === "suspended" && a.resume().then(() => {
console.log("Audio context resumed");
});
};
s.forEach((o) => {
window.addEventListener(o, t, { capture: !0 });
});
}
function y() {
return a;
}
p();
const d = 48e3;
class x {
constructor(t) {
n(this, "audioBuffer", null);
n(this, "audioSource", null);
n(this, "previousSamplePosition", 0);
n(this, "audioElapsedTime", 0);
n(this, "audioContextPreviousTime", 0);
n(this, "_motionSync", null);
n(this, "_internalModel");
n(this, "_model");
n(this, "soundBuffer", new c());
this._internalModel = t, this._model = t.coreModel, u.startUp(new m()), u.initialize();
}
get audioContext() {
return y();
}
async loadAudio(t) {
const e = await (await fetch(t)).arrayBuffer();
this.reset(), this.audioBuffer = await this.audioContext.decodeAudioData(e);
}
async loadAudioBuffer(t) {
this.reset(), this.audioBuffer = t;
}
resetMouthStatus() {
try {
if (!this._motionSync) return;
const t = this._motionSync.getData().getSetting(0);
if (!t) return;
const o = t.cubismParameterList;
if (!o) return;
const e = o._ptr.map(
(i) => i.parameterIndex
);
for (const i of e)
this._model.setParameterValueByIndex(i, 0);
} catch (t) {
console.error(t);
}
}
reset() {
this.resetMouthStatus(), this.audioSource && (this.audioSource.stop(), this.audioSource.disconnect(), this.audioSource = null), this.audioContextPreviousTime = 0, this.previousSamplePosition = 0, this.audioElapsedTime = 0, this.soundBuffer.clear(), this.soundBuffer = new c();
}
async play(t) {
return new Promise(async (o, e) => {
typeof t == "string" ? await this.loadAudio(t) : await this.loadAudioBuffer(t), this.audioBuffer ? (this.audioSource = this.audioContext.createBufferSource(), this.audioSource.buffer = this.audioBuffer, this.audioSource.connect(this.audioContext.destination), this.audioSource.start(0), this.audioSource.onended = () => {
o();
}, this.audioContextPreviousTime = this.audioContext.currentTime) : e(new Error("audioBuffer is null"));
});
}
updateMotionSync() {
if (!this.audioBuffer || !this.audioSource)
return;
const t = this.audioContext.currentTime;
t <= this.audioContextPreviousTime && (this.audioContextPreviousTime = t);
const o = t - this.audioContextPreviousTime;
this.audioElapsedTime += o;
const e = Math.floor(
this.audioElapsedTime * this.audioBuffer.sampleRate
);
if (this.previousSamplePosition <= this.audioBuffer.length) {
const i = this.audioBuffer.getChannelData(0).slice(this.previousSamplePosition, e);
for (let r = 0; r < i.length; r++)
this.soundBuffer.pushBack(i[r]);
if (!this._motionSync) return;
this._motionSync.setSoundBuffer(0, this.soundBuffer, 0), this._motionSync.updateParameters(this._model, o);
const l = this._motionSync.getLastTotalProcessedCount(0);
this.removeProcessedData(l), this.audioContextPreviousTime = t, this.previousSamplePosition = e;
}
}
modelUpdateWithMotionSync() {
if (!this._motionSync) return;
const o = this._internalModel, e = o.motionManager.update;
o.motionManager.update = (...i) => {
e.apply(this._internalModel.motionManager, i), this.updateMotionSync();
};
}
removeProcessedData(t) {
const o = this.soundBuffer;
if (t < o.getSize())
return !(o != null && o.begin()) || (o == null ? void 0 : o._size) <= t || (o._ptr.splice(0, t), o._size -= t), o;
}
loadMotionSync(t, o = d) {
if (t == null || t.byteLength == 0) {
console.warn("Failed to loadMotionSync().");
return;
}
this._motionSync = u.create(
this._model,
t,
t.byteLength,
o
), this.modelUpdateWithMotionSync();
}
async loadDefaultMotionSync(t = d) {
const e = await new Blob([S], { type: "application/json" }).arrayBuffer();
this.loadMotionSync(e, t);
}
async loadMotionSyncFromUrl(t, o = d) {
try {
const i = await (await fetch(t)).arrayBuffer();
this.loadMotionSync(i, o);
} catch {
console.warn("Failed to loadMotionSync(). Use default fallback."), await this.loadDefaultMotionSync(o);
}
}
}
export {
x as MotionSync,
y as getAudioContext,
p as initAudioContext
};