import { b as m } from "../three-vrm.module-BuztCP2r.js";
const S = [0, 400, 560, 2400, 4800], p = [0, 500, 700, 3e3, 6e3], x = [], h = [], f = 1024, A = 44100;
for (let a = 0; a < S.length; a++)
  h[a] = Math.round(
    2 * f / A * S[a]
  );
for (let a = 0; a < p.length; a++)
  x[a] = Math.round(
    2 * f / A * p[a]
  );
class g {
  constructor(s, e) {
    this.vrm = s, this.onAudioEnd = e;
    const n = (i, r) => {
      requestAnimationFrame(n), this.update(i, r);
    };
    n();
  }
  start(s) {
    this.userSpeechAnalyzer = this.audioContext.createAnalyser(), this.userSpeechAnalyzer.smoothingTimeConstant = 0.5, this.userSpeechAnalyzer.fftSize = f, this.mediaStreamSource && this.mediaStreamSource.stop(), this.mediaStreamSource = this.audioContext.createMediaStreamSource(s), this.meter = g.createAudioMeter(this.audioContext), this.mediaStreamSource.connect(this.meter), this.mediaStreamSource.connect(this.audioContext.destination), this.mediaStreamSource.connect(this.userSpeechAnalyzer), this.mediaStreamSource.onended = () => {
      this.onAudioEnd && this.onAudioEnd();
    };
  }
  startWithAudio(s, e, n, i) {
    s.crossOrigin = "anonymous", this.audioContext = e;
    const r = this.audioContext.createMediaStreamDestination();
    this.audioContext.createMediaElementSource(s).connect(r);
    const c = r.stream;
    n && n(), s.addEventListener("ended", function() {
      i && i();
    }), this.start(c);
  }
  startFromAudioBuffer(s) {
    this.audioContext || (this.audioContext = new AudioContext()), this.userSpeechAnalyzer = this.audioContext.createAnalyser(), this.userSpeechAnalyzer.smoothingTimeConstant = 0.5, this.userSpeechAnalyzer.fftSize = f, this.mediaStreamSource && this.mediaStreamSource.stop(), this.mediaStreamSource = this.audioContext.createBufferSource(), this.mediaStreamSource.buffer = s, this.meter = g.createAudioMeter(this.audioContext), this.mediaStreamSource.connect(this.meter), this.mediaStreamSource.connect(this.audioContext.destination), this.audioContext.createGain(), this.audioContext.resume(), this.mediaStreamSource.start ? this.mediaStreamSource.start(0) : this.mediaStreamSource.play ? this.mediaStreamSource.play(0) : this.mediaStreamSource.noteOn && this.mediaStreamSource.noteOn(0), this.mediaStreamSource.connect(this.userSpeechAnalyzer), this.mediaStreamSource.onended = () => {
      this.onAudioEnd && this.onAudioEnd();
    };
  }
  destroy() {
    var s, e, n;
    return (s = this.meter) == null || s.shutdown(), this.meter = null, (e = this.mediaStreamSource) == null || e.disconnect(), ((n = this.audioContext) == null ? void 0 : n.close().catch(() => {
    })) || Promise.resolve();
  }
  update(s) {
    if (this.meter) {
      const { volume: e } = this.meter;
      if (e < 0.01)
        this.vrm.expressionManager.setValue(m.Oh, 0), this.vrm.expressionManager.setValue(m.Ah, 0), this.vrm.expressionManager.setValue(m.Ee, 0);
      else {
        const { ah: n, oh: i, ee: r } = this.update2();
        this.vrm.expressionManager.setValue(m.Oh, i), this.vrm.expressionManager.setValue(m.Ah, n), this.vrm.expressionManager.setValue(m.Ee, r), this.vrm.expressionManager.update(s);
      }
    }
  }
  update2() {
    function s(t) {
      const M = new Float32Array(t.length);
      for (let l = 0; l < t.length; l++)
        M[l] = 0.5 + (t[l] + 20) / 140;
      return M;
    }
    const e = new Float32Array(
      this.userSpeechAnalyzer.frequencyBinCount
    );
    this.userSpeechAnalyzer.getFloatFrequencyData(e);
    const n = s(e), i = new Float32Array(S.length), r = new Float32Array(p.length);
    for (let t = 0; t < S.length - 1; t++) {
      for (let o = h[t]; o <= h[t + 1]; o++)
        n[o] > 0 && (i[t] += n[o]);
      i[t] /= h[t + 1] - h[t];
    }
    for (let t = 0; t < p.length - 1; t++) {
      for (let o = h[t]; o <= h[t + 1]; o++)
        n[o] > 0 && (r[t] += n[o]);
      i[t] /= h[t + 1] - h[t], r[t] = r[t] / (x[t + 1] - x[t]);
    }
    const u = Math.max(r[1], i[1]) > 0.2 ? 1 - 2 * Math.max(i[2], r[2]) : (1 - 2 * Math.max(i[2], r[2])) * 5 * Math.max(i[1], r[1]), c = 3 * Math.max(i[3], r[3]), y = 0.8 * (Math.max(i[1], r[1]) - Math.max(i[3], r[3]));
    return { oh: u, ee: y, ah: c };
  }
  static createAudioMeter(s) {
    const e = s.createScriptProcessor(512);
    return e.onaudioprocess = (n) => {
      const i = n.inputBuffer.getChannelData(0), r = i.length;
      let u = 0, c;
      for (let t = 0; t < r; t++)
        c = i[t], Math.abs(c) >= e.clipLevel && (e.clipping = !0, e.lastClip = window.performance.now()), u += c * c;
      const y = Math.sqrt(u / r);
      e.volume = Math.max(y, e.volume * e.averaging);
    }, e.clipping = !1, e.lastClip = 0, e.volume = 0, e.clipLevel = 0.98, e.averaging = 0.95, e.clipLag = 750, e.connect(s.destination), e.checkClipping = () => e.clipping ? (e.lastClip + e.clipLag < window.performance.now() && (e.clipping = !1), e.clipping) : !1, e.shutdown = () => {
      e.disconnect(), e.onaudioprocess = null;
    }, e;
  }
}
let d;
const v = async (a, s, e, n, i, r) => {
  if (a) {
    d && d.destroy(), d = new g(a, i);
    try {
      d.startWithAudio(
        s,
        e,
        n,
        i
      );
    } catch {
      try {
        s.currentTime = 0, await s.play(), n && n(), setTimeout(() => {
          i();
        }, 3e3);
      } catch {
        r();
      }
    }
  }
};
export {
  v as startLipSync
};
