@waveform-playlist/core 11.3.1 → 12.0.0

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.js CHANGED
@@ -24,8 +24,11 @@ __export(index_exports, {
24
24
  MAX_CANVAS_WIDTH: () => MAX_CANVAS_WIDTH,
25
25
  MIN_PIXELS_PER_UNIT: () => MIN_PIXELS_PER_UNIT,
26
26
  PPQN: () => PPQN,
27
+ appendPeaks: () => appendPeaks,
28
+ appendToAudioBuffer: () => appendToAudioBuffer,
27
29
  applyFadeIn: () => applyFadeIn,
28
30
  applyFadeOut: () => applyFadeOut,
31
+ calculateDuration: () => calculateDuration,
29
32
  clipDurationTime: () => clipDurationTime,
30
33
  clipEndTime: () => clipEndTime,
31
34
  clipOffsetTime: () => clipOffsetTime,
@@ -33,16 +36,21 @@ __export(index_exports, {
33
36
  clipStartTime: () => clipStartTime,
34
37
  clipsOverlap: () => clipsOverlap,
35
38
  computeMusicalTicks: () => computeMusicalTicks,
39
+ concatenateAudioData: () => concatenateAudioData,
40
+ createAudioBuffer: () => createAudioBuffer,
36
41
  createClip: () => createClip,
37
42
  createClipFromSeconds: () => createClipFromSeconds,
43
+ createClipFromTicks: () => createClipFromTicks,
38
44
  createTimeline: () => createTimeline,
39
45
  createTrack: () => createTrack,
40
46
  dBToNormalized: () => dBToNormalized,
47
+ detectMeterChanges: () => detectMeterChanges,
41
48
  exponentialCurve: () => exponentialCurve,
42
49
  findGaps: () => findGaps,
43
50
  gainToDb: () => gainToDb,
44
51
  gainToNormalized: () => gainToNormalized,
45
52
  generateCurve: () => generateCurve,
53
+ generatePeaks: () => generatePeaks,
46
54
  getClipsAtSample: () => getClipsAtSample,
47
55
  getClipsInRange: () => getClipsInRange,
48
56
  getShortcutLabel: () => getShortcutLabel,
@@ -64,7 +72,6 @@ __export(index_exports, {
64
72
  sortClipsByTime: () => sortClipsByTime,
65
73
  ticksPerBar: () => ticksPerBar,
66
74
  ticksPerBeat: () => ticksPerBeat,
67
- ticksToBarBeatLabel: () => ticksToBarBeatLabel,
68
75
  ticksToSamples: () => ticksToSamples,
69
76
  trackChannelCount: () => trackChannelCount
70
77
  });
@@ -74,10 +81,50 @@ module.exports = __toCommonJS(index_exports);
74
81
  var MAX_CANVAS_WIDTH = 1e3;
75
82
 
76
83
  // src/types/clip.ts
84
+ function createClipFromTicks(options) {
85
+ const { startTick, ticksToSeconds, bpm, ppqn } = options;
86
+ if (startTick < 0) {
87
+ throw new Error("createClipFromTicks: startTick must be non-negative");
88
+ }
89
+ let toSeconds;
90
+ if (ticksToSeconds) {
91
+ toSeconds = ticksToSeconds;
92
+ } else if (bpm !== void 0 && ppqn !== void 0) {
93
+ toSeconds = (tick) => tick * 60 / (ppqn * bpm);
94
+ } else {
95
+ throw new Error(
96
+ "createClipFromTicks: either ticksToSeconds callback or both bpm and ppqn are required"
97
+ );
98
+ }
99
+ const sampleRate = options.audioBuffer?.sampleRate ?? options.sampleRate ?? options.waveformData?.sample_rate;
100
+ if (sampleRate === void 0) {
101
+ throw new Error("createClipFromTicks: sampleRate is required when audioBuffer is not provided");
102
+ }
103
+ const startSample = Math.round(toSeconds(startTick) * sampleRate);
104
+ return createClip({
105
+ audioBuffer: options.audioBuffer,
106
+ startSample,
107
+ startTick,
108
+ durationSamples: options.durationSamples,
109
+ offsetSamples: options.offsetSamples,
110
+ gain: options.gain,
111
+ name: options.name,
112
+ color: options.color,
113
+ fadeIn: options.fadeIn,
114
+ fadeOut: options.fadeOut,
115
+ waveformData: options.waveformData,
116
+ sampleRate: options.sampleRate,
117
+ sourceDurationSamples: options.sourceDurationSamples,
118
+ midiNotes: options.midiNotes,
119
+ midiChannel: options.midiChannel,
120
+ midiProgram: options.midiProgram
121
+ });
122
+ }
77
123
  function createClip(options) {
78
124
  const {
79
125
  audioBuffer,
80
126
  startSample,
127
+ startTick,
81
128
  offsetSamples = 0,
82
129
  gain = 1,
83
130
  name,
@@ -111,6 +158,7 @@ function createClip(options) {
111
158
  id: generateId(),
112
159
  audioBuffer,
113
160
  startSample,
161
+ startTick,
114
162
  durationSamples,
115
163
  offsetSamples,
116
164
  sampleRate,
@@ -157,6 +205,7 @@ function createClipFromSeconds(options) {
157
205
  return createClip({
158
206
  audioBuffer,
159
207
  startSample: Math.round(startTime * sampleRate),
208
+ startTick: options.startTick,
160
209
  durationSamples: Math.round(duration * sampleRate),
161
210
  offsetSamples: Math.round(offset * sampleRate),
162
211
  sampleRate,
@@ -306,14 +355,6 @@ function samplesToTicks(samples, bpm, sampleRate, ppqn = PPQN) {
306
355
  function snapToGrid(ticks, gridSizeTicks) {
307
356
  return Math.round(ticks / gridSizeTicks) * gridSizeTicks;
308
357
  }
309
- function ticksToBarBeatLabel(ticks, timeSignature, ppqn = PPQN) {
310
- const barTicks = ticksPerBar(timeSignature, ppqn);
311
- const beatTicks = ticksPerBeat(timeSignature, ppqn);
312
- const bar = Math.floor(ticks / barTicks) + 1;
313
- const beatInBar = Math.floor(ticks % barTicks / beatTicks) + 1;
314
- if (beatInBar === 1) return `${bar}`;
315
- return `${bar}.${beatInBar}`;
316
- }
317
358
 
318
359
  // src/utils/dBUtils.ts
319
360
  var DEFAULT_FLOOR = -100;
@@ -349,11 +390,12 @@ function gainToNormalized(gain, floor = DEFAULT_FLOOR) {
349
390
 
350
391
  // src/utils/musicalTicks.ts
351
392
  function snapToTicks(snapTo, timeSignature, ppqn = 960) {
393
+ const ts = timeSignature;
352
394
  switch (snapTo) {
353
395
  case "bar":
354
- return ticksPerBar(timeSignature, ppqn);
396
+ return ticksPerBar(ts, ppqn);
355
397
  case "beat":
356
- return ticksPerBeat(timeSignature, ppqn);
398
+ return ticksPerBeat(ts, ppqn);
357
399
  case "1/2":
358
400
  return ppqn * 2;
359
401
  case "1/4":
@@ -379,22 +421,20 @@ function snapToTicks(snapTo, timeSignature, ppqn = 960) {
379
421
  var MIN_PIXELS_PER_UNIT = 8;
380
422
  var MIN_PIXELS_PER_LABEL = 60;
381
423
  function computeMusicalTicks(params) {
382
- const { timeSignature, ticksPerPixel, startPixel, endPixel, ppqn = 960 } = params;
383
- if (ticksPerPixel <= 0 || ppqn <= 0 || timeSignature[1] <= 0) {
384
- return { ticks: [], pixelsPerBar: 0, pixelsPerBeat: 0, zoomLevel: "coarse" };
424
+ const { meterEntries, ticksPerPixel, startPixel, endPixel, ppqn = 960 } = params;
425
+ const firstMeter = meterEntries[0] ?? { tick: 0, numerator: 4, denominator: 4 };
426
+ if (ticksPerPixel <= 0 || ppqn <= 0 || firstMeter.denominator <= 0) {
427
+ return { ticks: [], pixelsPerQuarterNote: 0, zoomLevel: "coarse" };
385
428
  }
386
- const tpBeat = ticksPerBeat(timeSignature, ppqn);
387
- const tpBar = ticksPerBar(timeSignature, ppqn);
429
+ const pixelsPerQuarterNote = ppqn / ticksPerPixel;
388
430
  const tpEighth = ppqn / 2;
389
431
  const tpSixteenth = ppqn / 4;
390
- const pixelsPerBar = tpBar / ticksPerPixel;
391
- const pixelsPerBeat = tpBeat / ticksPerPixel;
392
432
  const pixelsPerEighth = tpEighth / ticksPerPixel;
393
433
  const pixelsPerSixteenth = tpSixteenth / ticksPerPixel;
394
434
  let zoomLevel;
395
- if (pixelsPerBar < MIN_PIXELS_PER_UNIT) {
435
+ if (pixelsPerQuarterNote * 4 < MIN_PIXELS_PER_UNIT) {
396
436
  zoomLevel = "coarse";
397
- } else if (pixelsPerBeat < MIN_PIXELS_PER_UNIT) {
437
+ } else if (pixelsPerQuarterNote < MIN_PIXELS_PER_UNIT) {
398
438
  zoomLevel = "bar";
399
439
  } else if (pixelsPerEighth < MIN_PIXELS_PER_UNIT) {
400
440
  zoomLevel = "beat";
@@ -403,64 +443,247 @@ function computeMusicalTicks(params) {
403
443
  } else {
404
444
  zoomLevel = "sixteenth";
405
445
  }
406
- let stepTicks;
407
- let coarseBarStep;
446
+ let coarseQuarterNoteStep;
447
+ let coarseQuarterNotes = 0;
408
448
  if (zoomLevel === "coarse") {
409
- let multiplier = 2;
410
- while (tpBar * multiplier / ticksPerPixel < MIN_PIXELS_PER_UNIT) {
411
- multiplier *= 2;
449
+ coarseQuarterNotes = 2;
450
+ while (coarseQuarterNotes * ppqn / ticksPerPixel < MIN_PIXELS_PER_UNIT) {
451
+ coarseQuarterNotes *= 2;
412
452
  }
413
- stepTicks = tpBar * multiplier;
414
- coarseBarStep = multiplier;
415
- } else if (zoomLevel === "bar") {
416
- stepTicks = tpBar;
417
- } else if (zoomLevel === "beat") {
418
- stepTicks = tpBeat;
419
- } else if (zoomLevel === "eighth") {
420
- stepTicks = tpEighth;
421
- } else {
422
- stepTicks = tpSixteenth;
453
+ coarseQuarterNoteStep = coarseQuarterNotes;
423
454
  }
424
455
  const startTick = startPixel * ticksPerPixel;
425
456
  const endTick = endPixel * ticksPerPixel;
426
- const firstStep = Math.floor(startTick / stepTicks) * stepTicks;
427
- const ticks = [];
428
- for (let tick = firstStep; tick <= endTick; tick += stepTicks) {
429
- const pixel = tick / ticksPerPixel;
430
- if (pixel < startPixel || pixel > endPixel) {
431
- continue;
457
+ const segments = [];
458
+ {
459
+ let cumulativeBars = 0;
460
+ for (let i = 0; i < meterEntries.length; i++) {
461
+ const meter = meterEntries[i];
462
+ const segmentStart = meter.tick;
463
+ const segmentEnd = i + 1 < meterEntries.length ? meterEntries[i + 1].tick : Number.MAX_SAFE_INTEGER;
464
+ const ts = [meter.numerator, meter.denominator];
465
+ const tpBar = ticksPerBar(ts, ppqn);
466
+ segments.push({
467
+ segmentStartTick: segmentStart,
468
+ segmentEndTick: segmentEnd,
469
+ meter,
470
+ barOffset: cumulativeBars
471
+ });
472
+ if (segmentEnd !== Number.MAX_SAFE_INTEGER) {
473
+ const segmentLen = segmentEnd - segmentStart;
474
+ cumulativeBars += Math.floor(segmentLen / tpBar);
475
+ }
432
476
  }
433
- let type;
434
- if (tick % tpBar === 0) {
435
- type = "major";
436
- } else if (tick % tpBeat === 0) {
437
- type = "minor";
477
+ }
478
+ const ticks = [];
479
+ for (const { segmentStartTick, segmentEndTick, meter, barOffset } of segments) {
480
+ const ts = [meter.numerator, meter.denominator];
481
+ const tpBeat = ticksPerBeat(ts, ppqn);
482
+ const tpBar = ticksPerBar(ts, ppqn);
483
+ let stepTicks;
484
+ if (zoomLevel === "coarse") {
485
+ stepTicks = coarseQuarterNotes * ppqn;
486
+ } else if (zoomLevel === "bar") {
487
+ stepTicks = tpBar;
488
+ } else if (zoomLevel === "beat") {
489
+ stepTicks = tpBeat;
490
+ } else if (zoomLevel === "eighth") {
491
+ stepTicks = tpEighth;
438
492
  } else {
439
- type = "minorMinor";
493
+ stepTicks = tpSixteenth;
494
+ }
495
+ const segmentTickStart = Math.max(segmentStartTick, startTick);
496
+ const segmentTickEnd = Math.min(segmentEndTick - 1, endTick);
497
+ if (segmentTickStart > segmentTickEnd) {
498
+ continue;
440
499
  }
441
- const barIndex = Math.floor(tick / tpBar);
442
- let label;
443
- if (type === "major") {
444
- label = ticksToBarBeatLabel(tick, timeSignature, ppqn);
445
- } else if (type === "minor" && pixelsPerBeat >= MIN_PIXELS_PER_LABEL) {
446
- label = ticksToBarBeatLabel(tick, timeSignature, ppqn);
500
+ const offsetIntoSegment = segmentTickStart - segmentStartTick;
501
+ const firstStepOffset = Math.floor(offsetIntoSegment / stepTicks) * stepTicks;
502
+ const firstStepTick = segmentStartTick + firstStepOffset;
503
+ for (let tick = firstStepTick; tick <= segmentTickEnd && tick < segmentEndTick; tick += stepTicks) {
504
+ const pixel = tick / ticksPerPixel;
505
+ if (pixel < startPixel || pixel > endPixel) {
506
+ continue;
507
+ }
508
+ const tickOffsetInSegment = tick - segmentStartTick;
509
+ let type;
510
+ if (tickOffsetInSegment % tpBar === 0) {
511
+ type = "major";
512
+ } else if (tickOffsetInSegment % tpBeat === 0) {
513
+ type = "minor";
514
+ } else {
515
+ type = "minorMinor";
516
+ }
517
+ const barIndexInSegment = Math.floor(tickOffsetInSegment / tpBar);
518
+ const barIndex = barOffset + barIndexInSegment;
519
+ let label;
520
+ if (type === "major") {
521
+ label = `${barIndex + 1}`;
522
+ } else if (type === "minor" && tpBeat / ticksPerPixel >= MIN_PIXELS_PER_LABEL) {
523
+ const beatInBar = Math.floor(tickOffsetInSegment % tpBar / tpBeat) + 1;
524
+ label = `${barIndex + 1}.${beatInBar}`;
525
+ }
526
+ ticks.push({ pixel, type, barIndex, ...label !== void 0 ? { label } : {} });
447
527
  }
448
- ticks.push({ pixel, type, barIndex, ...label !== void 0 ? { label } : {} });
449
528
  }
529
+ ticks.sort((a, b) => a.pixel - b.pixel);
450
530
  const result = {
451
531
  ticks,
452
- pixelsPerBar,
453
- pixelsPerBeat,
532
+ pixelsPerQuarterNote,
454
533
  zoomLevel,
455
- ...coarseBarStep !== void 0 ? { coarseBarStep } : {}
534
+ ...coarseQuarterNoteStep !== void 0 ? { coarseQuarterNoteStep } : {}
456
535
  };
457
536
  return result;
458
537
  }
459
- function snapTickToGrid(tick, snapTo, timeSignature, ppqn = 960) {
538
+ function snapTickToGrid(tick, snapTo, meterEntries, ppqn = 960) {
460
539
  if (snapTo === "off") return tick;
461
- const gridSize = snapToTicks(snapTo, timeSignature, ppqn);
540
+ let meter = meterEntries[0] ?? { tick: 0, numerator: 4, denominator: 4 };
541
+ for (const entry of meterEntries) {
542
+ if (entry.tick <= tick) {
543
+ meter = entry;
544
+ } else {
545
+ break;
546
+ }
547
+ }
548
+ const ts = [meter.numerator, meter.denominator];
549
+ const gridSize = snapToTicks(snapTo, ts, ppqn);
462
550
  if (gridSize <= 0) return tick;
463
- return Math.round(tick / gridSize) * gridSize;
551
+ const offset = tick - meter.tick;
552
+ return meter.tick + Math.round(offset / gridSize) * gridSize;
553
+ }
554
+
555
+ // src/utils/meterDetection.ts
556
+ function detectMeterChanges(beats, firstBeatTick, ppqn) {
557
+ const DEFAULT_NUMERATOR = 4;
558
+ const DENOMINATOR = 4;
559
+ const defaultResult = [
560
+ { tick: 0, numerator: DEFAULT_NUMERATOR, denominator: DENOMINATOR }
561
+ ];
562
+ if (beats.length === 0) {
563
+ return defaultResult;
564
+ }
565
+ const firstDownbeatIndex = beats.findIndex((b) => b.beat === 1);
566
+ if (firstDownbeatIndex === -1) {
567
+ return defaultResult;
568
+ }
569
+ const bars = [];
570
+ let barStartBeatIndex = firstDownbeatIndex;
571
+ for (let i = firstDownbeatIndex + 1; i < beats.length; i++) {
572
+ if (beats[i].beat === 1) {
573
+ bars.push({ beatIndex: barStartBeatIndex, count: i - barStartBeatIndex });
574
+ barStartBeatIndex = i;
575
+ }
576
+ }
577
+ if (bars.length === 0) {
578
+ return defaultResult;
579
+ }
580
+ const rawEntries = [];
581
+ let prevNumerator = -1;
582
+ for (const bar of bars) {
583
+ const numerator = bar.count;
584
+ if (numerator !== prevNumerator) {
585
+ const tick = firstBeatTick + bar.beatIndex * ppqn;
586
+ rawEntries.push({ tick, numerator, denominator: DENOMINATOR });
587
+ prevNumerator = numerator;
588
+ }
589
+ }
590
+ if (rawEntries.length === 0) {
591
+ return defaultResult;
592
+ }
593
+ if (rawEntries[0].tick === 0) {
594
+ return rawEntries;
595
+ }
596
+ const tick0Entry = {
597
+ tick: 0,
598
+ numerator: rawEntries[0].numerator,
599
+ denominator: DENOMINATOR
600
+ };
601
+ const rest = rawEntries[0].numerator === tick0Entry.numerator ? rawEntries.slice(1) : rawEntries;
602
+ return [tick0Entry, ...rest];
603
+ }
604
+
605
+ // src/utils/peaksGenerator.ts
606
+ function generatePeaks(samples, samplesPerPixel, bits = 16) {
607
+ const numPeaks = Math.ceil(samples.length / samplesPerPixel);
608
+ const peakArray = bits === 8 ? new Int8Array(numPeaks * 2) : new Int16Array(numPeaks * 2);
609
+ const maxValue = 2 ** (bits - 1);
610
+ for (let i = 0; i < numPeaks; i++) {
611
+ const start = i * samplesPerPixel;
612
+ const end = Math.min(start + samplesPerPixel, samples.length);
613
+ let min = 0;
614
+ let max = 0;
615
+ for (let j = start; j < end; j++) {
616
+ const value = samples[j];
617
+ if (value < min) min = value;
618
+ if (value > max) max = value;
619
+ }
620
+ peakArray[i * 2] = Math.max(-maxValue, Math.floor(min * maxValue));
621
+ peakArray[i * 2 + 1] = Math.min(maxValue - 1, Math.floor(max * maxValue));
622
+ }
623
+ return peakArray;
624
+ }
625
+ function appendPeaks(existingPeaks, newSamples, samplesPerPixel, totalSamplesProcessed, bits = 16) {
626
+ const maxValue = 2 ** (bits - 1);
627
+ const remainder = totalSamplesProcessed % samplesPerPixel;
628
+ let offset = 0;
629
+ if (remainder > 0 && existingPeaks.length > 0) {
630
+ const samplesToComplete = samplesPerPixel - remainder;
631
+ const endIndex = Math.min(samplesToComplete, newSamples.length);
632
+ let min = existingPeaks[existingPeaks.length - 2] / maxValue;
633
+ let max = existingPeaks[existingPeaks.length - 1] / maxValue;
634
+ for (let i = 0; i < endIndex; i++) {
635
+ const value = newSamples[i];
636
+ if (value < min) min = value;
637
+ if (value > max) max = value;
638
+ }
639
+ const updated = new (bits === 8 ? Int8Array : Int16Array)(existingPeaks.length);
640
+ updated.set(existingPeaks);
641
+ updated[existingPeaks.length - 2] = Math.max(-maxValue, Math.floor(min * maxValue));
642
+ updated[existingPeaks.length - 1] = Math.min(maxValue - 1, Math.floor(max * maxValue));
643
+ offset = endIndex;
644
+ const newPeaks2 = generatePeaks(newSamples.slice(offset), samplesPerPixel, bits);
645
+ const result2 = new (bits === 8 ? Int8Array : Int16Array)(updated.length + newPeaks2.length);
646
+ result2.set(updated);
647
+ result2.set(newPeaks2, updated.length);
648
+ return result2;
649
+ }
650
+ const newPeaks = generatePeaks(newSamples.slice(offset), samplesPerPixel, bits);
651
+ const result = new (bits === 8 ? Int8Array : Int16Array)(existingPeaks.length + newPeaks.length);
652
+ result.set(existingPeaks);
653
+ result.set(newPeaks, existingPeaks.length);
654
+ return result;
655
+ }
656
+
657
+ // src/utils/audioBufferUtils.ts
658
+ function concatenateAudioData(chunks) {
659
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
660
+ const result = new Float32Array(totalLength);
661
+ let offset = 0;
662
+ for (const chunk of chunks) {
663
+ result.set(chunk, offset);
664
+ offset += chunk.length;
665
+ }
666
+ return result;
667
+ }
668
+ function createAudioBuffer(audioContext, channelData, sampleRate, channelCount = 1) {
669
+ const channels = channelData instanceof Float32Array ? [channelData] : channelData;
670
+ const length = channels[0]?.length ?? 0;
671
+ const buffer = audioContext.createBuffer(channelCount, length, sampleRate);
672
+ for (let ch = 0; ch < Math.min(channelCount, channels.length); ch++) {
673
+ buffer.copyToChannel(new Float32Array(channels[ch]), ch);
674
+ }
675
+ return buffer;
676
+ }
677
+ function appendToAudioBuffer(audioContext, existingBuffer, newSamples, sampleRate) {
678
+ if (!existingBuffer) {
679
+ return createAudioBuffer(audioContext, [newSamples], sampleRate);
680
+ }
681
+ const existingData = existingBuffer.getChannelData(0);
682
+ const combined = concatenateAudioData([existingData, newSamples]);
683
+ return createAudioBuffer(audioContext, [combined], sampleRate);
684
+ }
685
+ function calculateDuration(sampleCount, sampleRate) {
686
+ return sampleCount / sampleRate;
464
687
  }
465
688
 
466
689
  // src/clipTimeHelpers.ts
@@ -621,8 +844,11 @@ var getShortcutLabel = (shortcut) => {
621
844
  MAX_CANVAS_WIDTH,
622
845
  MIN_PIXELS_PER_UNIT,
623
846
  PPQN,
847
+ appendPeaks,
848
+ appendToAudioBuffer,
624
849
  applyFadeIn,
625
850
  applyFadeOut,
851
+ calculateDuration,
626
852
  clipDurationTime,
627
853
  clipEndTime,
628
854
  clipOffsetTime,
@@ -630,16 +856,21 @@ var getShortcutLabel = (shortcut) => {
630
856
  clipStartTime,
631
857
  clipsOverlap,
632
858
  computeMusicalTicks,
859
+ concatenateAudioData,
860
+ createAudioBuffer,
633
861
  createClip,
634
862
  createClipFromSeconds,
863
+ createClipFromTicks,
635
864
  createTimeline,
636
865
  createTrack,
637
866
  dBToNormalized,
867
+ detectMeterChanges,
638
868
  exponentialCurve,
639
869
  findGaps,
640
870
  gainToDb,
641
871
  gainToNormalized,
642
872
  generateCurve,
873
+ generatePeaks,
643
874
  getClipsAtSample,
644
875
  getClipsInRange,
645
876
  getShortcutLabel,
@@ -661,7 +892,6 @@ var getShortcutLabel = (shortcut) => {
661
892
  sortClipsByTime,
662
893
  ticksPerBar,
663
894
  ticksPerBeat,
664
- ticksToBarBeatLabel,
665
895
  ticksToSamples,
666
896
  trackChannelCount
667
897
  });