@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.d.mts +10 -5
- package/dist/index.d.ts +10 -5
- package/dist/index.js +44 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +44 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -8
package/dist/index.d.mts
CHANGED
|
@@ -142,6 +142,10 @@ declare class TempoMap {
|
|
|
142
142
|
private _ppqn;
|
|
143
143
|
private _entries;
|
|
144
144
|
constructor(ppqn?: number, initialBpm?: number);
|
|
145
|
+
/** A non-finite or non-positive BPM silently corrupts the secondsAtTick
|
|
146
|
+
* cache (Infinity, or non-monotonic values that break the binary search
|
|
147
|
+
* in secondsToTicks) — reject it at the boundary instead. */
|
|
148
|
+
private static _validateBpm;
|
|
145
149
|
getTempo(atTick?: Tick): number;
|
|
146
150
|
setTempo(bpm: number, atTick?: Tick, options?: SetTempoOptions): void;
|
|
147
151
|
ticksToSeconds(ticks: Tick): number;
|
|
@@ -299,17 +303,18 @@ interface ClipEvent extends SchedulerEvent {
|
|
|
299
303
|
trackId: string;
|
|
300
304
|
clipId: string;
|
|
301
305
|
audioBuffer: AudioBuffer;
|
|
302
|
-
/** Clip position on timeline (integer samples) */
|
|
306
|
+
/** Clip position on timeline (integer samples, at the TIMELINE sample rate) */
|
|
303
307
|
startSample: Sample;
|
|
304
|
-
/** Offset into audioBuffer (integer samples
|
|
308
|
+
/** Offset into audioBuffer (integer samples, at the BUFFER's own sample
|
|
309
|
+
* rate — they index the buffer, not the timeline) */
|
|
305
310
|
offsetSamples: Sample;
|
|
306
|
-
/** Duration to play (integer samples) */
|
|
311
|
+
/** Duration to play (integer samples, at the BUFFER's own sample rate) */
|
|
307
312
|
durationSamples: Sample;
|
|
308
313
|
/** Clip gain multiplier */
|
|
309
314
|
gain: number;
|
|
310
|
-
/** Fade in duration (integer samples) */
|
|
315
|
+
/** Fade in duration (integer samples, at the TIMELINE sample rate) */
|
|
311
316
|
fadeInDurationSamples: Sample;
|
|
312
|
-
/** Fade out duration (integer samples) */
|
|
317
|
+
/** Fade out duration (integer samples, at the TIMELINE sample rate) */
|
|
313
318
|
fadeOutDurationSamples: Sample;
|
|
314
319
|
}
|
|
315
320
|
declare class ClipPlayer implements SchedulerListener<ClipEvent> {
|
package/dist/index.d.ts
CHANGED
|
@@ -142,6 +142,10 @@ declare class TempoMap {
|
|
|
142
142
|
private _ppqn;
|
|
143
143
|
private _entries;
|
|
144
144
|
constructor(ppqn?: number, initialBpm?: number);
|
|
145
|
+
/** A non-finite or non-positive BPM silently corrupts the secondsAtTick
|
|
146
|
+
* cache (Infinity, or non-monotonic values that break the binary search
|
|
147
|
+
* in secondsToTicks) — reject it at the boundary instead. */
|
|
148
|
+
private static _validateBpm;
|
|
145
149
|
getTempo(atTick?: Tick): number;
|
|
146
150
|
setTempo(bpm: number, atTick?: Tick, options?: SetTempoOptions): void;
|
|
147
151
|
ticksToSeconds(ticks: Tick): number;
|
|
@@ -299,17 +303,18 @@ interface ClipEvent extends SchedulerEvent {
|
|
|
299
303
|
trackId: string;
|
|
300
304
|
clipId: string;
|
|
301
305
|
audioBuffer: AudioBuffer;
|
|
302
|
-
/** Clip position on timeline (integer samples) */
|
|
306
|
+
/** Clip position on timeline (integer samples, at the TIMELINE sample rate) */
|
|
303
307
|
startSample: Sample;
|
|
304
|
-
/** Offset into audioBuffer (integer samples
|
|
308
|
+
/** Offset into audioBuffer (integer samples, at the BUFFER's own sample
|
|
309
|
+
* rate — they index the buffer, not the timeline) */
|
|
305
310
|
offsetSamples: Sample;
|
|
306
|
-
/** Duration to play (integer samples) */
|
|
311
|
+
/** Duration to play (integer samples, at the BUFFER's own sample rate) */
|
|
307
312
|
durationSamples: Sample;
|
|
308
313
|
/** Clip gain multiplier */
|
|
309
314
|
gain: number;
|
|
310
|
-
/** Fade in duration (integer samples) */
|
|
315
|
+
/** Fade in duration (integer samples, at the TIMELINE sample rate) */
|
|
311
316
|
fadeInDurationSamples: Sample;
|
|
312
|
-
/** Fade out duration (integer samples) */
|
|
317
|
+
/** Fade out duration (integer samples, at the TIMELINE sample rate) */
|
|
313
318
|
fadeOutDurationSamples: Sample;
|
|
314
319
|
}
|
|
315
320
|
declare class ClipPlayer implements SchedulerListener<ClipEvent> {
|
package/dist/index.js
CHANGED
|
@@ -261,15 +261,27 @@ function curveNormalizedAt(x, slope) {
|
|
|
261
261
|
const p = Math.max(CURVE_EPSILON, Math.min(1 - CURVE_EPSILON, slope));
|
|
262
262
|
return p * p / (1 - p * 2) * (Math.pow((1 - p) / p, 2 * x) - 1);
|
|
263
263
|
}
|
|
264
|
-
var TempoMap = class {
|
|
264
|
+
var TempoMap = class _TempoMap {
|
|
265
265
|
constructor(ppqn = 960, initialBpm = 120) {
|
|
266
|
+
_TempoMap._validateBpm(initialBpm);
|
|
266
267
|
this._ppqn = ppqn;
|
|
267
268
|
this._entries = [{ tick: 0, bpm: initialBpm, interpolation: "step", secondsAtTick: 0 }];
|
|
268
269
|
}
|
|
270
|
+
/** A non-finite or non-positive BPM silently corrupts the secondsAtTick
|
|
271
|
+
* cache (Infinity, or non-monotonic values that break the binary search
|
|
272
|
+
* in secondsToTicks) — reject it at the boundary instead. */
|
|
273
|
+
static _validateBpm(bpm) {
|
|
274
|
+
if (!Number.isFinite(bpm) || bpm <= 0) {
|
|
275
|
+
throw new Error(
|
|
276
|
+
"[waveform-playlist] TempoMap: bpm must be a finite positive number, got " + bpm
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
269
280
|
getTempo(atTick = 0) {
|
|
270
281
|
return this._getTempoAt(atTick);
|
|
271
282
|
}
|
|
272
283
|
setTempo(bpm, atTick = 0, options) {
|
|
284
|
+
_TempoMap._validateBpm(bpm);
|
|
273
285
|
const interpolation = options?.interpolation ?? "step";
|
|
274
286
|
if (typeof interpolation === "object" && interpolation.type === "curve") {
|
|
275
287
|
const s = interpolation.slope;
|
|
@@ -507,6 +519,7 @@ function isPowerOf2(n) {
|
|
|
507
519
|
var MeterMap = class {
|
|
508
520
|
constructor(ppqn, numerator = 4, denominator = 4) {
|
|
509
521
|
this._ppqn = ppqn;
|
|
522
|
+
this._validateMeter(numerator, denominator);
|
|
510
523
|
this._entries = [{ tick: 0, numerator, denominator, barAtTick: 0 }];
|
|
511
524
|
}
|
|
512
525
|
get ppqn() {
|
|
@@ -800,11 +813,19 @@ var ClipPlayer = class {
|
|
|
800
813
|
const clipTick = clip.startTick !== void 0 ? clip.startTick : this._sampleTimeline.samplesToTicks(clip.startSample);
|
|
801
814
|
if (clipTick < fromTick) continue;
|
|
802
815
|
if (clipTick >= toTick) continue;
|
|
803
|
-
const
|
|
804
|
-
const
|
|
816
|
+
const timelineRate = this._sampleTimeline.sampleRate;
|
|
817
|
+
const bufferRate = clip.audioBuffer.sampleRate;
|
|
818
|
+
const fadeInDurationSamples = clip.fadeIn ? Math.round((clip.fadeIn.duration ?? 0) * timelineRate) : 0;
|
|
819
|
+
const fadeOutDurationSamples = clip.fadeOut ? Math.round((clip.fadeOut.duration ?? 0) * timelineRate) : 0;
|
|
805
820
|
let durationSamples = clip.durationSamples;
|
|
806
|
-
if (this._loopEnabled
|
|
807
|
-
|
|
821
|
+
if (this._loopEnabled) {
|
|
822
|
+
const durationTimelineSamples = Math.round(
|
|
823
|
+
clip.durationSamples / bufferRate * timelineRate
|
|
824
|
+
);
|
|
825
|
+
const allowedTimelineSamples = this._loopEndSamples - clip.startSample;
|
|
826
|
+
if (durationTimelineSamples > allowedTimelineSamples) {
|
|
827
|
+
durationSamples = Math.round(allowedTimelineSamples / timelineRate * bufferRate);
|
|
828
|
+
}
|
|
808
829
|
}
|
|
809
830
|
events.push({
|
|
810
831
|
trackId,
|
|
@@ -830,9 +851,9 @@ var ClipPlayer = class {
|
|
|
830
851
|
);
|
|
831
852
|
return;
|
|
832
853
|
}
|
|
833
|
-
const
|
|
834
|
-
const offsetSeconds = event.offsetSamples /
|
|
835
|
-
const durationSeconds = event.durationSamples /
|
|
854
|
+
const bufferRate = event.audioBuffer.sampleRate;
|
|
855
|
+
const offsetSeconds = event.offsetSamples / bufferRate;
|
|
856
|
+
const durationSeconds = event.durationSamples / bufferRate;
|
|
836
857
|
if (offsetSeconds >= event.audioBuffer.duration) {
|
|
837
858
|
console.warn(
|
|
838
859
|
"[waveform-playlist] ClipPlayer.consume: offset (" + offsetSeconds + "s) exceeds audioBuffer.duration (" + event.audioBuffer.duration + 's) for clipId "' + event.clipId + '" \u2014 clip will not play'
|
|
@@ -845,8 +866,9 @@ var ClipPlayer = class {
|
|
|
845
866
|
const when = this._toAudioTime(transportSeconds);
|
|
846
867
|
const gainNode = this._audioContext.createGain();
|
|
847
868
|
gainNode.gain.value = event.gain;
|
|
848
|
-
|
|
849
|
-
let
|
|
869
|
+
const timelineRate = this._sampleTimeline.sampleRate;
|
|
870
|
+
let fadeIn = event.fadeInDurationSamples / timelineRate;
|
|
871
|
+
let fadeOut = event.fadeOutDurationSamples / timelineRate;
|
|
850
872
|
if (fadeIn + fadeOut > durationSeconds) {
|
|
851
873
|
const ratio = durationSeconds / (fadeIn + fadeOut);
|
|
852
874
|
fadeIn *= ratio;
|
|
@@ -886,16 +908,21 @@ var ClipPlayer = class {
|
|
|
886
908
|
if (!clip.audioBuffer) continue;
|
|
887
909
|
const clipTick = clip.startTick !== void 0 ? clip.startTick : this._sampleTimeline.samplesToTicks(clip.startSample);
|
|
888
910
|
if (clipTick >= newTick) continue;
|
|
889
|
-
const
|
|
911
|
+
const timelineRate = this._sampleTimeline.sampleRate;
|
|
912
|
+
const bufferRate = clip.audioBuffer.sampleRate;
|
|
913
|
+
const bufToTimeline = (n) => Math.round(n / bufferRate * timelineRate);
|
|
914
|
+
const timelineToBuf = (n) => Math.round(n / timelineRate * bufferRate);
|
|
915
|
+
const clipEndSample = clip.startSample + bufToTimeline(clip.durationSamples);
|
|
890
916
|
if (clipEndSample <= newSample) continue;
|
|
891
917
|
const offsetIntoClipSamples = newSample - clip.startSample;
|
|
892
|
-
const offsetSamples = clip.offsetSamples + offsetIntoClipSamples;
|
|
893
|
-
let
|
|
894
|
-
if (this._loopEnabled && newSample +
|
|
895
|
-
|
|
918
|
+
const offsetSamples = clip.offsetSamples + timelineToBuf(offsetIntoClipSamples);
|
|
919
|
+
let remainingTimelineSamples = clipEndSample - newSample;
|
|
920
|
+
if (this._loopEnabled && newSample + remainingTimelineSamples > this._loopEndSamples) {
|
|
921
|
+
remainingTimelineSamples = this._loopEndSamples - newSample;
|
|
896
922
|
}
|
|
897
|
-
if (
|
|
898
|
-
const
|
|
923
|
+
if (remainingTimelineSamples <= 0) continue;
|
|
924
|
+
const durationSamples = timelineToBuf(remainingTimelineSamples);
|
|
925
|
+
const fadeOutDurationSamples = clip.fadeOut ? Math.round((clip.fadeOut.duration ?? 0) * timelineRate) : 0;
|
|
899
926
|
this.consume({
|
|
900
927
|
trackId,
|
|
901
928
|
clipId: clip.id,
|