@dawcore/transport 0.0.9 → 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.d.mts +14 -5
- package/dist/index.d.ts +14 -5
- package/dist/index.js +53 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +53 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -8
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() {
|
|
@@ -654,7 +667,7 @@ var MasterNode = class {
|
|
|
654
667
|
try {
|
|
655
668
|
this._gainNode.disconnect();
|
|
656
669
|
} catch (err) {
|
|
657
|
-
console.warn("[waveform-playlist] MasterNode.dispose: error disconnecting:"
|
|
670
|
+
console.warn("[waveform-playlist] MasterNode.dispose: error disconnecting: " + String(err));
|
|
658
671
|
}
|
|
659
672
|
}
|
|
660
673
|
};
|
|
@@ -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
|
|
767
|
-
const
|
|
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
|
|
770
|
-
|
|
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
|
|
797
|
-
const offsetSeconds = event.offsetSamples /
|
|
798
|
-
const durationSeconds = event.durationSamples /
|
|
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
|
-
|
|
812
|
-
let
|
|
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
|
|
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
|
|
857
|
-
if (this._loopEnabled && newSample +
|
|
858
|
-
|
|
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 (
|
|
861
|
-
const
|
|
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,
|
|
@@ -1575,6 +1602,11 @@ var _Transport = class _Transport {
|
|
|
1575
1602
|
}
|
|
1576
1603
|
trackNode.disconnectEffects();
|
|
1577
1604
|
}
|
|
1605
|
+
/** The master output AudioNode. Connect your own nodes (analyzers, recorders, etc.)
|
|
1606
|
+
* in parallel. The transport already routes this to audioContext.destination. */
|
|
1607
|
+
get masterOutputNode() {
|
|
1608
|
+
return this._masterNode.output;
|
|
1609
|
+
}
|
|
1578
1610
|
// --- Events ---
|
|
1579
1611
|
on(event, cb) {
|
|
1580
1612
|
if (!this._listeners.has(event)) {
|
|
@@ -1887,6 +1919,9 @@ var NativePlayoutAdapter = class {
|
|
|
1887
1919
|
secondsToTicks(seconds) {
|
|
1888
1920
|
return this._transport.timeToTick(seconds);
|
|
1889
1921
|
}
|
|
1922
|
+
get masterOutputNode() {
|
|
1923
|
+
return this._transport.masterOutputNode;
|
|
1924
|
+
}
|
|
1890
1925
|
dispose() {
|
|
1891
1926
|
this._transport.dispose();
|
|
1892
1927
|
}
|