@waveform-playlist/browser 12.0.0 → 13.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.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. */
@@ -1646,15 +1659,32 @@ declare const AnnotationIntegrationProvider: React$1.Provider<AnnotationIntegrat
1646
1659
  */
1647
1660
  declare function useAnnotationIntegration(): AnnotationIntegration;
1648
1661
 
1662
+ /**
1663
+ * Single-call canvas registration shape. Consolidates the OffscreenCanvas
1664
+ * transfer and per-canvas metadata that earlier required two separate
1665
+ * registration paths.
1666
+ *
1667
+ * Provider/orchestrator look up trackId from clipId and derive
1668
+ * globalPixelOffset = chunkIndex * MAX_CANVAS_WIDTH.
1669
+ */
1670
+ interface SpectrogramCanvasRegistration {
1671
+ canvasId: string;
1672
+ canvas: OffscreenCanvas;
1673
+ clipId: string;
1674
+ channelIndex: number;
1675
+ chunkIndex: number;
1676
+ widthPx: number;
1677
+ heightPx: number;
1678
+ }
1649
1679
  interface SpectrogramIntegration {
1650
1680
  trackSpectrogramOverrides: Map<string, TrackSpectrogramOverrides>;
1651
- spectrogramWorkerApi: SpectrogramWorkerApi | null;
1652
1681
  spectrogramConfig?: SpectrogramConfig;
1653
1682
  spectrogramColorMap?: ColorMapValue;
1654
1683
  setTrackRenderMode: (trackId: string, mode: RenderMode) => void;
1655
1684
  setTrackSpectrogramConfig: (trackId: string, config: SpectrogramConfig, colorMap?: ColorMapValue) => void;
1656
- registerSpectrogramCanvases: (clipId: string, channelIndex: number, canvasIds: string[], canvasWidths: number[]) => void;
1657
- unregisterSpectrogramCanvases: (clipId: string, channelIndex: number) => void;
1685
+ /** Single-canvas registration. OffscreenCanvas is non-transferable call once per canvas. */
1686
+ registerSpectrogramCanvas: (reg: SpectrogramCanvasRegistration) => void;
1687
+ unregisterSpectrogramCanvas: (canvasId: string) => void;
1658
1688
  /** Render spectrogram menu items for a track's context menu */
1659
1689
  renderMenuItems?: (props: {
1660
1690
  renderMode: string;
@@ -1675,11 +1705,6 @@ interface SpectrogramIntegration {
1675
1705
  /** Get frequency scale function for a scale name */
1676
1706
  getFrequencyScale: (name: string) => (f: number, minF: number, maxF: number) => number;
1677
1707
  }
1678
- /** Minimal type for the worker API surface used by browser components */
1679
- interface SpectrogramWorkerApi {
1680
- registerCanvas: (canvasId: string, canvas: OffscreenCanvas) => void;
1681
- unregisterCanvas: (canvasId: string) => void;
1682
- }
1683
1708
  declare const SpectrogramIntegrationProvider: React$1.Provider<SpectrogramIntegration | null>;
1684
1709
  /**
1685
1710
  * Hook to access spectrogram integration provided by @waveform-playlist/spectrogram.
@@ -1824,4 +1849,4 @@ declare function getWaveformDataMetadata(src: string): Promise<{
1824
1849
  bits: 8 | 16;
1825
1850
  }>;
1826
1851
 
1827
- export { type ActiveEffect, type AnnotationIntegration, AnnotationIntegrationProvider, AudioPosition, type AudioTrackConfig, AutomaticScrollCheckbox, ClearAllButton, type ClearAllButtonProps, ClipCollisionModifier, ClipInteractionProvider, type ClipInteractionProviderProps, ContinuousPlayCheckbox, DownloadAnnotationsButton, EditableCheckbox, type EffectDefinition, type EffectInstance, type EffectParameter, type ExportOptions, type ExportResult, ExportWavButton, type ExportWavButtonProps, FastForwardButton, type FrameData, type GetAnnotationBoxLabelFn, KeyboardShortcuts, type KeyboardShortcutsProps, LinkEndpointsCheckbox, LoopButton, MasterVolumeControl, type MasterVolumeControls, type MediaElementAnimationContextValue, MediaElementAnnotationList, type MediaElementAnnotationListProps, type MediaElementControlsContextValue, type MediaElementDataContextValue, MediaElementPlaylist, type MediaElementPlaylistProps, MediaElementPlaylistProvider, type MediaElementStateContextValue, type MediaElementTrackConfig, MediaElementWaveform, type MediaElementWaveformProps, type OnAnnotationUpdateFn, type ParameterType, PauseButton, PlayButton, PlaylistAnnotationList, type PlaylistAnnotationListProps, PlaylistVisualization, type PlaylistVisualizationProps, RewindButton, SelectionTimeInputs, SetLoopRegionButton, SkipBackwardButton, SkipForwardButton, SnapToGridModifier, type SpectrogramIntegration, SpectrogramIntegrationProvider, StopButton, type TimeFormatControls, TimeFormatSelect, type TrackActiveEffect, type TrackEffectsState, type TrackLoadError, type TrackSource, type TrackState$1 as TrackState, type UseDynamicEffectsReturn, type UseDynamicTracksReturn, type UseExportWavReturn, type UseOutputMeterOptions, type UseOutputMeterReturn, type UsePlaybackShortcutsOptions, type UsePlaybackShortcutsReturn, type UseTrackDynamicEffectsReturn, Waveform, WaveformPlaylistProvider, type WaveformProps, type WaveformTrack, type ZoomControls, ZoomInButton, ZoomOutButton, createEffectChain, createEffectInstance, effectCategories, effectDefinitions, getEffectDefinition, getEffectsByCategory, getWaveformDataMetadata, loadPeaksFromWaveformData, loadWaveformData, noDropAnimationPlugins, useAnnotationDragHandlers, useAnnotationIntegration, useAnnotationKeyboardControls, useAudioTracks, useClipDragHandlers, useClipInteractionEnabled, useClipSplitting, useDragSensors, useDynamicEffects, useDynamicTracks, useExportWav, useKeyboardShortcuts, useMasterAnalyser, useMasterVolume, useMediaElementAnimation, useMediaElementControls, useMediaElementData, useMediaElementState, useOutputMeter, usePlaybackAnimation, usePlaybackShortcuts, usePlaylistControls, usePlaylistData, usePlaylistState, useSpectrogramIntegration, useTimeFormat, useTrackDynamicEffects, useZoomControls, waveformDataToPeaks };
1852
+ export { type ActiveEffect, type AnnotationIntegration, AnnotationIntegrationProvider, AudioPosition, type AudioTrackConfig, AutomaticScrollCheckbox, ClearAllButton, type ClearAllButtonProps, ClipCollisionModifier, ClipInteractionProvider, type ClipInteractionProviderProps, ContinuousPlayCheckbox, DownloadAnnotationsButton, EditableCheckbox, type EffectDefinition, type EffectInstance, type EffectParameter, type ExportOptions, type ExportResult, ExportWavButton, type ExportWavButtonProps, FastForwardButton, type FrameData, type GetAnnotationBoxLabelFn, KeyboardShortcuts, type KeyboardShortcutsProps, LinkEndpointsCheckbox, LoopButton, MasterVolumeControl, type MasterVolumeControls, type MediaElementAnimationContextValue, MediaElementAnnotationList, type MediaElementAnnotationListProps, type MediaElementControlsContextValue, type MediaElementDataContextValue, MediaElementPlaylist, type MediaElementPlaylistProps, MediaElementPlaylistProvider, type MediaElementStateContextValue, type MediaElementTrackConfig, MediaElementWaveform, type MediaElementWaveformProps, type OnAnnotationUpdateFn, type ParameterType, PauseButton, PlayButton, PlaylistAnnotationList, type PlaylistAnnotationListProps, PlaylistVisualization, type PlaylistVisualizationProps, RewindButton, SelectionTimeInputs, SetLoopRegionButton, SkipBackwardButton, SkipForwardButton, SnapToGridModifier, type SpectrogramCanvasRegistration, type SpectrogramIntegration, SpectrogramIntegrationProvider, StopButton, type TimeFormatControls, TimeFormatSelect, type TrackActiveEffect, type TrackEffectsState, type TrackLoadError, type TrackSource, type TrackState$1 as TrackState, type UseDynamicEffectsReturn, type UseDynamicTracksReturn, type UseExportWavReturn, type UseOutputMeterOptions, type UseOutputMeterReturn, type UsePlaybackShortcutsOptions, type UsePlaybackShortcutsReturn, type UseTrackDynamicEffectsReturn, Waveform, WaveformPlaylistProvider, type WaveformProps, type WaveformTrack, type ZoomControls, ZoomInButton, ZoomOutButton, createEffectChain, createEffectInstance, effectCategories, effectDefinitions, getEffectDefinition, getEffectsByCategory, getWaveformDataMetadata, loadPeaksFromWaveformData, loadWaveformData, noDropAnimationPlugins, useAnnotationDragHandlers, useAnnotationIntegration, useAnnotationKeyboardControls, useAudioTracks, useClipDragHandlers, useClipInteractionEnabled, useClipSplitting, useDragSensors, useDynamicEffects, useDynamicTracks, useExportWav, useKeyboardShortcuts, useMasterAnalyser, useMasterVolume, useMediaElementAnimation, useMediaElementControls, useMediaElementData, useMediaElementState, useOutputMeter, usePlaybackAnimation, usePlaybackShortcuts, usePlaylistControls, usePlaylistData, usePlaylistState, useSpectrogramIntegration, useTimeFormat, useTrackDynamicEffects, useZoomControls, waveformDataToPeaks };
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. */
@@ -1646,15 +1659,32 @@ declare const AnnotationIntegrationProvider: React$1.Provider<AnnotationIntegrat
1646
1659
  */
1647
1660
  declare function useAnnotationIntegration(): AnnotationIntegration;
1648
1661
 
1662
+ /**
1663
+ * Single-call canvas registration shape. Consolidates the OffscreenCanvas
1664
+ * transfer and per-canvas metadata that earlier required two separate
1665
+ * registration paths.
1666
+ *
1667
+ * Provider/orchestrator look up trackId from clipId and derive
1668
+ * globalPixelOffset = chunkIndex * MAX_CANVAS_WIDTH.
1669
+ */
1670
+ interface SpectrogramCanvasRegistration {
1671
+ canvasId: string;
1672
+ canvas: OffscreenCanvas;
1673
+ clipId: string;
1674
+ channelIndex: number;
1675
+ chunkIndex: number;
1676
+ widthPx: number;
1677
+ heightPx: number;
1678
+ }
1649
1679
  interface SpectrogramIntegration {
1650
1680
  trackSpectrogramOverrides: Map<string, TrackSpectrogramOverrides>;
1651
- spectrogramWorkerApi: SpectrogramWorkerApi | null;
1652
1681
  spectrogramConfig?: SpectrogramConfig;
1653
1682
  spectrogramColorMap?: ColorMapValue;
1654
1683
  setTrackRenderMode: (trackId: string, mode: RenderMode) => void;
1655
1684
  setTrackSpectrogramConfig: (trackId: string, config: SpectrogramConfig, colorMap?: ColorMapValue) => void;
1656
- registerSpectrogramCanvases: (clipId: string, channelIndex: number, canvasIds: string[], canvasWidths: number[]) => void;
1657
- unregisterSpectrogramCanvases: (clipId: string, channelIndex: number) => void;
1685
+ /** Single-canvas registration. OffscreenCanvas is non-transferable call once per canvas. */
1686
+ registerSpectrogramCanvas: (reg: SpectrogramCanvasRegistration) => void;
1687
+ unregisterSpectrogramCanvas: (canvasId: string) => void;
1658
1688
  /** Render spectrogram menu items for a track's context menu */
1659
1689
  renderMenuItems?: (props: {
1660
1690
  renderMode: string;
@@ -1675,11 +1705,6 @@ interface SpectrogramIntegration {
1675
1705
  /** Get frequency scale function for a scale name */
1676
1706
  getFrequencyScale: (name: string) => (f: number, minF: number, maxF: number) => number;
1677
1707
  }
1678
- /** Minimal type for the worker API surface used by browser components */
1679
- interface SpectrogramWorkerApi {
1680
- registerCanvas: (canvasId: string, canvas: OffscreenCanvas) => void;
1681
- unregisterCanvas: (canvasId: string) => void;
1682
- }
1683
1708
  declare const SpectrogramIntegrationProvider: React$1.Provider<SpectrogramIntegration | null>;
1684
1709
  /**
1685
1710
  * Hook to access spectrogram integration provided by @waveform-playlist/spectrogram.
@@ -1824,4 +1849,4 @@ declare function getWaveformDataMetadata(src: string): Promise<{
1824
1849
  bits: 8 | 16;
1825
1850
  }>;
1826
1851
 
1827
- export { type ActiveEffect, type AnnotationIntegration, AnnotationIntegrationProvider, AudioPosition, type AudioTrackConfig, AutomaticScrollCheckbox, ClearAllButton, type ClearAllButtonProps, ClipCollisionModifier, ClipInteractionProvider, type ClipInteractionProviderProps, ContinuousPlayCheckbox, DownloadAnnotationsButton, EditableCheckbox, type EffectDefinition, type EffectInstance, type EffectParameter, type ExportOptions, type ExportResult, ExportWavButton, type ExportWavButtonProps, FastForwardButton, type FrameData, type GetAnnotationBoxLabelFn, KeyboardShortcuts, type KeyboardShortcutsProps, LinkEndpointsCheckbox, LoopButton, MasterVolumeControl, type MasterVolumeControls, type MediaElementAnimationContextValue, MediaElementAnnotationList, type MediaElementAnnotationListProps, type MediaElementControlsContextValue, type MediaElementDataContextValue, MediaElementPlaylist, type MediaElementPlaylistProps, MediaElementPlaylistProvider, type MediaElementStateContextValue, type MediaElementTrackConfig, MediaElementWaveform, type MediaElementWaveformProps, type OnAnnotationUpdateFn, type ParameterType, PauseButton, PlayButton, PlaylistAnnotationList, type PlaylistAnnotationListProps, PlaylistVisualization, type PlaylistVisualizationProps, RewindButton, SelectionTimeInputs, SetLoopRegionButton, SkipBackwardButton, SkipForwardButton, SnapToGridModifier, type SpectrogramIntegration, SpectrogramIntegrationProvider, StopButton, type TimeFormatControls, TimeFormatSelect, type TrackActiveEffect, type TrackEffectsState, type TrackLoadError, type TrackSource, type TrackState$1 as TrackState, type UseDynamicEffectsReturn, type UseDynamicTracksReturn, type UseExportWavReturn, type UseOutputMeterOptions, type UseOutputMeterReturn, type UsePlaybackShortcutsOptions, type UsePlaybackShortcutsReturn, type UseTrackDynamicEffectsReturn, Waveform, WaveformPlaylistProvider, type WaveformProps, type WaveformTrack, type ZoomControls, ZoomInButton, ZoomOutButton, createEffectChain, createEffectInstance, effectCategories, effectDefinitions, getEffectDefinition, getEffectsByCategory, getWaveformDataMetadata, loadPeaksFromWaveformData, loadWaveformData, noDropAnimationPlugins, useAnnotationDragHandlers, useAnnotationIntegration, useAnnotationKeyboardControls, useAudioTracks, useClipDragHandlers, useClipInteractionEnabled, useClipSplitting, useDragSensors, useDynamicEffects, useDynamicTracks, useExportWav, useKeyboardShortcuts, useMasterAnalyser, useMasterVolume, useMediaElementAnimation, useMediaElementControls, useMediaElementData, useMediaElementState, useOutputMeter, usePlaybackAnimation, usePlaybackShortcuts, usePlaylistControls, usePlaylistData, usePlaylistState, useSpectrogramIntegration, useTimeFormat, useTrackDynamicEffects, useZoomControls, waveformDataToPeaks };
1852
+ export { type ActiveEffect, type AnnotationIntegration, AnnotationIntegrationProvider, AudioPosition, type AudioTrackConfig, AutomaticScrollCheckbox, ClearAllButton, type ClearAllButtonProps, ClipCollisionModifier, ClipInteractionProvider, type ClipInteractionProviderProps, ContinuousPlayCheckbox, DownloadAnnotationsButton, EditableCheckbox, type EffectDefinition, type EffectInstance, type EffectParameter, type ExportOptions, type ExportResult, ExportWavButton, type ExportWavButtonProps, FastForwardButton, type FrameData, type GetAnnotationBoxLabelFn, KeyboardShortcuts, type KeyboardShortcutsProps, LinkEndpointsCheckbox, LoopButton, MasterVolumeControl, type MasterVolumeControls, type MediaElementAnimationContextValue, MediaElementAnnotationList, type MediaElementAnnotationListProps, type MediaElementControlsContextValue, type MediaElementDataContextValue, MediaElementPlaylist, type MediaElementPlaylistProps, MediaElementPlaylistProvider, type MediaElementStateContextValue, type MediaElementTrackConfig, MediaElementWaveform, type MediaElementWaveformProps, type OnAnnotationUpdateFn, type ParameterType, PauseButton, PlayButton, PlaylistAnnotationList, type PlaylistAnnotationListProps, PlaylistVisualization, type PlaylistVisualizationProps, RewindButton, SelectionTimeInputs, SetLoopRegionButton, SkipBackwardButton, SkipForwardButton, SnapToGridModifier, type SpectrogramCanvasRegistration, type SpectrogramIntegration, SpectrogramIntegrationProvider, StopButton, type TimeFormatControls, TimeFormatSelect, type TrackActiveEffect, type TrackEffectsState, type TrackLoadError, type TrackSource, type TrackState$1 as TrackState, type UseDynamicEffectsReturn, type UseDynamicTracksReturn, type UseExportWavReturn, type UseOutputMeterOptions, type UseOutputMeterReturn, type UsePlaybackShortcutsOptions, type UsePlaybackShortcutsReturn, type UseTrackDynamicEffectsReturn, Waveform, WaveformPlaylistProvider, type WaveformProps, type WaveformTrack, type ZoomControls, ZoomInButton, ZoomOutButton, createEffectChain, createEffectInstance, effectCategories, effectDefinitions, getEffectDefinition, getEffectsByCategory, getWaveformDataMetadata, loadPeaksFromWaveformData, loadWaveformData, noDropAnimationPlugins, useAnnotationDragHandlers, useAnnotationIntegration, useAnnotationKeyboardControls, useAudioTracks, useClipDragHandlers, useClipInteractionEnabled, useClipSplitting, useDragSensors, useDynamicEffects, useDynamicTracks, useExportWav, useKeyboardShortcuts, useMasterAnalyser, useMasterVolume, useMediaElementAnimation, useMediaElementControls, useMediaElementData, useMediaElementState, useOutputMeter, usePlaybackAnimation, usePlaybackShortcuts, usePlaylistControls, usePlaylistData, usePlaylistState, useSpectrogramIntegration, useTimeFormat, useTrackDynamicEffects, useZoomControls, waveformDataToPeaks };
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,
@@ -5766,17 +5816,6 @@ var PlaylistVisualization = ({
5766
5816
  });
5767
5817
  return helpers;
5768
5818
  }, [tracks, spectrogram]);
5769
- const workerCanvasApi = (0, import_react33.useMemo)(() => {
5770
- if (!(spectrogram == null ? void 0 : spectrogram.spectrogramWorkerApi)) return void 0;
5771
- return {
5772
- registerCanvas: spectrogram.spectrogramWorkerApi.registerCanvas.bind(
5773
- spectrogram.spectrogramWorkerApi
5774
- ),
5775
- unregisterCanvas: spectrogram.spectrogramWorkerApi.unregisterCanvas.bind(
5776
- spectrogram.spectrogramWorkerApi
5777
- )
5778
- };
5779
- }, [spectrogram == null ? void 0 : spectrogram.spectrogramWorkerApi]);
5780
5819
  const [settingsModalTrackId, setSettingsModalTrackId] = (0, import_react33.useState)(null);
5781
5820
  const [isSelecting, setIsSelecting] = (0, import_react33.useState)(false);
5782
5821
  const mouseDownTimeRef = (0, import_react33.useRef)(0);
@@ -6142,16 +6181,9 @@ var PlaylistVisualization = ({
6142
6181
  clipSampleRate: clip.sampleRate,
6143
6182
  clipOffsetSeconds: clip.offsetSamples != null ? clip.offsetSamples / (clip.sampleRate || sampleRate) : 0,
6144
6183
  samplesPerPixel,
6145
- spectrogramWorkerApi: workerCanvasApi,
6146
6184
  spectrogramClipId: clip.clipId,
6147
- spectrogramOnCanvasesReady: spectrogram ? (canvasIds, canvasWidths) => {
6148
- spectrogram.registerSpectrogramCanvases(
6149
- clip.clipId,
6150
- channelIndex,
6151
- canvasIds,
6152
- canvasWidths
6153
- );
6154
- } : void 0
6185
+ spectrogramOnCanvasRegister: spectrogram ? spectrogram.registerSpectrogramCanvas : void 0,
6186
+ spectrogramOnCanvasUnregister: spectrogram ? spectrogram.unregisterSpectrogramCanvas : void 0
6155
6187
  },
6156
6188
  `${clip.clipId}-${channelIndex}`
6157
6189
  );
@@ -6160,22 +6192,39 @@ var PlaylistVisualization = ({
6160
6192
  clip.clipId
6161
6193
  );
6162
6194
  }),
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)(
6195
+ (recordingState == null ? void 0 : recordingState.isRecording) && recordingState.trackId === track.id && ((_d2 = recordingState.peaks[0]) == null ? void 0 : _d2.length) > 0 && (() => {
6196
+ const audioCtx = (0, import_playout6.getGlobalAudioContext)();
6197
+ const outputLatency = "outputLatency" in audioCtx ? audioCtx.outputLatency : 0;
6198
+ const lookAhead = getLookAhead();
6199
+ const latencyOffsetSamples = (0, import_core8.audibleLatencySamples)(
6200
+ outputLatency,
6201
+ lookAhead,
6202
+ sampleRate
6203
+ );
6204
+ const latencyPixels = Math.floor(latencyOffsetSamples / samplesPerPixel);
6205
+ const skipPeakElements = latencyPixels * 2;
6206
+ const previewDuration = Math.max(
6207
+ 0,
6208
+ recordingState.durationSamples - latencyOffsetSamples
6209
+ );
6210
+ const previewChannels = (mono ? recordingState.peaks.slice(0, 1) : recordingState.peaks).map(
6211
+ (channelPeaks) => skipPeakElements > 0 && skipPeakElements < channelPeaks.length ? channelPeaks.subarray(skipPeakElements) : channelPeaks
6212
+ );
6213
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6214
+ import_ui_components9.Clip,
6215
+ {
6216
+ clipId: "recording-preview",
6217
+ trackIndex,
6218
+ clipIndex: trackClipPeaks.length,
6219
+ trackName: "Recording...",
6220
+ startSample: recordingState.startSample,
6221
+ durationSamples: previewDuration,
6222
+ samplesPerPixel,
6223
+ showHeader: showClipHeaders,
6224
+ disableHeaderDrag: true,
6225
+ isSelected: track.id === selectedTrackId,
6226
+ trackId: track.id,
6227
+ children: previewChannels.map((channelPeaks, chIdx) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
6179
6228
  ChannelWithProgress,
6180
6229
  {
6181
6230
  index: chIdx,
@@ -6184,14 +6233,14 @@ var PlaylistVisualization = ({
6184
6233
  length: Math.floor(channelPeaks.length / 2),
6185
6234
  isSelected: track.id === selectedTrackId,
6186
6235
  clipStartSample: recordingState.startSample,
6187
- clipDurationSamples: recordingState.durationSamples
6236
+ clipDurationSamples: previewDuration
6188
6237
  },
6189
6238
  `${track.id}-recording-${chIdx}`
6190
- )
6191
- )
6192
- },
6193
- `${track.id}-recording`
6194
- )
6239
+ ))
6240
+ },
6241
+ `${track.id}-recording`
6242
+ );
6243
+ })()
6195
6244
  ]
6196
6245
  },
6197
6246
  track.id
@@ -7024,7 +7073,7 @@ var KeyboardShortcuts = ({
7024
7073
  var import_react40 = __toESM(require("react"));
7025
7074
  var import_react41 = require("@dnd-kit/react");
7026
7075
  var import_modifiers2 = require("@dnd-kit/abstract/modifiers");
7027
- var import_core9 = require("@waveform-playlist/core");
7076
+ var import_core10 = require("@waveform-playlist/core");
7028
7077
  var import_ui_components12 = require("@waveform-playlist/ui-components");
7029
7078
 
7030
7079
  // src/modifiers/ClipCollisionModifier.ts
@@ -7053,7 +7102,7 @@ var ClipCollisionModifier = _ClipCollisionModifier;
7053
7102
 
7054
7103
  // src/modifiers/SnapToGridModifier.ts
7055
7104
  var import_abstract2 = require("@dnd-kit/abstract");
7056
- var import_core8 = require("@waveform-playlist/core");
7105
+ var import_core9 = require("@waveform-playlist/core");
7057
7106
  var _SnapToGridModifier = class _SnapToGridModifier extends import_abstract2.Modifier {
7058
7107
  apply(operation) {
7059
7108
  const { transform, source } = operation;
@@ -7074,18 +7123,18 @@ var _SnapToGridModifier = class _SnapToGridModifier extends import_abstract2.Mod
7074
7123
  }
7075
7124
  const { snapTo, bpm, timeSignature, sampleRate } = this.options;
7076
7125
  if (snapTo === "off") return transform;
7077
- const gridTicks = snapTo === "bar" ? (0, import_core8.ticksPerBar)(timeSignature) : (0, import_core8.ticksPerBeat)(timeSignature);
7126
+ const gridTicks = snapTo === "bar" ? (0, import_core9.ticksPerBar)(timeSignature) : (0, import_core9.ticksPerBeat)(timeSignature);
7078
7127
  if (startSample !== void 0) {
7079
7128
  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);
7129
+ const proposedTicks = (0, import_core9.samplesToTicks)(proposedSamples, bpm, sampleRate);
7130
+ const snappedTicks2 = (0, import_core9.snapToGrid)(proposedTicks, gridTicks);
7131
+ const snappedSamples2 = (0, import_core9.ticksToSamples)(snappedTicks2, bpm, sampleRate);
7083
7132
  return { x: (snappedSamples2 - startSample) / samplesPerPixel, y: 0 };
7084
7133
  }
7085
7134
  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);
7135
+ const deltaTicks = (0, import_core9.samplesToTicks)(deltaSamples, bpm, sampleRate);
7136
+ const snappedTicks = (0, import_core9.snapToGrid)(deltaTicks, gridTicks);
7137
+ const snappedSamples = (0, import_core9.ticksToSamples)(snappedTicks, bpm, sampleRate);
7089
7138
  return { x: snappedSamples / samplesPerPixel, y: 0 };
7090
7139
  }
7091
7140
  };
@@ -7116,11 +7165,11 @@ var ClipInteractionProvider = ({
7116
7165
  const snapSamplePosition = (0, import_react40.useMemo)(() => {
7117
7166
  if (useBeatsSnap && beatsAndBars) {
7118
7167
  const { bpm, timeSignature, snapTo } = beatsAndBars;
7119
- const gridTicks = snapTo === "bar" ? (0, import_core9.ticksPerBar)(timeSignature) : (0, import_core9.ticksPerBeat)(timeSignature);
7168
+ const gridTicks = snapTo === "bar" ? (0, import_core10.ticksPerBar)(timeSignature) : (0, import_core10.ticksPerBeat)(timeSignature);
7120
7169
  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);
7170
+ const ticks = (0, import_core10.samplesToTicks)(samplePos, bpm, sampleRate);
7171
+ const snapped = (0, import_core10.snapToGrid)(ticks, gridTicks);
7172
+ return (0, import_core10.ticksToSamples)(snapped, bpm, sampleRate);
7124
7173
  };
7125
7174
  }
7126
7175
  if (useTimescaleSnap) {