audio-mixer-engine 1.3.5 → 1.3.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.
@@ -1,4 +1,4 @@
1
- function Jl(V) {
1
+ function sl(V) {
2
2
  return { all: V = V || /* @__PURE__ */ new Map(), on: function(l, U) {
3
3
  var F = V.get(l);
4
4
  F ? F.push(U) : V.set(l, [U]);
@@ -24,7 +24,7 @@ class dl {
24
24
  constructor(l, U = {}) {
25
25
  if (new.target === dl)
26
26
  throw new Error("AudioEngine is abstract and cannot be instantiated directly");
27
- this.audioContext = l, this.options = U, this.isInitialized = !1, this.channels = /* @__PURE__ */ new WeakMap(), this.activeChannels = /* @__PURE__ */ new Set(), this.eventBus = Jl();
27
+ this.audioContext = l, this.options = U, this.isInitialized = !1, this.channels = /* @__PURE__ */ new WeakMap(), this.activeChannels = /* @__PURE__ */ new Set(), this.eventBus = sl();
28
28
  }
29
29
  /**
30
30
  * Subscribe to engine events
@@ -992,12 +992,8 @@ class Dl extends Ql {
992
992
  const U = this.activeSources.get(l);
993
993
  U && (U.forEach((F) => {
994
994
  try {
995
- if (F.loop)
996
- F.stop();
997
- else {
998
- const Z = this.engine.audioContext.currentTime, d = F._velocityGain;
999
- d && d.gain.linearRampToValueAtTime(0, Z + 0.05), F.stop(Z + 0.05);
1000
- }
995
+ const Z = F._velocityGain, d = this.engine.audioContext.currentTime, Q = F.loop ? 0.15 : 0.03;
996
+ Z && (Z.gain.setValueAtTime(Z.gain.value, d), Z.gain.exponentialRampToValueAtTime(1e-4, d + Q)), F.stop(d + Q);
1001
997
  } catch {
1002
998
  }
1003
999
  }), U.clear(), this.activeSources.delete(l));
@@ -1578,8 +1574,8 @@ class Pl {
1578
1574
  m = W + U * 4 * R.numerator / R.denominator;
1579
1575
  const t = R.numerator, c = [], b = U * (4 / R.denominator);
1580
1576
  for (let a = 0; a < t; a++) {
1581
- const J = W + a * b, s = this._ticksToTime(J, l);
1582
- c.push(s);
1577
+ const s = W + a * b, J = this._ticksToTime(s, l);
1578
+ c.push(J);
1583
1579
  }
1584
1580
  d.push({
1585
1581
  sig: [R.numerator, R.denominator],
@@ -1992,22 +1988,22 @@ class Ol {
1992
1988
  // Total beats
1993
1989
  t.sig[1]
1994
1990
  // Keep original note value
1995
- ], J = [
1991
+ ], s = [
1996
1992
  ...t.beats || [],
1997
1993
  ...b.beats || []
1998
1994
  ];
1999
1995
  t = {
2000
1996
  sig: a,
2001
- beats: J
1997
+ beats: s
2002
1998
  }, R[d] = t, R.splice(d + 1, 1), c = a[0];
2003
1999
  }
2004
2000
  if (c > m) {
2005
- const b = m, a = c - m, J = t.beats ? t.beats.slice(0, b) : [], s = t.beats ? t.beats.slice(b) : [], i = {
2001
+ const b = m, a = c - m, s = t.beats ? t.beats.slice(0, b) : [], J = t.beats ? t.beats.slice(b) : [], i = {
2006
2002
  sig: [b, t.sig[1]],
2007
- beats: J
2003
+ beats: s
2008
2004
  }, S = {
2009
2005
  sig: [a, t.sig[1]],
2010
- beats: s
2006
+ beats: J
2011
2007
  };
2012
2008
  R[d] = i, R.splice(d + 1, 0, S), t = i;
2013
2009
  }
@@ -2025,14 +2021,14 @@ class Ol {
2025
2021
  const t = l[Q], c = t.barNumber, b = Z[c] !== void 0 ? Z[c] : 4;
2026
2022
  Z[c] === void 0 && (Z[c] = b);
2027
2023
  const a = [];
2028
- for (let s = 0; s < b; s++)
2024
+ for (let J = 0; J < b; J++)
2029
2025
  a.push(m), m += n;
2030
- const J = {
2026
+ const s = {
2031
2027
  sig: [b, 4],
2032
2028
  // Default to quarter notes
2033
2029
  beats: a
2034
2030
  };
2035
- this._generateBeatsForBar(F, t, J, b), Q++;
2031
+ this._generateBeatsForBar(F, t, s, b), Q++;
2036
2032
  }
2037
2033
  }
2038
2034
  return F;
@@ -2086,7 +2082,7 @@ class tl {
2086
2082
  constructor(l = null, U, F = null, Z = null) {
2087
2083
  if (!U)
2088
2084
  throw new Error("Parsed MIDI data is required");
2089
- this.audioEngine = l, this._audioEngineReady = !!(l && l.isInitialized), this.instrumentMap = F || {}, this.parsedData = U, this._isPlaying = !1, this._isPreScheduling = !1, this._currentTime = 0, this._totalDuration = 0, this.playbackSpeed = 1, this.partChannels = /* @__PURE__ */ new Map(), this.partOutputs = /* @__PURE__ */ new Map(), this.playbackStartTime = 0, this.lookAheadTime = 0.05, this.scheduleInterval = null, this.partNotePointers = /* @__PURE__ */ new Map(), this.partProgramPointers = /* @__PURE__ */ new Map(), this.eventBus = Jl(), this.beatMapper = new Ol(), this.beats = [], this.structureMetadata = Z, this._calculateTotalDuration();
2085
+ this.audioEngine = l, this._audioEngineReady = !!(l && l.isInitialized), this.instrumentMap = F || {}, this.parsedData = U, this._isPlaying = !1, this._isPreScheduling = !1, this._currentTime = 0, this._totalDuration = 0, this.playbackSpeed = 1, this.partChannels = /* @__PURE__ */ new Map(), this.partOutputs = /* @__PURE__ */ new Map(), this.playbackStartTime = 0, this.lookAheadTime = 0.05, this.scheduleInterval = null, this.partNotePointers = /* @__PURE__ */ new Map(), this.partProgramPointers = /* @__PURE__ */ new Map(), this.eventBus = sl(), this.beatMapper = new Ol(), this.beats = [], this.structureMetadata = Z, this._calculateTotalDuration();
2090
2086
  const d = Z || this._createDefaultStructureMetadata();
2091
2087
  this.beats = this.beatMapper.mapBeats(U, d), this._audioEngineReady && (this._setupPartChannels(), this._resetNotePointers(), this._resetProgramPointers());
2092
2088
  }
@@ -2871,11 +2867,11 @@ class nU {
2871
2867
  continue;
2872
2868
  }
2873
2869
  if (n.tagName !== "note") continue;
2874
- const m = G(n, "chord") !== null, t = G(n, "rest") !== null, c = G(n, "grace") !== null, b = y(n, "duration", 0), a = this.timing.xmlDurationToTicks(b), J = G(n, "time-modification") !== null;
2870
+ const m = G(n, "chord") !== null, t = G(n, "rest") !== null, c = G(n, "grace") !== null, b = y(n, "duration", 0), a = this.timing.xmlDurationToTicks(b), s = G(n, "time-modification") !== null;
2875
2871
  if (c) continue;
2876
2872
  m && (R = W);
2877
- const s = R;
2878
- if (m || (W = R), R = s + a, t) continue;
2873
+ const J = R;
2874
+ if (m || (W = R), R = J + a, t) continue;
2879
2875
  const i = G(n, "pitch");
2880
2876
  if (!i) continue;
2881
2877
  const S = VU(i), Y = p(n, "tie");
@@ -2886,19 +2882,19 @@ class nU {
2886
2882
  }
2887
2883
  if (D && this.pendingTies.has(S)) {
2888
2884
  const X = this.pendingTies.get(S);
2889
- L ? (X.endTick = s + a, X.isTuplet = X.isTuplet || J) : (X.endTick = s + a, X.isTuplet = X.isTuplet || J, d.push(this._buildNote(X, F, Z)), this.pendingTies.delete(S));
2885
+ L ? (X.endTick = J + a, X.isTuplet = X.isTuplet || s) : (X.endTick = J + a, X.isTuplet = X.isTuplet || s, d.push(this._buildNote(X, F, Z)), this.pendingTies.delete(S));
2890
2886
  } else L ? this.pendingTies.set(S, {
2891
2887
  pitch: S,
2892
- startTick: s,
2893
- endTick: s + a,
2888
+ startTick: J,
2889
+ endTick: J + a,
2894
2890
  velocity: this.currentVelocity,
2895
- isTuplet: J
2891
+ isTuplet: s
2896
2892
  }) : d.push(this._buildNote({
2897
2893
  pitch: S,
2898
- startTick: s,
2899
- endTick: s + a,
2894
+ startTick: J,
2895
+ endTick: J + a,
2900
2896
  velocity: this.currentVelocity,
2901
- isTuplet: J
2897
+ isTuplet: s
2902
2898
  }, F, Z));
2903
2899
  const A = p(n, "lyric");
2904
2900
  for (const X of A) {
@@ -2908,9 +2904,9 @@ class nU {
2908
2904
  Q.push({
2909
2905
  text: C,
2910
2906
  syllabic: K || "single",
2911
- tick: s,
2912
- time: this.timing.tickToTime(s),
2913
- isTuplet: J
2907
+ tick: J,
2908
+ time: this.timing.tickToTime(J),
2909
+ isTuplet: s
2914
2910
  });
2915
2911
  }
2916
2912
  }
@@ -3022,7 +3018,7 @@ function WU(V) {
3022
3018
  const c = G(m, "ending");
3023
3019
  if (c) {
3024
3020
  const b = O(c, "type"), a = O(c, "number");
3025
- b === "start" && a && (Q.endings = a.split(/[,\s]+/).map((J) => parseInt(J.trim(), 10)).filter((J) => !isNaN(J))), (b === "stop" || b === "discontinue") && (Q.endingStop = !0);
3021
+ b === "start" && a && (Q.endings = a.split(/[,\s]+/).map((s) => parseInt(s.trim(), 10)).filter((s) => !isNaN(s))), (b === "stop" || b === "discontinue") && (Q.endingStop = !0);
3026
3022
  }
3027
3023
  }
3028
3024
  const W = p(d, "direction");
@@ -3033,10 +3029,10 @@ function WU(V) {
3033
3029
  b && (Q.segno = b);
3034
3030
  const a = t.getAttribute("coda");
3035
3031
  a && (Q.coda = a), t.getAttribute("fine") === "yes" && (Q.fine = !0), t.getAttribute("dacapo") === "yes" && (Q.dacapo = !0);
3036
- const J = t.getAttribute("dalsegno");
3037
- J && (Q.dalsegno = J);
3038
- const s = t.getAttribute("tocoda");
3039
- s && (Q.tocoda = s);
3032
+ const s = t.getAttribute("dalsegno");
3033
+ s && (Q.dalsegno = s);
3034
+ const J = t.getAttribute("tocoda");
3035
+ J && (Q.tocoda = J);
3040
3036
  const i = t.getAttribute("tempo");
3041
3037
  i && (Q.tempo = parseFloat(i));
3042
3038
  }
@@ -3159,7 +3155,7 @@ function bU(V) {
3159
3155
  F++;
3160
3156
  continue;
3161
3157
  }
3162
- W = JU(V, b), R = !W, F = b;
3158
+ W = sU(V, b), R = !W, F = b;
3163
3159
  continue;
3164
3160
  }
3165
3161
  F++;
@@ -3182,12 +3178,12 @@ function BU(V, l) {
3182
3178
  if (V[U].coda === l) return U;
3183
3179
  return -1;
3184
3180
  }
3185
- function JU(V, l) {
3181
+ function sU(V, l) {
3186
3182
  for (let U = l; U < V.length; U++)
3187
3183
  if (V[U].tocoda) return V[U].tocoda;
3188
3184
  return null;
3189
3185
  }
3190
- function sU(V) {
3186
+ function JU(V) {
3191
3187
  if (V.length === 0) return [];
3192
3188
  const l = [];
3193
3189
  let U = null;
@@ -3258,7 +3254,7 @@ class GU {
3258
3254
  denominator: b.currentTimeSig.denominator
3259
3255
  }]
3260
3256
  });
3261
- const a = {}, J = /* @__PURE__ */ new Map();
3257
+ const a = {}, s = /* @__PURE__ */ new Map();
3262
3258
  for (let h = 0; h < R.length; h++) {
3263
3259
  const B = R[h], e = O(B, "id"), N = Q.partInfos.find((x) => x.id === e) || {
3264
3260
  id: e,
@@ -3266,7 +3262,7 @@ class GU {
3266
3262
  midiProgram: null,
3267
3263
  midiChannel: null
3268
3264
  };
3269
- J.set(e, {
3265
+ s.set(e, {
3270
3266
  partElement: B,
3271
3267
  measures: p(B, "measure"),
3272
3268
  channel: h,
@@ -3282,7 +3278,7 @@ class GU {
3282
3278
  // Default to choir_aahs
3283
3279
  };
3284
3280
  }
3285
- const s = [], i = sU(t), S = eU(n), Y = /* @__PURE__ */ new Map();
3281
+ const J = [], i = JU(t), S = eU(n), Y = /* @__PURE__ */ new Map();
3286
3282
  for (let h = 0; h < W.length; h++) {
3287
3283
  const B = W[h], e = G(B, "attributes"), N = {};
3288
3284
  if (e) {
@@ -3313,7 +3309,7 @@ class GU {
3313
3309
  Y.set(h, N);
3314
3310
  }
3315
3311
  const L = /* @__PURE__ */ new Map();
3316
- for (const [h, B] of J)
3312
+ for (const [h, B] of s)
3317
3313
  L.set(h, new nU(c, {
3318
3314
  defaultVelocity: U.defaultVelocity || 80
3319
3315
  }));
@@ -3321,8 +3317,8 @@ class GU {
3321
3317
  const B = h.measureIndex, e = Y.get(B) || {};
3322
3318
  e.divisions && (c.currentDivisions = e.divisions), e.timeSig && (c.currentTimeSig = { ...e.timeSig }), e.tempo && c.processTempo(e.tempo), e.swing && c.processSwing(e.swing);
3323
3319
  const N = c.currentTick, x = h.beatsInMeasure, E = c.generateBarStructureEntry(N, x);
3324
- s.push(E);
3325
- for (const [o, H] of J) {
3320
+ J.push(E);
3321
+ for (const [o, H] of s) {
3326
3322
  const j = H.measures[B];
3327
3323
  if (!j) continue;
3328
3324
  const f = L.get(o), { notes: q, lyrics: Fl } = f.extractMeasure(
@@ -3336,7 +3332,7 @@ class GU {
3336
3332
  const M = c.getTicksPerBeatInTimeSig() * x;
3337
3333
  c.advance(M);
3338
3334
  }
3339
- for (const [h, B] of J) {
3335
+ for (const [h, B] of s) {
3340
3336
  const N = L.get(h).flushPendingTies(B.channel, B.trackIndex), x = B.partInfo.name;
3341
3337
  a[x].notes.push(...N);
3342
3338
  }
@@ -3363,7 +3359,7 @@ class GU {
3363
3359
  index: B,
3364
3360
  name: h.name
3365
3361
  })), X = {};
3366
- for (const [h, B] of J) {
3362
+ for (const [h, B] of s) {
3367
3363
  const e = B.partInfo.name;
3368
3364
  X[e] = {
3369
3365
  trackIndex: B.trackIndex,
@@ -3373,7 +3369,7 @@ class GU {
3373
3369
  }
3374
3370
  const C = {
3375
3371
  parts: a,
3376
- barStructure: s,
3372
+ barStructure: J,
3377
3373
  metadata: {
3378
3374
  title: Q.title,
3379
3375
  composer: Q.composer,
@@ -3558,7 +3554,7 @@ var oU = /* @__PURE__ */ ll(Ul, 9, 1), YU = /* @__PURE__ */ ll(Ll, 5, 1), nl = f
3558
3554
  return (V[U] | V[U + 1] << 8 | V[U + 2] << 16) >> (l & 7);
3559
3555
  }, yU = function(V) {
3560
3556
  return (V + 7) / 8 | 0;
3561
- }, sl = function(V, l, U) {
3557
+ }, Jl = function(V, l, U) {
3562
3558
  return (l == null || l < 0) && (l = 0), (U == null || U > V.length) && (U = V.length), new T(V.subarray(l, U));
3563
3559
  }, pU = [
3564
3560
  "unexpected EOF",
@@ -3593,14 +3589,14 @@ var oU = /* @__PURE__ */ ll(Ul, 9, 1), YU = /* @__PURE__ */ ll(Ll, 5, 1), nl = f
3593
3589
  var ul = new T(Math.max(Sl * 2, il));
3594
3590
  ul.set(U), U = ul;
3595
3591
  }
3596
- }, m = l.f || 0, t = l.p || 0, c = l.b || 0, b = l.l, a = l.d, J = l.m, s = l.n, i = Z * 8;
3592
+ }, m = l.f || 0, t = l.p || 0, c = l.b || 0, b = l.l, a = l.d, s = l.m, J = l.n, i = Z * 8;
3597
3593
  do {
3598
3594
  if (!b) {
3599
3595
  m = z(V, t, 1);
3600
3596
  var S = z(V, t + 1, 3);
3601
3597
  if (t += 3, S)
3602
3598
  if (S == 1)
3603
- b = oU, a = YU, J = 9, s = 5;
3599
+ b = oU, a = YU, s = 9, J = 5;
3604
3600
  else if (S == 2) {
3605
3601
  var A = z(V, t, 31) + 257, X = z(V, t + 10, 15) + 4, C = A + z(V, t + 5, 31) + 1;
3606
3602
  t += 14;
@@ -3620,7 +3616,7 @@ var oU = /* @__PURE__ */ ll(Ul, 9, 1), YU = /* @__PURE__ */ ll(Ll, 5, 1), nl = f
3620
3616
  }
3621
3617
  }
3622
3618
  var M = K.subarray(0, A), o = K.subarray(A);
3623
- J = nl(M), s = nl(o), b = ll(M, J, 1), a = ll(o, s, 1);
3619
+ s = nl(M), J = nl(o), b = ll(M, s, 1), a = ll(o, J, 1);
3624
3620
  } else
3625
3621
  r(1);
3626
3622
  else {
@@ -3638,7 +3634,7 @@ var oU = /* @__PURE__ */ ll(Ul, 9, 1), YU = /* @__PURE__ */ ll(Ll, 5, 1), nl = f
3638
3634
  }
3639
3635
  }
3640
3636
  R && n(c + 131072);
3641
- for (var H = (1 << J) - 1, j = (1 << s) - 1, f = t; ; f = t) {
3637
+ for (var H = (1 << s) - 1, j = (1 << J) - 1, f = t; ; f = t) {
3642
3638
  var E = b[Wl(V, t) & H], q = E >> 4;
3643
3639
  if (t += E & 15, t > i) {
3644
3640
  W && r(0);
@@ -3677,9 +3673,9 @@ var oU = /* @__PURE__ */ ll(Ul, 9, 1), YU = /* @__PURE__ */ ll(Ll, 5, 1), nl = f
3677
3673
  U[c] = U[c - o];
3678
3674
  }
3679
3675
  }
3680
- l.l = b, l.p = f, l.b = c, l.f = m, b && (m = 1, l.m = J, l.d = a, l.n = s);
3676
+ l.l = b, l.p = f, l.b = c, l.f = m, b && (m = 1, l.m = s, l.d = a, l.n = J);
3681
3677
  } while (!m);
3682
- return c != U.length && Q ? sl(U, 0, c) : U.subarray(0, c);
3678
+ return c != U.length && Q ? Jl(U, 0, c) : U.subarray(0, c);
3683
3679
  }, kU = /* @__PURE__ */ new T(0), g = function(V, l) {
3684
3680
  return V[l] | V[l + 1] << 8;
3685
3681
  }, I = function(V, l) {
@@ -3699,7 +3695,7 @@ var LU = function(V) {
3699
3695
  for (var l = "", U = 0; ; ) {
3700
3696
  var F = V[U++], Z = (F > 127) + (F > 223) + (F > 239);
3701
3697
  if (U + Z > V.length)
3702
- return { s: l, r: sl(V, U - 1) };
3698
+ return { s: l, r: Jl(V, U - 1) };
3703
3699
  Z ? Z == 3 ? (F = ((F & 15) << 18 | (V[U++] & 63) << 12 | (V[U++] & 63) << 6 | V[U++] & 63) - 65536, l += String.fromCharCode(55296 | F >> 10, 56320 | F & 1023)) : Z & 1 ? l += String.fromCharCode((F & 31) << 6 | V[U++] & 63) : l += String.fromCharCode((F & 15) << 12 | (V[U++] & 63) << 6 | V[U++] & 63) : l += String.fromCharCode(F);
3704
3700
  }
3705
3701
  };
@@ -3737,8 +3733,8 @@ function zU(V, l) {
3737
3733
  Q = I(V, R) == 101075792, Q && (Z = I(V, R + 32), d = I(V, R + 48));
3738
3734
  }
3739
3735
  for (var W = 0; W < Z; ++W) {
3740
- var n = xU(V, d, Q), m = n[0], t = n[1], c = n[2], b = n[3], a = n[4], J = n[5], s = CU(V, J);
3741
- d = a, m ? m == 8 ? U[b] = TU(V.subarray(s, s + t), { out: new T(c) }) : r(14, "unknown compression type " + m) : U[b] = sl(V, s, s + t);
3736
+ var n = xU(V, d, Q), m = n[0], t = n[1], c = n[2], b = n[3], a = n[4], s = n[5], J = CU(V, s);
3737
+ d = a, m ? m == 8 ? U[b] = TU(V.subarray(J, J + t), { out: new T(c) }) : r(14, "unknown compression type " + m) : U[b] = Jl(V, J, J + t);
3742
3738
  }
3743
3739
  return U;
3744
3740
  }
@@ -3844,7 +3840,7 @@ class jU {
3844
3840
  * @param {number} [options.startup.delayMs=25] - Startup delay in milliseconds
3845
3841
  */
3846
3842
  constructor(l = null, U = {}) {
3847
- l instanceof tl ? (this.audioEngine = l.audioEngine, this.midiPlayer = l, this.parsedData = l.parsedData, this._audioEngineReady = !!(this.audioEngine && this.audioEngine.isInitialized)) : (this.audioEngine = l, this._audioEngineReady = !!(l && l.isInitialized), this.midiPlayer = null, this.parsedData = null), this.eventBus = Jl(), this._parser = new Pl(), this._musicXmlConverter = new GU(), this._partOutputsMap = /* @__PURE__ */ new Map(), this.instrumentMap = null, this.metronomeConfig = {
3843
+ l instanceof tl ? (this.audioEngine = l.audioEngine, this.midiPlayer = l, this.parsedData = l.parsedData, this._audioEngineReady = !!(this.audioEngine && this.audioEngine.isInitialized)) : (this.audioEngine = l, this._audioEngineReady = !!(l && l.isInitialized), this.midiPlayer = null, this.parsedData = null), this.eventBus = sl(), this._parser = new Pl(), this._musicXmlConverter = new GU(), this._partOutputsMap = /* @__PURE__ */ new Map(), this.instrumentMap = null, this.metronomeConfig = {
3848
3844
  enabled: !1,
3849
3845
  tickInstrument: 115,
3850
3846
  // woodblock
@@ -4007,8 +4003,8 @@ class jU {
4007
4003
  */
4008
4004
  stop() {
4009
4005
  if (this.state === "stopped") return;
4010
- const l = this.state === "playing";
4011
- this.state = "stopped", this.frozenTime = 0, this.leadInData = null, this.leadInProgress = null, this.leadInStartTime = null, this._stopLeadIn(), this._stopMetronome(), this._stopTimeUpdateLoop(), this._resetMetronomeBeatTracking(), l && this.midiPlayer.stop(), this._emitEvent("playbackStopped", {});
4006
+ const l = this.state;
4007
+ l === "lead-in" ? this._pauseLeadIn() : l === "playing" && (this.midiPlayer.pause(), this._stopMetronome()), this._stopLeadIn(), this._stopTimeUpdateLoop(), this.frozenTime = 0, this.leadInData = null, this.leadInProgress = null, this.leadInStartTime = null, this.midiPlayer && this.midiPlayer.skipToTime(0), this._resetMetronomeBeatTracking(), this.state = "stopped", this._emitEvent("playbackStopped", {});
4012
4008
  }
4013
4009
  // ========================================
4014
4010
  // PUBLIC API - Positioning Methods
@@ -4998,19 +4994,19 @@ class jU {
4998
4994
  return;
4999
4995
  }
5000
4996
  l.getFloatTimeDomainData(W);
5001
- let a = 0, J = 0;
4997
+ let a = 0, s = 0;
5002
4998
  for (let i = 0; i < R; i++) {
5003
4999
  const S = Math.abs(W[i]);
5004
- a += W[i] * W[i], S > J && (J = S);
5000
+ a += W[i] * W[i], S > s && (s = S);
5005
5001
  }
5006
- const s = Math.sqrt(a / R);
5007
- if (s >= Z) {
5002
+ const J = Math.sqrt(a / R);
5003
+ if (J >= Z) {
5008
5004
  clearInterval(c);
5009
5005
  const i = Q.currentTime, S = (i - U) * 1e3;
5010
5006
  t({
5011
5007
  latencyMs: S,
5012
- rms: s,
5013
- peak: J,
5008
+ rms: J,
5009
+ peak: s,
5014
5010
  detectedTime: i
5015
5011
  });
5016
5012
  }
@@ -5035,18 +5031,18 @@ class jU {
5035
5031
  return;
5036
5032
  }
5037
5033
  l.getFloatTimeDomainData(R);
5038
- let a = 0, J = 0;
5034
+ let a = 0, s = 0;
5039
5035
  for (let S = 0; S < Q; S++) {
5040
5036
  const Y = Math.abs(R[S]);
5041
- a += R[S] * R[S], Y > J && (J = Y);
5037
+ a += R[S] * R[S], Y > s && (s = Y);
5042
5038
  }
5043
- const s = Math.sqrt(a / Q), i = d.currentTime;
5039
+ const J = Math.sqrt(a / Q), i = d.currentTime;
5044
5040
  W.push({
5045
5041
  time: i,
5046
5042
  relativeTime: (i - U) * 1e3,
5047
5043
  // ms relative to scheduled time
5048
- rms: s,
5049
- peak: J
5044
+ rms: J,
5045
+ peak: s
5050
5046
  });
5051
5047
  }, F);
5052
5048
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "audio-mixer-engine",
3
- "version": "1.3.5",
3
+ "version": "1.3.7",
4
4
  "description": "Audio engine library for audio mixer applications with MIDI parsing, playback, and synthesis",
5
5
  "main": "dist/audio-mixer-engine.cjs.js",
6
6
  "module": "dist/audio-mixer-engine.es.js",
@@ -138,21 +138,15 @@ export default class LightweightChannelHandle extends ChannelHandle {
138
138
  // Stop all sources for this pitch
139
139
  sources.forEach(source => {
140
140
  try {
141
- // For looping samples, stop immediately
142
- // For non-looping samples, they'll stop naturally
143
- if (source.loop) {
144
- source.stop();
145
- } else {
146
- // Piano notes decay naturally - but we can stop them early if needed
147
- // Apply a quick fade-out for better sound quality
148
- const now = this.engine.audioContext.currentTime;
149
- // Get the velocity gain node (it's connected between source and output)
150
- const velocityGain = source._velocityGain;
151
- if (velocityGain) {
152
- velocityGain.gain.linearRampToValueAtTime(0, now + 0.05); // 50ms fade
153
- }
154
- source.stop(now + 0.05);
141
+ const velocityGain = source._velocityGain;
142
+ const now = this.engine.audioContext.currentTime;
143
+ const fadeTime = source.loop ? 0.15 : 0.03; // longer fade for looping (vocal) sources
144
+ if (velocityGain) {
145
+ // Anchor current value before ramping — prevents jump-to-1 artefact
146
+ velocityGain.gain.setValueAtTime(velocityGain.gain.value, now);
147
+ velocityGain.gain.exponentialRampToValueAtTime(0.0001, now + fadeTime);
155
148
  }
149
+ source.stop(now + fadeTime);
156
150
  } catch (e) {
157
151
  // Source may already be stopped
158
152
  }
@@ -446,26 +446,29 @@ export default class PlaybackManager {
446
446
  stop() {
447
447
  if (this.state === 'stopped') return;
448
448
 
449
- const wasPlaying = this.state === 'playing';
450
- this.state = 'stopped';
451
- this.frozenTime = 0;
452
- this.leadInData = null;
453
- this.leadInProgress = null;
454
- this.leadInStartTime = null;
449
+ const previousState = this.state;
455
450
 
456
- // Stop all scheduling
451
+ // Apply the same per-state cleanup as pause()
452
+ if (previousState === 'lead-in') {
453
+ this._pauseLeadIn();
454
+ } else if (previousState === 'playing') {
455
+ this.midiPlayer.pause();
456
+ this._stopMetronome();
457
+ }
457
458
  this._stopLeadIn();
458
- this._stopMetronome();
459
459
  this._stopTimeUpdateLoop();
460
460
 
461
- // Reset metronome tracking
462
- this._resetMetronomeBeatTracking();
463
-
464
- // Stop MIDI player only if it was actually playing
465
- if (wasPlaying) {
466
- this.midiPlayer.stop();
461
+ // Reset to beginning
462
+ this.frozenTime = 0;
463
+ this.leadInData = null;
464
+ this.leadInProgress = null;
465
+ this.leadInStartTime = null;
466
+ if (this.midiPlayer) {
467
+ this.midiPlayer.skipToTime(0);
467
468
  }
469
+ this._resetMetronomeBeatTracking();
468
470
 
471
+ this.state = 'stopped';
469
472
  this._emitEvent('playbackStopped', {});
470
473
  }
471
474