@waveform-playlist/browser 11.3.1 → 12.1.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.d.mts CHANGED
@@ -54,10 +54,23 @@ interface PlaybackAnimationContextValue {
54
54
  isPlaying: boolean;
55
55
  currentTime: number;
56
56
  currentTimeRef: React__default.RefObject<number>;
57
+ /**
58
+ * Visually-aligned playback time (raw engine time minus `outputLatency` and
59
+ * `engine.lookAhead`). Kept current by the animation loop during playback
60
+ * and by pause/seek/stop paths when stopped. Read from this for any visual
61
+ * positioning that should match the audible output.
62
+ */
63
+ visualTimeRef: React__default.RefObject<number>;
57
64
  playbackStartTimeRef: React__default.RefObject<number>;
58
65
  audioStartPositionRef: React__default.RefObject<number>;
59
- /** Returns current playback time from engine (auto-wraps at loop boundaries). */
66
+ /** Returns raw playback time from engine (auto-wraps at loop boundaries). */
60
67
  getPlaybackTime: () => number;
68
+ /**
69
+ * Returns the current adapter scheduler lookahead (Tone ~0.1s, native 0).
70
+ * Use this for any audible-latency calculation that must match the playhead
71
+ * (e.g., recording live-preview peak slicing).
72
+ */
73
+ getLookAhead: () => number;
61
74
  /** Register a per-frame callback driven by the single animation loop. */
62
75
  registerFrameCallback: (id: string, cb: (data: FrameData) => void) => void;
63
76
  /** Unregister a per-frame callback. */
package/dist/index.d.ts CHANGED
@@ -54,10 +54,23 @@ interface PlaybackAnimationContextValue {
54
54
  isPlaying: boolean;
55
55
  currentTime: number;
56
56
  currentTimeRef: React__default.RefObject<number>;
57
+ /**
58
+ * Visually-aligned playback time (raw engine time minus `outputLatency` and
59
+ * `engine.lookAhead`). Kept current by the animation loop during playback
60
+ * and by pause/seek/stop paths when stopped. Read from this for any visual
61
+ * positioning that should match the audible output.
62
+ */
63
+ visualTimeRef: React__default.RefObject<number>;
57
64
  playbackStartTimeRef: React__default.RefObject<number>;
58
65
  audioStartPositionRef: React__default.RefObject<number>;
59
- /** Returns current playback time from engine (auto-wraps at loop boundaries). */
66
+ /** Returns raw playback time from engine (auto-wraps at loop boundaries). */
60
67
  getPlaybackTime: () => number;
68
+ /**
69
+ * Returns the current adapter scheduler lookahead (Tone ~0.1s, native 0).
70
+ * Use this for any audible-latency calculation that must match the playhead
71
+ * (e.g., recording live-preview peak slicing).
72
+ */
73
+ getLookAhead: () => number;
61
74
  /** Register a per-frame callback driven by the single animation loop. */
62
75
  registerFrameCallback: (id: string, cb: (data: FrameData) => void) => void;
63
76
  /** Unregister a per-frame callback. */
package/dist/index.js CHANGED
@@ -3692,6 +3692,7 @@ var WaveformPlaylistProvider = ({
3692
3692
  isPlayingRef.current = isPlaying;
3693
3693
  const playStartPositionRef = (0, import_react24.useRef)(0);
3694
3694
  const currentTimeRef = (0, import_react24.useRef)(0);
3695
+ const visualTimeRef = (0, import_react24.useRef)(0);
3695
3696
  const tracksRef = (0, import_react24.useRef)(tracks);
3696
3697
  const soundFontCacheRef = (0, import_react24.useRef)(soundFontCache);
3697
3698
  soundFontCacheRef.current = soundFontCache;
@@ -4162,6 +4163,25 @@ var WaveformPlaylistProvider = ({
4162
4163
  const elapsed = (0, import_tone4.getContext)().currentTime - ((_a2 = playbackStartTimeRef.current) != null ? _a2 : 0);
4163
4164
  return ((_b2 = audioStartPositionRef.current) != null ? _b2 : 0) + elapsed;
4164
4165
  }, []);
4166
+ const toVisualTime = (0, import_react24.useCallback)((rawTime) => {
4167
+ var _a2, _b2;
4168
+ const audioCtx = (0, import_playout5.getGlobalAudioContext)();
4169
+ const latency = "outputLatency" in audioCtx ? audioCtx.outputLatency : 0;
4170
+ const lookAhead = (_b2 = (_a2 = engineRef.current) == null ? void 0 : _a2.lookAhead) != null ? _b2 : 0;
4171
+ const visual = rawTime - latency - lookAhead;
4172
+ return Number.isFinite(visual) ? Math.max(0, visual) : 0;
4173
+ }, []);
4174
+ const setCurrentTimeRefs = (0, import_react24.useCallback)(
4175
+ (rawTime) => {
4176
+ currentTimeRef.current = rawTime;
4177
+ visualTimeRef.current = toVisualTime(rawTime);
4178
+ },
4179
+ [toVisualTime]
4180
+ );
4181
+ const getLookAhead = (0, import_react24.useCallback)(() => {
4182
+ var _a2, _b2;
4183
+ return (_b2 = (_a2 = engineRef.current) == null ? void 0 : _a2.lookAhead) != null ? _b2 : 0;
4184
+ }, []);
4165
4185
  const registerFrameCallback = (0, import_react24.useCallback)((id, cb) => {
4166
4186
  frameCallbacksRef.current.set(id, cb);
4167
4187
  }, []);
@@ -4171,10 +4191,14 @@ var WaveformPlaylistProvider = ({
4171
4191
  const startAnimationLoop = (0, import_react24.useCallback)(() => {
4172
4192
  const audioCtx = (0, import_playout5.getGlobalAudioContext)();
4173
4193
  const updateTime = () => {
4194
+ var _a2, _b2;
4174
4195
  const time = getPlaybackTime();
4175
4196
  currentTimeRef.current = time;
4176
4197
  const latency = "outputLatency" in audioCtx ? audioCtx.outputLatency : 0;
4177
- const visualTime = Math.max(0, time - latency);
4198
+ const lookAhead = (_b2 = (_a2 = engineRef.current) == null ? void 0 : _a2.lookAhead) != null ? _b2 : 0;
4199
+ const visualRaw = time - latency - lookAhead;
4200
+ const visualTime = Number.isFinite(visualRaw) ? Math.max(0, visualRaw) : 0;
4201
+ visualTimeRef.current = visualTime;
4178
4202
  const sr = sampleRateRef.current;
4179
4203
  const spp = samplesPerPixelRef.current;
4180
4204
  const frameData = {
@@ -4207,7 +4231,7 @@ var WaveformPlaylistProvider = ({
4207
4231
  engineRef.current.stop();
4208
4232
  }
4209
4233
  setIsPlaying(false);
4210
- currentTimeRef.current = playStartPositionRef.current;
4234
+ setCurrentTimeRefs(playStartPositionRef.current);
4211
4235
  setCurrentTime(playStartPositionRef.current);
4212
4236
  return;
4213
4237
  }
@@ -4230,7 +4254,7 @@ var WaveformPlaylistProvider = ({
4230
4254
  engineRef.current.stop();
4231
4255
  }
4232
4256
  setIsPlaying(false);
4233
- currentTimeRef.current = playbackEndTimeRef.current;
4257
+ setCurrentTimeRefs(playbackEndTimeRef.current);
4234
4258
  setCurrentTime(playbackEndTimeRef.current);
4235
4259
  playbackEndTimeRef.current = null;
4236
4260
  return;
@@ -4240,7 +4264,7 @@ var WaveformPlaylistProvider = ({
4240
4264
  engineRef.current.stop();
4241
4265
  }
4242
4266
  setIsPlaying(false);
4243
- currentTimeRef.current = playStartPositionRef.current;
4267
+ setCurrentTimeRefs(playStartPositionRef.current);
4244
4268
  setCurrentTime(playStartPositionRef.current);
4245
4269
  setActiveAnnotationId(null);
4246
4270
  return;
@@ -4248,7 +4272,13 @@ var WaveformPlaylistProvider = ({
4248
4272
  startAnimationFrameLoop(updateTime);
4249
4273
  };
4250
4274
  startAnimationFrameLoop(updateTime);
4251
- }, [duration, setActiveAnnotationId, startAnimationFrameLoop, getPlaybackTime]);
4275
+ }, [
4276
+ duration,
4277
+ setActiveAnnotationId,
4278
+ startAnimationFrameLoop,
4279
+ getPlaybackTime,
4280
+ setCurrentTimeRefs
4281
+ ]);
4252
4282
  const stopAnimationLoop = stopAnimationFrameLoop;
4253
4283
  (0, import_react24.useEffect)(() => {
4254
4284
  const reschedulePlayback = () => __async(null, null, function* () {
@@ -4304,7 +4334,7 @@ var WaveformPlaylistProvider = ({
4304
4334
  if (!engineRef.current) return;
4305
4335
  const actualStartTime = startTime != null ? startTime : currentTimeRef.current;
4306
4336
  playStartPositionRef.current = actualStartTime;
4307
- currentTimeRef.current = actualStartTime;
4337
+ setCurrentTimeRefs(actualStartTime);
4308
4338
  engineRef.current.stop();
4309
4339
  engineRef.current.seek(actualStartTime);
4310
4340
  stopAnimationLoop();
@@ -4328,7 +4358,7 @@ var WaveformPlaylistProvider = ({
4328
4358
  setIsPlaying(true);
4329
4359
  startAnimationLoop();
4330
4360
  }),
4331
- [startAnimationLoop, stopAnimationLoop]
4361
+ [startAnimationLoop, stopAnimationLoop, setCurrentTimeRefs]
4332
4362
  );
4333
4363
  const pause = (0, import_react24.useCallback)(() => {
4334
4364
  if (!engineRef.current) return;
@@ -4336,28 +4366,28 @@ var WaveformPlaylistProvider = ({
4336
4366
  engineRef.current.pause();
4337
4367
  setIsPlaying(false);
4338
4368
  stopAnimationLoop();
4339
- currentTimeRef.current = pauseTime;
4369
+ setCurrentTimeRefs(pauseTime);
4340
4370
  setCurrentTime(pauseTime);
4341
- }, [stopAnimationLoop, getPlaybackTime]);
4371
+ }, [stopAnimationLoop, getPlaybackTime, setCurrentTimeRefs]);
4342
4372
  const stop = (0, import_react24.useCallback)(() => {
4343
4373
  if (!engineRef.current) return;
4344
4374
  engineRef.current.stop();
4345
4375
  setIsPlaying(false);
4346
4376
  stopAnimationLoop();
4347
- currentTimeRef.current = playStartPositionRef.current;
4377
+ setCurrentTimeRefs(playStartPositionRef.current);
4348
4378
  setCurrentTime(playStartPositionRef.current);
4349
4379
  setActiveAnnotationId(null);
4350
- }, [stopAnimationLoop, setActiveAnnotationId]);
4380
+ }, [stopAnimationLoop, setActiveAnnotationId, setCurrentTimeRefs]);
4351
4381
  const seekTo = (0, import_react24.useCallback)(
4352
4382
  (time) => {
4353
4383
  const clampedTime = Math.max(0, Math.min(time, duration));
4354
- currentTimeRef.current = clampedTime;
4384
+ setCurrentTimeRefs(clampedTime);
4355
4385
  setCurrentTime(clampedTime);
4356
4386
  if (isPlaying && engineRef.current) {
4357
4387
  play(clampedTime);
4358
4388
  }
4359
4389
  },
4360
- [duration, isPlaying, play]
4390
+ [duration, isPlaying, play, setCurrentTimeRefs]
4361
4391
  );
4362
4392
  const setTrackMute = (0, import_react24.useCallback)(
4363
4393
  (trackIndex, muted) => {
@@ -4418,7 +4448,7 @@ var WaveformPlaylistProvider = ({
4418
4448
  const setSelection = (0, import_react24.useCallback)(
4419
4449
  (start, end) => {
4420
4450
  setSelectionEngine(start, end);
4421
- currentTimeRef.current = start;
4451
+ setCurrentTimeRefs(start);
4422
4452
  setCurrentTime(start);
4423
4453
  if (isPlaying && engineRef.current) {
4424
4454
  engineRef.current.stop();
@@ -4426,7 +4456,7 @@ var WaveformPlaylistProvider = ({
4426
4456
  engineRef.current.play(start);
4427
4457
  }
4428
4458
  },
4429
- [isPlaying, setSelectionEngine]
4459
+ [isPlaying, setSelectionEngine, setCurrentTimeRefs]
4430
4460
  );
4431
4461
  const setScrollContainer = (0, import_react24.useCallback)((element) => {
4432
4462
  scrollContainerRef.current = element;
@@ -4456,9 +4486,11 @@ var WaveformPlaylistProvider = ({
4456
4486
  isPlaying,
4457
4487
  currentTime,
4458
4488
  currentTimeRef,
4489
+ visualTimeRef,
4459
4490
  playbackStartTimeRef,
4460
4491
  audioStartPositionRef,
4461
4492
  getPlaybackTime,
4493
+ getLookAhead,
4462
4494
  registerFrameCallback,
4463
4495
  unregisterFrameCallback
4464
4496
  }),
@@ -4466,9 +4498,11 @@ var WaveformPlaylistProvider = ({
4466
4498
  isPlaying,
4467
4499
  currentTime,
4468
4500
  currentTimeRef,
4501
+ visualTimeRef,
4469
4502
  playbackStartTimeRef,
4470
4503
  audioStartPositionRef,
4471
4504
  getPlaybackTime,
4505
+ getLookAhead,
4472
4506
  registerFrameCallback,
4473
4507
  unregisterFrameCallback
4474
4508
  ]
@@ -4511,10 +4545,10 @@ var WaveformPlaylistProvider = ({
4511
4545
  );
4512
4546
  const setCurrentTimeControl = (0, import_react24.useCallback)(
4513
4547
  (time) => {
4514
- currentTimeRef.current = time;
4548
+ setCurrentTimeRefs(time);
4515
4549
  setCurrentTime(time);
4516
4550
  },
4517
- [currentTimeRef]
4551
+ [setCurrentTimeRefs]
4518
4552
  );
4519
4553
  const setAutomaticScrollControl = (0, import_react24.useCallback)((enabled) => {
4520
4554
  setIsAutomaticScroll(enabled);
@@ -5402,6 +5436,7 @@ var import_react_dom = require("react-dom");
5402
5436
  var import_styled_components6 = __toESM(require("styled-components"));
5403
5437
  var import_playout6 = require("@waveform-playlist/playout");
5404
5438
  var import_ui_components9 = require("@waveform-playlist/ui-components");
5439
+ var import_core8 = require("@waveform-playlist/core");
5405
5440
 
5406
5441
  // src/components/AnimatedPlayhead.tsx
5407
5442
  var import_react30 = require("react");
@@ -5423,7 +5458,13 @@ var PlayheadLine = import_styled_components4.default.div.attrs((props) => ({
5423
5458
  `;
5424
5459
  var AnimatedPlayhead = ({ color = "#ff0000" }) => {
5425
5460
  const playheadRef = (0, import_react30.useRef)(null);
5426
- const { isPlaying, currentTimeRef, registerFrameCallback, unregisterFrameCallback } = usePlaybackAnimation();
5461
+ const {
5462
+ isPlaying,
5463
+ currentTimeRef,
5464
+ visualTimeRef,
5465
+ registerFrameCallback,
5466
+ unregisterFrameCallback
5467
+ } = usePlaybackAnimation();
5427
5468
  const { samplesPerPixel, sampleRate, progressBarWidth } = usePlaylistData();
5428
5469
  (0, import_react30.useEffect)(() => {
5429
5470
  const id = "playhead";
@@ -5438,9 +5479,9 @@ var AnimatedPlayhead = ({ color = "#ff0000" }) => {
5438
5479
  return () => unregisterFrameCallback(id);
5439
5480
  }, [isPlaying, registerFrameCallback, unregisterFrameCallback]);
5440
5481
  (0, import_react30.useEffect)(() => {
5441
- var _a;
5482
+ var _a, _b;
5442
5483
  if (!isPlaying && playheadRef.current) {
5443
- const time = (_a = currentTimeRef.current) != null ? _a : 0;
5484
+ const time = (_b = (_a = visualTimeRef.current) != null ? _a : currentTimeRef.current) != null ? _b : 0;
5444
5485
  const position = time * sampleRate / samplesPerPixel;
5445
5486
  playheadRef.current.style.transform = `translate3d(${position}px, 0, 0)`;
5446
5487
  }
@@ -5511,7 +5552,13 @@ var ChannelWithProgress = (_a) => {
5511
5552
  const callbackId = (0, import_react31.useId)();
5512
5553
  const theme = (0, import_ui_components8.useTheme)();
5513
5554
  const { waveHeight } = (0, import_ui_components8.usePlaylistInfo)();
5514
- const { isPlaying, currentTimeRef, registerFrameCallback, unregisterFrameCallback } = usePlaybackAnimation();
5555
+ const {
5556
+ isPlaying,
5557
+ currentTimeRef,
5558
+ visualTimeRef,
5559
+ registerFrameCallback,
5560
+ unregisterFrameCallback
5561
+ } = usePlaybackAnimation();
5515
5562
  const { samplesPerPixel, sampleRate } = usePlaylistData();
5516
5563
  const progressColor = (theme == null ? void 0 : theme.waveProgressColor) || "rgba(0, 0, 0, 0.1)";
5517
5564
  const clipPixelWidth = (0, import_core7.clipPixelWidth)(
@@ -5548,9 +5595,9 @@ var ChannelWithProgress = (_a) => {
5548
5595
  unregisterFrameCallback
5549
5596
  ]);
5550
5597
  (0, import_react31.useEffect)(() => {
5551
- var _a2;
5598
+ var _a2, _b2;
5552
5599
  if (!isPlaying && progressRef.current) {
5553
- const currentTime = (_a2 = currentTimeRef.current) != null ? _a2 : 0;
5600
+ const currentTime = (_b2 = (_a2 = visualTimeRef.current) != null ? _a2 : currentTimeRef.current) != null ? _b2 : 0;
5554
5601
  const currentSample = currentTime * sampleRate;
5555
5602
  const clipEndSample = clipStartSample + clipDurationSamples;
5556
5603
  let ratio = 0;
@@ -5658,25 +5705,28 @@ var ControlSlot = import_styled_components6.default.div.attrs((props) => ({
5658
5705
  ${(props) => props.$isSelected && `background: ${props.theme.selectedTrackControlsBackground};`}
5659
5706
  `;
5660
5707
  var CustomPlayhead = ({ renderPlayhead, color, samplesPerPixel, sampleRate }) => {
5661
- var _a;
5708
+ var _a, _b;
5662
5709
  const {
5663
5710
  isPlaying,
5664
5711
  currentTimeRef,
5712
+ visualTimeRef,
5665
5713
  playbackStartTimeRef,
5666
5714
  audioStartPositionRef,
5667
5715
  getPlaybackTime
5668
5716
  } = usePlaybackAnimation();
5717
+ const visualTime = (_b = (_a = visualTimeRef.current) != null ? _a : currentTimeRef.current) != null ? _b : 0;
5669
5718
  return renderPlayhead({
5670
- position: ((_a = currentTimeRef.current) != null ? _a : 0) * sampleRate / samplesPerPixel,
5719
+ position: visualTime * sampleRate / samplesPerPixel,
5671
5720
  color,
5672
5721
  isPlaying,
5673
5722
  currentTimeRef,
5723
+ visualTimeRef,
5674
5724
  playbackStartTimeRef,
5675
5725
  audioStartPositionRef,
5676
5726
  samplesPerPixel,
5677
5727
  sampleRate,
5678
5728
  controlsOffset: 0,
5679
- getAudioContextTime: () => (0, import_playout6.getGlobalContext)().rawContext.currentTime,
5729
+ getAudioContextTime: () => (0, import_playout6.getGlobalAudioContext)().currentTime,
5680
5730
  getPlaybackTime
5681
5731
  });
5682
5732
  };
@@ -5701,7 +5751,7 @@ var PlaylistVisualization = ({
5701
5751
  }) => {
5702
5752
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
5703
5753
  const theme = (0, import_ui_components9.useTheme)();
5704
- const { isPlaying } = usePlaybackAnimation();
5754
+ const { isPlaying, getLookAhead } = usePlaybackAnimation();
5705
5755
  const {
5706
5756
  selectionStart,
5707
5757
  selectionEnd,
@@ -6160,22 +6210,39 @@ var PlaylistVisualization = ({
6160
6210
  clip.clipId
6161
6211
  );
6162
6212
  }),
6163
- (recordingState == null ? void 0 : recordingState.isRecording) && recordingState.trackId === track.id && ((_d2 = recordingState.peaks[0]) == null ? void 0 : _d2.length) > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6164
- import_ui_components9.Clip,
6165
- {
6166
- clipId: "recording-preview",
6167
- trackIndex,
6168
- clipIndex: trackClipPeaks.length,
6169
- trackName: "Recording...",
6170
- startSample: recordingState.startSample,
6171
- durationSamples: recordingState.durationSamples,
6172
- samplesPerPixel,
6173
- showHeader: showClipHeaders,
6174
- disableHeaderDrag: true,
6175
- isSelected: track.id === selectedTrackId,
6176
- trackId: track.id,
6177
- children: (mono ? recordingState.peaks.slice(0, 1) : recordingState.peaks).map(
6178
- (channelPeaks, chIdx) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6213
+ (recordingState == null ? void 0 : recordingState.isRecording) && recordingState.trackId === track.id && ((_d2 = recordingState.peaks[0]) == null ? void 0 : _d2.length) > 0 && (() => {
6214
+ const audioCtx = (0, import_playout6.getGlobalAudioContext)();
6215
+ const outputLatency = "outputLatency" in audioCtx ? audioCtx.outputLatency : 0;
6216
+ const lookAhead = getLookAhead();
6217
+ const latencyOffsetSamples = (0, import_core8.audibleLatencySamples)(
6218
+ outputLatency,
6219
+ lookAhead,
6220
+ sampleRate
6221
+ );
6222
+ const latencyPixels = Math.floor(latencyOffsetSamples / samplesPerPixel);
6223
+ const skipPeakElements = latencyPixels * 2;
6224
+ const previewDuration = Math.max(
6225
+ 0,
6226
+ recordingState.durationSamples - latencyOffsetSamples
6227
+ );
6228
+ const previewChannels = (mono ? recordingState.peaks.slice(0, 1) : recordingState.peaks).map(
6229
+ (channelPeaks) => skipPeakElements > 0 && skipPeakElements < channelPeaks.length ? channelPeaks.subarray(skipPeakElements) : channelPeaks
6230
+ );
6231
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6232
+ import_ui_components9.Clip,
6233
+ {
6234
+ clipId: "recording-preview",
6235
+ trackIndex,
6236
+ clipIndex: trackClipPeaks.length,
6237
+ trackName: "Recording...",
6238
+ startSample: recordingState.startSample,
6239
+ durationSamples: previewDuration,
6240
+ samplesPerPixel,
6241
+ showHeader: showClipHeaders,
6242
+ disableHeaderDrag: true,
6243
+ isSelected: track.id === selectedTrackId,
6244
+ trackId: track.id,
6245
+ children: previewChannels.map((channelPeaks, chIdx) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6179
6246
  ChannelWithProgress,
6180
6247
  {
6181
6248
  index: chIdx,
@@ -6184,14 +6251,14 @@ var PlaylistVisualization = ({
6184
6251
  length: Math.floor(channelPeaks.length / 2),
6185
6252
  isSelected: track.id === selectedTrackId,
6186
6253
  clipStartSample: recordingState.startSample,
6187
- clipDurationSamples: recordingState.durationSamples
6254
+ clipDurationSamples: previewDuration
6188
6255
  },
6189
6256
  `${track.id}-recording-${chIdx}`
6190
- )
6191
- )
6192
- },
6193
- `${track.id}-recording`
6194
- )
6257
+ ))
6258
+ },
6259
+ `${track.id}-recording`
6260
+ );
6261
+ })()
6195
6262
  ]
6196
6263
  },
6197
6264
  track.id
@@ -7024,7 +7091,7 @@ var KeyboardShortcuts = ({
7024
7091
  var import_react40 = __toESM(require("react"));
7025
7092
  var import_react41 = require("@dnd-kit/react");
7026
7093
  var import_modifiers2 = require("@dnd-kit/abstract/modifiers");
7027
- var import_core9 = require("@waveform-playlist/core");
7094
+ var import_core10 = require("@waveform-playlist/core");
7028
7095
  var import_ui_components12 = require("@waveform-playlist/ui-components");
7029
7096
 
7030
7097
  // src/modifiers/ClipCollisionModifier.ts
@@ -7053,7 +7120,7 @@ var ClipCollisionModifier = _ClipCollisionModifier;
7053
7120
 
7054
7121
  // src/modifiers/SnapToGridModifier.ts
7055
7122
  var import_abstract2 = require("@dnd-kit/abstract");
7056
- var import_core8 = require("@waveform-playlist/core");
7123
+ var import_core9 = require("@waveform-playlist/core");
7057
7124
  var _SnapToGridModifier = class _SnapToGridModifier extends import_abstract2.Modifier {
7058
7125
  apply(operation) {
7059
7126
  const { transform, source } = operation;
@@ -7074,18 +7141,18 @@ var _SnapToGridModifier = class _SnapToGridModifier extends import_abstract2.Mod
7074
7141
  }
7075
7142
  const { snapTo, bpm, timeSignature, sampleRate } = this.options;
7076
7143
  if (snapTo === "off") return transform;
7077
- const gridTicks = snapTo === "bar" ? (0, import_core8.ticksPerBar)(timeSignature) : (0, import_core8.ticksPerBeat)(timeSignature);
7144
+ const gridTicks = snapTo === "bar" ? (0, import_core9.ticksPerBar)(timeSignature) : (0, import_core9.ticksPerBeat)(timeSignature);
7078
7145
  if (startSample !== void 0) {
7079
7146
  const proposedSamples = startSample + transform.x * samplesPerPixel;
7080
- const proposedTicks = (0, import_core8.samplesToTicks)(proposedSamples, bpm, sampleRate);
7081
- const snappedTicks2 = (0, import_core8.snapToGrid)(proposedTicks, gridTicks);
7082
- const snappedSamples2 = (0, import_core8.ticksToSamples)(snappedTicks2, bpm, sampleRate);
7147
+ const proposedTicks = (0, import_core9.samplesToTicks)(proposedSamples, bpm, sampleRate);
7148
+ const snappedTicks2 = (0, import_core9.snapToGrid)(proposedTicks, gridTicks);
7149
+ const snappedSamples2 = (0, import_core9.ticksToSamples)(snappedTicks2, bpm, sampleRate);
7083
7150
  return { x: (snappedSamples2 - startSample) / samplesPerPixel, y: 0 };
7084
7151
  }
7085
7152
  const deltaSamples = transform.x * samplesPerPixel;
7086
- const deltaTicks = (0, import_core8.samplesToTicks)(deltaSamples, bpm, sampleRate);
7087
- const snappedTicks = (0, import_core8.snapToGrid)(deltaTicks, gridTicks);
7088
- const snappedSamples = (0, import_core8.ticksToSamples)(snappedTicks, bpm, sampleRate);
7153
+ const deltaTicks = (0, import_core9.samplesToTicks)(deltaSamples, bpm, sampleRate);
7154
+ const snappedTicks = (0, import_core9.snapToGrid)(deltaTicks, gridTicks);
7155
+ const snappedSamples = (0, import_core9.ticksToSamples)(snappedTicks, bpm, sampleRate);
7089
7156
  return { x: snappedSamples / samplesPerPixel, y: 0 };
7090
7157
  }
7091
7158
  };
@@ -7116,11 +7183,11 @@ var ClipInteractionProvider = ({
7116
7183
  const snapSamplePosition = (0, import_react40.useMemo)(() => {
7117
7184
  if (useBeatsSnap && beatsAndBars) {
7118
7185
  const { bpm, timeSignature, snapTo } = beatsAndBars;
7119
- const gridTicks = snapTo === "bar" ? (0, import_core9.ticksPerBar)(timeSignature) : (0, import_core9.ticksPerBeat)(timeSignature);
7186
+ const gridTicks = snapTo === "bar" ? (0, import_core10.ticksPerBar)(timeSignature) : (0, import_core10.ticksPerBeat)(timeSignature);
7120
7187
  return (samplePos) => {
7121
- const ticks = (0, import_core9.samplesToTicks)(samplePos, bpm, sampleRate);
7122
- const snapped = (0, import_core9.snapToGrid)(ticks, gridTicks);
7123
- return (0, import_core9.ticksToSamples)(snapped, bpm, sampleRate);
7188
+ const ticks = (0, import_core10.samplesToTicks)(samplePos, bpm, sampleRate);
7189
+ const snapped = (0, import_core10.snapToGrid)(ticks, gridTicks);
7190
+ return (0, import_core10.ticksToSamples)(snapped, bpm, sampleRate);
7124
7191
  };
7125
7192
  }
7126
7193
  if (useTimescaleSnap) {