@dawcore/transport 0.0.10 → 0.0.11

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.mjs CHANGED
@@ -224,15 +224,27 @@ function curveNormalizedAt(x, slope) {
224
224
  const p = Math.max(CURVE_EPSILON, Math.min(1 - CURVE_EPSILON, slope));
225
225
  return p * p / (1 - p * 2) * (Math.pow((1 - p) / p, 2 * x) - 1);
226
226
  }
227
- var TempoMap = class {
227
+ var TempoMap = class _TempoMap {
228
228
  constructor(ppqn = 960, initialBpm = 120) {
229
+ _TempoMap._validateBpm(initialBpm);
229
230
  this._ppqn = ppqn;
230
231
  this._entries = [{ tick: 0, bpm: initialBpm, interpolation: "step", secondsAtTick: 0 }];
231
232
  }
233
+ /** A non-finite or non-positive BPM silently corrupts the secondsAtTick
234
+ * cache (Infinity, or non-monotonic values that break the binary search
235
+ * in secondsToTicks) — reject it at the boundary instead. */
236
+ static _validateBpm(bpm) {
237
+ if (!Number.isFinite(bpm) || bpm <= 0) {
238
+ throw new Error(
239
+ "[waveform-playlist] TempoMap: bpm must be a finite positive number, got " + bpm
240
+ );
241
+ }
242
+ }
232
243
  getTempo(atTick = 0) {
233
244
  return this._getTempoAt(atTick);
234
245
  }
235
246
  setTempo(bpm, atTick = 0, options) {
247
+ _TempoMap._validateBpm(bpm);
236
248
  const interpolation = options?.interpolation ?? "step";
237
249
  if (typeof interpolation === "object" && interpolation.type === "curve") {
238
250
  const s = interpolation.slope;
@@ -470,6 +482,7 @@ function isPowerOf2(n) {
470
482
  var MeterMap = class {
471
483
  constructor(ppqn, numerator = 4, denominator = 4) {
472
484
  this._ppqn = ppqn;
485
+ this._validateMeter(numerator, denominator);
473
486
  this._entries = [{ tick: 0, numerator, denominator, barAtTick: 0 }];
474
487
  }
475
488
  get ppqn() {
@@ -763,11 +776,19 @@ var ClipPlayer = class {
763
776
  const clipTick = clip.startTick !== void 0 ? clip.startTick : this._sampleTimeline.samplesToTicks(clip.startSample);
764
777
  if (clipTick < fromTick) continue;
765
778
  if (clipTick >= toTick) continue;
766
- const fadeInDurationSamples = clip.fadeIn ? clip.fadeIn.duration ?? 0 : 0;
767
- const fadeOutDurationSamples = clip.fadeOut ? clip.fadeOut.duration ?? 0 : 0;
779
+ const timelineRate = this._sampleTimeline.sampleRate;
780
+ const bufferRate = clip.audioBuffer.sampleRate;
781
+ const fadeInDurationSamples = clip.fadeIn ? Math.round((clip.fadeIn.duration ?? 0) * timelineRate) : 0;
782
+ const fadeOutDurationSamples = clip.fadeOut ? Math.round((clip.fadeOut.duration ?? 0) * timelineRate) : 0;
768
783
  let durationSamples = clip.durationSamples;
769
- if (this._loopEnabled && clip.startSample + durationSamples > this._loopEndSamples) {
770
- durationSamples = this._loopEndSamples - clip.startSample;
784
+ if (this._loopEnabled) {
785
+ const durationTimelineSamples = Math.round(
786
+ clip.durationSamples / bufferRate * timelineRate
787
+ );
788
+ const allowedTimelineSamples = this._loopEndSamples - clip.startSample;
789
+ if (durationTimelineSamples > allowedTimelineSamples) {
790
+ durationSamples = Math.round(allowedTimelineSamples / timelineRate * bufferRate);
791
+ }
771
792
  }
772
793
  events.push({
773
794
  trackId,
@@ -793,9 +814,9 @@ var ClipPlayer = class {
793
814
  );
794
815
  return;
795
816
  }
796
- const sampleRate = this._sampleTimeline.sampleRate;
797
- const offsetSeconds = event.offsetSamples / sampleRate;
798
- const durationSeconds = event.durationSamples / sampleRate;
817
+ const bufferRate = event.audioBuffer.sampleRate;
818
+ const offsetSeconds = event.offsetSamples / bufferRate;
819
+ const durationSeconds = event.durationSamples / bufferRate;
799
820
  if (offsetSeconds >= event.audioBuffer.duration) {
800
821
  console.warn(
801
822
  "[waveform-playlist] ClipPlayer.consume: offset (" + offsetSeconds + "s) exceeds audioBuffer.duration (" + event.audioBuffer.duration + 's) for clipId "' + event.clipId + '" \u2014 clip will not play'
@@ -808,8 +829,9 @@ var ClipPlayer = class {
808
829
  const when = this._toAudioTime(transportSeconds);
809
830
  const gainNode = this._audioContext.createGain();
810
831
  gainNode.gain.value = event.gain;
811
- let fadeIn = event.fadeInDurationSamples / sampleRate;
812
- let fadeOut = event.fadeOutDurationSamples / sampleRate;
832
+ const timelineRate = this._sampleTimeline.sampleRate;
833
+ let fadeIn = event.fadeInDurationSamples / timelineRate;
834
+ let fadeOut = event.fadeOutDurationSamples / timelineRate;
813
835
  if (fadeIn + fadeOut > durationSeconds) {
814
836
  const ratio = durationSeconds / (fadeIn + fadeOut);
815
837
  fadeIn *= ratio;
@@ -849,16 +871,21 @@ var ClipPlayer = class {
849
871
  if (!clip.audioBuffer) continue;
850
872
  const clipTick = clip.startTick !== void 0 ? clip.startTick : this._sampleTimeline.samplesToTicks(clip.startSample);
851
873
  if (clipTick >= newTick) continue;
852
- const clipEndSample = clip.startSample + clip.durationSamples;
874
+ const timelineRate = this._sampleTimeline.sampleRate;
875
+ const bufferRate = clip.audioBuffer.sampleRate;
876
+ const bufToTimeline = (n) => Math.round(n / bufferRate * timelineRate);
877
+ const timelineToBuf = (n) => Math.round(n / timelineRate * bufferRate);
878
+ const clipEndSample = clip.startSample + bufToTimeline(clip.durationSamples);
853
879
  if (clipEndSample <= newSample) continue;
854
880
  const offsetIntoClipSamples = newSample - clip.startSample;
855
- const offsetSamples = clip.offsetSamples + offsetIntoClipSamples;
856
- let durationSamples = clipEndSample - newSample;
857
- if (this._loopEnabled && newSample + durationSamples > this._loopEndSamples) {
858
- durationSamples = this._loopEndSamples - newSample;
881
+ const offsetSamples = clip.offsetSamples + timelineToBuf(offsetIntoClipSamples);
882
+ let remainingTimelineSamples = clipEndSample - newSample;
883
+ if (this._loopEnabled && newSample + remainingTimelineSamples > this._loopEndSamples) {
884
+ remainingTimelineSamples = this._loopEndSamples - newSample;
859
885
  }
860
- if (durationSamples <= 0) continue;
861
- const fadeOutDurationSamples = clip.fadeOut ? clip.fadeOut.duration ?? 0 : 0;
886
+ if (remainingTimelineSamples <= 0) continue;
887
+ const durationSamples = timelineToBuf(remainingTimelineSamples);
888
+ const fadeOutDurationSamples = clip.fadeOut ? Math.round((clip.fadeOut.duration ?? 0) * timelineRate) : 0;
862
889
  this.consume({
863
890
  trackId,
864
891
  clipId: clip.id,