import { EffectsFunction, SoundFontCache, TrackEffectsFunction } from '@waveform-playlist/playout'; export { EffectsFunction, TrackEffectsFunction } from '@waveform-playlist/playout'; import * as React$1 from 'react'; import React__default, { ReactNode, RefObject } from 'react'; import { PlayoutAdapter, PlaylistEngine, EngineState } from '@waveform-playlist/engine'; import { PeakData, Fade, MidiNoteData, ClipTrack, AnnotationData, AnnotationAction, WaveformDataObject, KeyboardShortcut, AnnotationActionOptions, RenderAnnotationItemProps, TrackSpectrogramOverrides, SpectrogramConfig, ColorMapValue, RenderMode } from '@waveform-playlist/core'; export { AnnotationData, AudioClip, ClipTrack, Fade, getShortcutLabel } from '@waveform-playlist/core'; import { WaveformPlaylistTheme, TimeFormat, RenderPlayheadFunction, TrackMenuItem, SnapTo } from '@waveform-playlist/ui-components'; export { TimeFormat } from '@waveform-playlist/ui-components'; import { MediaElementPlayout, FadeConfig } from '@waveform-playlist/media-element-playout'; import * as _dnd_kit_abstract from '@dnd-kit/abstract'; import { DragStartEvent, DragMoveEvent, DragEndEvent, PluginDescriptor, Modifier, DragDropManager, DragOperation, Plugins } from '@dnd-kit/abstract'; import { PointerSensor } from '@dnd-kit/dom'; import WaveformData from 'waveform-data'; /** * Pure helpers for the track-reorder drag preview. * * The preview is view-level only: it produces a DISPLAY order/geometry while * the engine's committed `tracks` order stays untouched until drop. */ interface TrackDragPreview { trackId: string; toIndex: number; } interface ClipPeaks { clipId: string; trackName: string; peaks: PeakData; startSample: number; durationSamples: number; fadeIn?: Fade; fadeOut?: Fade; midiNotes?: MidiNoteData[]; sampleRate?: number; offsetSamples?: number; } type TrackClipPeaks = ClipPeaks[]; interface WaveformTrack { src: string | AudioBuffer; name?: string; effects?: TrackEffectsFunction; } interface TrackState { name: string; muted: boolean; soloed: boolean; volume: number; pan: number; } /** Per-frame data passed to registered animation callbacks. */ interface FrameData { /** Raw engine time (for state/logic — NOT for visual positioning). */ readonly time: number; /** Visually-aligned time for DOM positioning: engine.getAudibleTime() while * playing (matches speaker output), raw time when resting. */ readonly visualTime: number; readonly sampleRate: number; readonly samplesPerPixel: number; } interface PlaybackAnimationContextValue { isPlaying: boolean; currentTime: number; currentTimeRef: React__default.RefObject; /** * Visually-aligned playback time (engine.getAudibleTime() while playing; * raw resting time otherwise). Kept current by the animation loop during playback * and by pause/seek/stop paths when stopped. Read from this for any visual * positioning that should match the audible output. */ visualTimeRef: React__default.RefObject; playbackStartTimeRef: React__default.RefObject; audioStartPositionRef: React__default.RefObject; /** Returns raw playback time from engine (auto-wraps at loop boundaries). */ getPlaybackTime: () => number; /** Current time of the adapter's AudioContext, in seconds. */ getAudioContextTime: () => number; /** * Returns the current adapter scheduler lookahead (Tone ~0.1s, native 0). * Use this for any audible-latency calculation that must match the playhead * (e.g., recording live-preview peak slicing). */ getLookAhead: () => number; /** * Returns the adapter AudioContext's output latency in seconds. * Use this for audible-latency calculations (e.g., recording live-preview peak slicing). */ getOutputLatency: () => number; /** Register a per-frame callback driven by the single animation loop. */ registerFrameCallback: (id: string, cb: (data: FrameData) => void) => void; /** Unregister a per-frame callback. */ unregisterFrameCallback: (id: string) => void; } interface PlaylistStateContextValue { continuousPlay: boolean; linkEndpoints: boolean; annotationsEditable: boolean; isAutomaticScroll: boolean; isLoopEnabled: boolean; annotations: AnnotationData[]; activeAnnotationId: string | null; selectionStart: number; selectionEnd: number; selectedTrackId: string | null; loopStart: number; loopEnd: number; /** Whether playback continues past the end of loaded audio instead of * auto-stopping (implies the fillViewport layout) */ indefinitePlayback: boolean; /** Whether the timeline visually fills the scroll container even when the * audio is shorter (layout only — no effect on playback) */ fillViewport: boolean; /** Whether undo is available */ canUndo: boolean; /** Whether redo is available */ canRedo: boolean; } interface PlaylistControlsContextValue { play: (startTime?: number, playDuration?: number) => Promise; pause: () => void; stop: () => void; seekTo: (time: number) => void; setCurrentTime: (time: number) => void; setTrackMute: (trackIndex: number, muted: boolean) => void; setTrackSolo: (trackIndex: number, soloed: boolean) => void; setTrackVolume: (trackIndex: number, volume: number) => void; setTrackPan: (trackIndex: number, pan: number) => void; /** Move a track to a new index in the vertical track order. Purely * organizational — playback is not interrupted. The reordered tracks * array flows back through onTracksChange. */ reorderTrack: (trackId: string, toIndex: number) => void; /** Internal: call after every track-reorder DRAG interaction ends * (committed or canceled) to force PlaylistVisualization to remount the * track-controls slots, discarding any @dnd-kit sortable-plugin DOM * corruption. Not needed for button-driven reorderTrack calls (they never * touch dnd-kit's DOM). See bumpTrackReorderEpoch in the provider. */ bumpTrackReorderEpoch: () => void; /** INTERNAL wiring for ClipInteractionProvider: publishes/clears the live * track-reorder drag preview. Custom drag integrations may call it, but * most consumers only ever READ trackDragPreview from usePlaylistData(). */ setTrackDragPreview: React__default.Dispatch>; setSelection: (start: number, end: number) => void; setSelectedTrackId: (trackId: string | null) => void; setTimeFormat: (format: TimeFormat) => void; formatTime: (seconds: number) => string; zoomIn: () => void; zoomOut: () => void; setMasterVolume: (volume: number) => void; setAutomaticScroll: (enabled: boolean) => void; setScrollContainer: (element: HTMLDivElement | null) => void; scrollContainerRef: React__default.RefObject; setContinuousPlay: (enabled: boolean) => void; setLinkEndpoints: (enabled: boolean) => void; setAnnotationsEditable: (enabled: boolean) => void; setAnnotations: React__default.Dispatch>; setActiveAnnotationId: (id: string | null) => void; setLoopEnabled: (enabled: boolean) => void; setLoopRegion: (start: number, end: number) => void; setLoopRegionFromSelection: () => void; clearLoopRegion: () => void; undo: () => void; redo: () => void; /** Mark a recording session active/inactive. While active: (1) the * end-of-audio auto-stop is suppressed so overdub playback runs past the * end of existing material, and (2) with an `armedTrackId`, that track's * existing content is transiently muted — punch-in recording replaces * whatever the take overlaps (#579), so the doomed material must not play * under the overdub; its previous mute state is restored when the session * ends (audio-only, the UI mute control is untouched). Wired automatically * from the Waveform / PlaylistVisualization `recordingState` prop; overdub * flows should also call it eagerly (before `play()`). */ setRecordingActive: (active: boolean, armedTrackId?: string | null) => void; } interface PlaylistDataContextValue { duration: number; audioBuffers: AudioBuffer[]; peaksDataArray: TrackClipPeaks[]; trackStates: TrackState[]; tracks: ClipTrack[]; sampleRate: number; waveHeight: number; timeScaleHeight: number; minimumPlaylistHeight: number; controls: { show: boolean; width: number; }; playoutRef: React__default.RefObject; samplesPerPixel: number; timeFormat: TimeFormat; masterVolume: number; canZoomIn: boolean; canZoomOut: boolean; barWidth: number; barGap: number; /** Draw bars with pill-shaped rounded caps (radius barWidth/2). */ roundedBars: boolean; /** Width in pixels of progress bars. Defaults to barWidth + barGap (fills gaps). */ progressBarWidth: number; /** Whether the playlist has finished loading all tracks */ isReady: boolean; /** Internal: incremented after every track-reorder drag interaction ends. * PlaylistVisualization folds this into the track-controls slot `key` to * force a remount, working around @dnd-kit sortable-plugin DOM corruption * (see bumpTrackReorderEpoch in PlaylistControlsContextValue). */ trackReorderEpoch: number; /** Non-null while a track-reorder drag is live: the dragged track and the * index it would drop at. Both playlist columns derive their display * layout from it; custom renderTrackControls consumers can read it to * mirror the preview in their own UI. */ trackDragPreview: TrackDragPreview | null; /** Whether tracks are rendered in mono mode */ mono: boolean; /** Ref set by useClipDragHandlers during boundary trim drags. * When true, loadAudio skips engine rebuild — visual updates flow via React state only. */ isDraggingRef: React__default.MutableRefObject; onTracksChange: ((tracks: ClipTrack[]) => void) | undefined; } interface WaveformPlaylistProviderProps { tracks: ClipTrack[]; timescale?: boolean; mono?: boolean; waveHeight?: number; samplesPerPixel?: number; zoomLevels?: number[]; automaticScroll?: boolean; theme?: Partial; controls?: { show: boolean; width: number; }; annotationList?: { annotations?: AnnotationData[]; editable?: boolean; isContinuousPlay?: boolean; linkEndpoints?: boolean; controls?: AnnotationAction[]; }; effects?: EffectsFunction; onReady?: () => void; /** Called when audio/engine initialization fails (e.g. a missing optional peer, * a throwing `createAdapter`, or an invalid `zoomLevels`/`samplesPerPixel`). The * provider already logs the error; use this to surface it in your UI. */ onError?: (err: Error) => void; /** @deprecated Use onAnnotationsChange instead */ onAnnotationUpdate?: (annotations: AnnotationData[]) => void; /** Callback when annotations are changed (drag, edit, etc.) */ onAnnotationsChange?: (annotations: AnnotationData[]) => void; /** Width in pixels of waveform bars. Default: 1 */ barWidth?: number; /** Spacing in pixels between waveform bars. Default: 0 */ barGap?: number; /** Draw bars with pill-shaped rounded caps (radius barWidth/2). Default: false */ roundedBars?: boolean; /** Width in pixels of progress bars. Default: barWidth + barGap (fills gaps). */ progressBarWidth?: number; /** Callback when engine clip operations (move, trim, split) change tracks. * The provider calls this so the parent can update its tracks state without * triggering a full engine rebuild. * * **Important:** The parent must pass the received `tracks` reference back as * the `tracks` prop (i.e. `setState(tracks)`). The provider uses reference * identity (`tracks === engineTracksRef.current`) to detect engine-originated * updates and skip the expensive `loadAudio` rebuild. */ onTracksChange?: (tracks: ClipTrack[]) => void; /** SoundFont cache for sample-based MIDI playback. When provided, MIDI clips * use SoundFont samples instead of PolySynth synthesis. */ soundFontCache?: SoundFontCache; /** When true, tracks render visually but the engine build is deferred. * Use this during progressive loading to avoid rebuilding the engine for * each track — flip to false when all tracks are ready for a single build. */ deferEngineRebuild?: boolean; /** Disable the automatic stop when the cursor reaches the end of the * longest track — the transport rolls until an explicit stop/pause * (DAW-style). Implies the fillViewport layout. Recording sessions * suppress the auto-stop automatically, so most recording UIs don't * need this. */ indefinitePlayback?: boolean; /** Extend the timeline (background + timescale) to fill the visible scroll * container even when the audio is shorter. Layout only. Recording UIs * typically want this so the empty timeline doesn't collapse to the audio * width. */ fillViewport?: boolean; /** Desired AudioContext sample rate. Creates a cross-browser AudioContext at * this rate via standardized-audio-context. Pre-computed peaks (.dat files) * render instantly when they match. On mismatch, falls back to worker. */ sampleRate?: number; /** Factory for a custom PlayoutAdapter. When omitted, the Tone.js engine * (@waveform-playlist/playout) is dynamically imported — so a custom adapter * lets a consumer use neither @waveform-playlist/playout nor tone. Called once * per engine rebuild; the provider owns and disposes the returned instance. * Pass a stable reference (module-level or useCallback) — it is read directly * inside the curated `loadAudio` effect, not via its dependency array. */ createAdapter?: () => PlayoutAdapter; children: ReactNode; } declare const WaveformPlaylistProvider: React__default.FC; declare const usePlaybackAnimation: () => PlaybackAnimationContextValue; declare const usePlaylistState: () => PlaylistStateContextValue; declare const usePlaylistControls: () => PlaylistControlsContextValue; declare const usePlaylistData: () => PlaylistDataContextValue; /** * Like {@link usePlaylistData} but returns `null` instead of throwing when there * is no WaveformPlaylistProvider ancestor. Use this in hooks/components that may * also run in the MediaElement path (MediaElementPlaylistProvider), where the * WebAudio playlist context is absent. */ declare const usePlaylistDataOptional: () => PlaylistDataContextValue | null; interface MediaElementTrackConfig { /** Audio source URL or Blob URL */ source: string; /** Pre-computed waveform data (required for visualization) */ waveformData: WaveformDataObject; /** Track name for display */ name?: string; /** Fade in configuration (requires audioContext on provider) */ fadeIn?: FadeConfig; /** Fade out configuration (requires audioContext on provider) */ fadeOut?: FadeConfig; } interface MediaElementAnimationContextValue { isPlaying: boolean; currentTime: number; currentTimeRef: React__default.RefObject; } interface MediaElementStateContextValue { continuousPlay: boolean; annotations: AnnotationData[]; activeAnnotationId: string | null; playbackRate: number; isAutomaticScroll: boolean; } interface MediaElementControlsContextValue { play: (startTime?: number) => void; pause: () => void; stop: () => void; seekTo: (time: number) => void; setPlaybackRate: (rate: number) => void; setContinuousPlay: (enabled: boolean) => void; setAnnotations: React__default.Dispatch>; setActiveAnnotationId: (id: string | null) => void; setAutomaticScroll: (enabled: boolean) => void; setScrollContainer: (element: HTMLDivElement | null) => void; scrollContainerRef: React__default.RefObject; } interface MediaElementDataContextValue { duration: number; peaksDataArray: TrackClipPeaks[]; sampleRate: number; waveHeight: number; timeScaleHeight: number; samplesPerPixel: number; playoutRef: React__default.RefObject; controls: { show: boolean; width: number; }; barWidth: number; barGap: number; /** Draw bars with pill-shaped rounded caps (radius barWidth/2). */ roundedBars: boolean; progressBarWidth: number; fadeIn?: FadeConfig; fadeOut?: FadeConfig; } interface MediaElementPlaylistProviderProps { /** Single track configuration with source URL and waveform data */ track: MediaElementTrackConfig; /** Initial samples per pixel (zoom level) */ samplesPerPixel?: number; /** Height of each waveform track */ waveHeight?: number; /** Show timescale */ timescale?: boolean; /** Initial playback rate (0.5 to 2.0) */ playbackRate?: number; /** Whether to preserve pitch when changing playback rate (default: true). * Set to false when using an external pitch processor like SoundTouch. */ preservesPitch?: boolean; /** Enable automatic scroll to keep playhead centered */ automaticScroll?: boolean; /** Theme configuration */ theme?: Partial; /** Track controls configuration */ controls?: { show: boolean; width: number; }; /** Annotations */ annotationList?: { annotations?: AnnotationData[]; isContinuousPlay?: boolean; }; /** Width of waveform bars */ barWidth?: number; /** Gap between waveform bars */ barGap?: number; /** Draw bars with pill-shaped rounded caps (radius barWidth/2). Default: false */ roundedBars?: boolean; /** Width of progress bars */ progressBarWidth?: number; /** Callback when annotations are changed (drag, edit, etc.) */ onAnnotationsChange?: (annotations: AnnotationData[]) => void; /** * AudioContext for Web Audio routing (fades, effects). * When provided, audio routes through Web Audio nodes: * HTMLAudioElement → MediaElementSourceNode → fadeGain → volumeGain → destination * * Without this, playback uses HTMLAudioElement directly (no fades or effects). * Each provider instance should use its own AudioContext or share one — * createMediaElementSource() is called once per audio element. */ audioContext?: AudioContext; /** Callback when audio is ready */ onReady?: () => void; /** Called when playout initialization fails (e.g. a missing optional peer, * a throwing `createPlayout`, or an `addTrack` error). The provider already * logs the error; use this to surface it in your UI. */ onError?: (err: Error) => void; /** Factory for a custom MediaElement playout. When omitted, the bundled engine * (@waveform-playlist/media-element-playout) is dynamically imported. */ createPlayout?: () => MediaElementPlayout; children: ReactNode; } /** * MediaElementPlaylistProvider * * A simplified playlist provider for single-track playback using HTMLAudioElement. * Key features: * - Pitch-preserving playback rate (0.5x - 2.0x) * - Pre-computed peaks visualization (no AudioBuffer needed) * - Simpler API than full WaveformPlaylistProvider * * Use this for: * - Language learning apps (speed control) * - Podcast players * - Single-track audio viewers * * For multi-track editing, use WaveformPlaylistProvider instead. */ declare const MediaElementPlaylistProvider: React__default.FC; declare const useMediaElementAnimation: () => MediaElementAnimationContextValue; declare const useMediaElementState: () => MediaElementStateContextValue; declare const useMediaElementControls: () => MediaElementControlsContextValue; declare const useMediaElementData: () => MediaElementDataContextValue; interface TimeFormatControls { timeFormat: TimeFormat; setTimeFormat: (format: TimeFormat) => void; formatTime: (seconds: number) => string; parseTime: (timeString: string) => number; } /** * Hook to manage time format state * * @example * ```tsx * const { timeFormat, setTimeFormat, formatTime, parseTime } = useTimeFormat(); * * * {formatTime(currentTime)} * seekTo(parseTime(e.target.value))} /> * ``` */ declare function useTimeFormat(): TimeFormatControls; interface ZoomControls { samplesPerPixel: number; zoomIn: () => void; zoomOut: () => void; canZoomIn: boolean; canZoomOut: boolean; } interface UseZoomControlsProps { engineRef: RefObject; initialSamplesPerPixel: number; } /** * Hook for managing zoom controls via PlaylistEngine delegation. * * zoomIn/zoomOut delegate to the engine. State is mirrored back from * the engine via onEngineState(), which the provider's statechange * handler calls on every engine event. * * samplesPerPixel updates use startTransition so React treats them as * non-urgent — during playback, animation RAF callbacks interleave * with the zoom re-render instead of being blocked. */ declare function useZoomControls({ engineRef, initialSamplesPerPixel, }: UseZoomControlsProps): ZoomControls & { onEngineState: (state: EngineState) => void; }; interface UseMasterVolumeProps { engineRef: RefObject; initialVolume?: number; } interface MasterVolumeControls { masterVolume: number; setMasterVolume: (volume: number) => void; /** Ref holding the current masterVolume for seeding a fresh engine. */ masterVolumeRef: React.RefObject; } /** * Hook for managing master volume via PlaylistEngine delegation. * * setMasterVolume delegates to the engine. State is mirrored back from * the engine via onEngineState(), which the provider's statechange * handler calls on every engine event. */ declare function useMasterVolume({ engineRef, initialVolume, }: UseMasterVolumeProps): MasterVolumeControls & { onEngineState: (state: EngineState) => void; }; interface UseClipDragHandlersOptions { tracks: ClipTrack[]; onTracksChange: (tracks: ClipTrack[]) => void; samplesPerPixel: number; engineRef: React__default.RefObject; /** Ref toggled during boundary trim drags. When true, the provider's loadAudio * skips engine rebuilds so engine keeps original clip positions. On drag end, * engine.trimClip() commits the final delta. Obtain from usePlaylistData(). */ isDraggingRef: React__default.MutableRefObject; /** Optional function that snaps a sample position to the nearest grid position. * Used for boundary trim snapping (move snapping is handled by the SnapToGridModifier). */ snapSamplePosition?: (samplePosition: number) => number; } /** * Custom hook for handling clip drag operations (movement and trimming) * * Provides drag handlers for use with @dnd-kit/react DragDropProvider. * Handles both clip movement (dragging entire clips) and boundary trimming (adjusting clip edges). * * Collision detection for clip moves is handled by `ClipCollisionModifier` (passed to DragDropProvider). * * **Move:** `onDragEnd` delegates to `engine.moveClip()` in one shot. * * **Trim:** `onDragMove` updates React state per-frame via `onTracksChange` for smooth * visual feedback (using cumulative deltas from the original clip snapshot). `isDraggingRef` * prevents loadAudio from rebuilding the engine during the drag, so the engine keeps the * original clip positions. On drag end, `engine.trimClip()` commits the final delta. * * @example * ```tsx * const { onDragStart, onDragMove, onDragEnd } = useClipDragHandlers({ * tracks, * onTracksChange: setTracks, * samplesPerPixel, * engineRef: playoutRef, * isDraggingRef, * }); * * return ( * * * * ); * ``` */ declare function useClipDragHandlers({ tracks, onTracksChange, samplesPerPixel, engineRef, isDraggingRef, snapSamplePosition, }: UseClipDragHandlersOptions): { onDragStart: (event: Parameters[0]) => void; onDragMove: (event: Parameters[0]) => void; onDragEnd: (event: Parameters[0]) => void; }; interface UseAnnotationDragHandlersOptions { annotations: AnnotationData[]; onAnnotationsChange: (annotations: AnnotationData[]) => void; samplesPerPixel: number; /** Sample rate for pixel-to-time conversion. Providers pass the real rate from * context; defaults to 48000 (the engine default) for out-of-provider usage. */ sampleRate?: number; duration: number; linkEndpoints: boolean; } /** * Custom hook for handling annotation drag operations (boundary trimming) * * Provides drag handlers for use with @dnd-kit/react DragDropProvider. * Handles annotation boundary resizing with linked endpoints support. * * @example * ```tsx * const { onDragStart, onDragMove, onDragEnd } = useAnnotationDragHandlers({ * annotations, * onAnnotationsChange: setAnnotations, * samplesPerPixel, * duration, * linkEndpoints, * }); * * return ( * * {renderAnnotations()} * * ); * ``` */ declare function useAnnotationDragHandlers({ annotations, onAnnotationsChange, samplesPerPixel, sampleRate, duration, linkEndpoints, }: UseAnnotationDragHandlersOptions): { onDragStart: (event: Parameters[0]) => void; onDragMove: (event: Parameters[0]) => void; onDragEnd: (event: Parameters[0]) => void; }; /** * Hook for configuring @dnd-kit sensors for clip dragging * * Provides consistent drag activation behavior across all examples. * Always overrides PointerSensor defaults with custom activation constraints: * - Default mode: distance-based activation (1px) for all pointer types * - Touch-optimized mode: delay-based activation for touch (250ms), * distance-based for mouse/pen */ interface DragSensorOptions { /** * Enable mobile-optimized touch handling with delay-based activation. * When true, touch events get delay-based activation while mouse/pen get distance-based. * When false (default), all pointer types use distance-based activation (1px). */ touchOptimized?: boolean; /** * Delay in milliseconds before touch drag activates (only when touchOptimized is true). * Default: 250ms - long enough to distinguish from scroll intent */ touchDelay?: number; /** * Distance tolerance during touch delay (only when touchOptimized is true). * If finger moves more than this during delay, drag is cancelled. * Default: 5px - allows slight finger movement */ touchTolerance?: number; /** * Distance in pixels before mouse drag activates. * Default: 1px for immediate feedback on desktop */ mouseDistance?: number; } /** * Returns configured sensors for @dnd-kit drag operations * * @param options - Configuration options for drag sensors * @returns Array of sensor constructors/descriptors for DragDropProvider's sensors prop * * @example * // Desktop-optimized (default — 1px distance activation for all pointer types) * const sensors = useDragSensors(); * * @example * // Mobile-optimized with custom touch delay * const sensors = useDragSensors({ touchOptimized: true, touchDelay: 300 }); */ declare function useDragSensors(options?: DragSensorOptions): (typeof PointerSensor | PluginDescriptor)[]; interface UseClipSplittingOptions { tracks: ClipTrack[]; samplesPerPixel: number; engineRef: React__default.RefObject; } interface UseClipSplittingResult { splitClipAtPlayhead: () => boolean; splitClipAt: (trackIndex: number, clipIndex: number, splitTime: number) => boolean; } /** * Hook for splitting clips at the playhead or at a specific time * * Splitting delegates to `engine.splitClip()` — the engine handles clip creation, * adapter sync, and emits statechange. The provider's statechange handler propagates * the updated tracks to the parent via `onTracksChange`. * * @param options - Configuration options * @returns Object with split functions * * @example * ```tsx * const { splitClipAtPlayhead } = useClipSplitting({ * tracks, * samplesPerPixel, * engineRef: playoutRef, * }); * * // In keyboard handler * const handleKeyPress = (e: KeyboardEvent) => { * if (e.key === 's' || e.key === 'S') { * splitClipAtPlayhead(); * } * }; * ``` */ declare const useClipSplitting: (options: UseClipSplittingOptions) => UseClipSplittingResult; interface UseKeyboardShortcutsOptions { shortcuts: KeyboardShortcut[]; enabled?: boolean; } /** * Hook for managing keyboard shortcuts * * @param options - Configuration options * * @example * ```tsx * useKeyboardShortcuts({ * shortcuts: [ * { * key: ' ', * action: togglePlayPause, * description: 'Play/Pause', * preventDefault: true, * }, * { * key: 's', * action: splitClipAtPlayhead, * description: 'Split clip at playhead', * preventDefault: true, * }, * ], * }); * ``` */ declare const useKeyboardShortcuts: (options: UseKeyboardShortcutsOptions) => void; interface UsePlaybackShortcutsOptions { /** * Enable the shortcuts. Defaults to true. */ enabled?: boolean; /** * Additional shortcuts to include alongside the default playback shortcuts. */ additionalShortcuts?: KeyboardShortcut[]; /** * Override default shortcuts. If provided, only these shortcuts will be used. */ shortcuts?: KeyboardShortcut[]; } interface UsePlaybackShortcutsReturn { /** Rewind to the beginning (time = 0) */ rewindToStart: () => void; /** Toggle play/pause */ togglePlayPause: () => void; /** Stop playback and return to start position */ stopPlayback: () => void; /** The list of active keyboard shortcuts */ shortcuts: KeyboardShortcut[]; } /** * Hook that provides common playback keyboard shortcuts for the playlist. * * Default shortcuts: * - `Space` - Toggle play/pause * - `Escape` - Stop playback * - `0` - Rewind to start (seek to time 0) * * @example * ```tsx * // Basic usage - enables default shortcuts * usePlaybackShortcuts(); * * // With additional custom shortcuts * usePlaybackShortcuts({ * additionalShortcuts: [ * { key: 's', action: splitClipAtPlayhead, description: 'Split clip' }, * ], * }); * * // Completely override shortcuts * usePlaybackShortcuts({ * shortcuts: [ * { key: 'Home', action: rewindToStart, description: 'Go to start' }, * ], * }); * ``` */ declare const usePlaybackShortcuts: (options?: UsePlaybackShortcutsOptions) => UsePlaybackShortcutsReturn; interface UseAnnotationKeyboardControlsOptions { annotations: AnnotationData[]; activeAnnotationId: string | null; onAnnotationsChange: (annotations: AnnotationData[]) => void; /** Callback to set the active annotation ID for selection */ onActiveAnnotationChange?: (id: string | null) => void; duration: number; linkEndpoints: boolean; /** Whether continuous play is enabled (affects playback duration) */ continuousPlay?: boolean; enabled?: boolean; /** Optional: scroll container ref for auto-scrolling to annotation */ scrollContainerRef?: React.RefObject; /** Optional: callback to start playback at a time with optional duration */ onPlay?: (startTime: number, duration?: number) => void; /** * Pixels-per-sample for auto-scroll positioning. Falls back to the * WaveformPlaylistProvider context when omitted (WebAudio path). Pass * explicitly when used outside that provider (e.g. the MediaElement path). */ samplesPerPixel?: number; /** Sample rate for auto-scroll positioning. Falls back to context. */ sampleRate?: number; } /** * Hook for keyboard-based annotation navigation and boundary editing * * Navigation Shortcuts: * - ArrowUp / ArrowLeft = Select previous annotation * - ArrowDown / ArrowRight = Select next annotation * - Home = Select first annotation * - End = Select last annotation * - Escape = Deselect annotation * - Enter = Play selected annotation * * Boundary Editing Shortcuts (requires active annotation): * - [ = Move start boundary earlier (left) * - ] = Move start boundary later (right) * - Shift+[ = Move end boundary earlier (left) * - Shift+] = Move end boundary later (right) * * Respects linkEndpoints and continuousPlay settings. * * @example * ```tsx * useAnnotationKeyboardControls({ * annotations, * activeAnnotationId, * onAnnotationsChange: setAnnotations, * onActiveAnnotationChange: setActiveAnnotationId, * duration, * linkEndpoints, * }); * ``` */ declare function useAnnotationKeyboardControls({ annotations, activeAnnotationId, onAnnotationsChange, onActiveAnnotationChange, duration, linkEndpoints, continuousPlay, enabled, scrollContainerRef, onPlay, samplesPerPixel: samplesPerPixelProp, sampleRate: sampleRateProp, }: UseAnnotationKeyboardControlsOptions): { moveStartBoundary: (delta: number) => void; moveEndBoundary: (delta: number) => void; selectPrevious: () => void; selectNext: () => void; selectFirst: () => void; selectLast: () => void; clearSelection: () => void; scrollToAnnotation: (annotationId: string) => void; playActiveAnnotation: () => void; }; declare const PlayButton: React__default.FC<{ className?: string; }>; declare const PauseButton: React__default.FC<{ className?: string; }>; declare const StopButton: React__default.FC<{ className?: string; }>; declare const RewindButton: React__default.FC<{ className?: string; }>; declare const FastForwardButton: React__default.FC<{ className?: string; }>; declare const SkipBackwardButton: React__default.FC<{ skipAmount?: number; className?: string; }>; declare const SkipForwardButton: React__default.FC<{ skipAmount?: number; className?: string; }>; declare const LoopButton: React__default.FC<{ className?: string; }>; declare const SetLoopRegionButton: React__default.FC<{ className?: string; }>; interface ClearAllButtonProps { onClearAll: () => void; label?: string; className?: string; } declare const ClearAllButton: React__default.FC; declare const ZoomInButton: React__default.FC<{ className?: string; disabled?: boolean; }>; declare const ZoomOutButton: React__default.FC<{ className?: string; disabled?: boolean; }>; /** * Master volume control that uses the playlist context */ declare const MasterVolumeControl: React__default.FC<{ className?: string; }>; /** * Time format selector that uses the playlist context */ declare const TimeFormatSelect: React__default.FC<{ className?: string; }>; /** * Audio position display that uses the playlist context. * Updates via the shared animation frame registry — no own rAF loop. * Direct DOM manipulation avoids React re-renders. */ declare const AudioPosition: React__default.FC<{ className?: string; }>; /** * Selection time inputs that use the playlist context */ declare const SelectionTimeInputs: React__default.FC<{ className?: string; }>; /** * Automatic scroll checkbox that uses the playlist context * Uses split contexts to avoid re-rendering during animation */ declare const AutomaticScrollCheckbox: React__default.FC<{ className?: string; }>; /** * Continuous play checkbox that uses the playlist context. * Must be used within . */ declare const ContinuousPlayCheckbox: React__default.FC<{ className?: string; }>; /** * Link endpoints checkbox that uses the playlist context. * Must be used within . */ declare const LinkEndpointsCheckbox: React__default.FC<{ className?: string; }>; /** * Editable annotations checkbox that uses the playlist context. * Must be used within . */ declare const EditableCheckbox: React__default.FC<{ className?: string; }>; /** * Download annotations button that uses the playlist context. * Must be used within . */ declare const DownloadAnnotationsButton: React__default.FC<{ filename?: string; className?: string; }>; /** * Shared annotation types used across Waveform components */ /** * Custom function to generate the label shown on annotation boxes in the waveform. * Receives the annotation data and its index in the list, returns a string label. * Default behavior: displays annotation.id */ type GetAnnotationBoxLabelFn = (annotation: AnnotationData, index: number) => string; /** * Callback when annotations are updated (e.g., boundaries dragged). * Called with the full updated annotations array. */ type OnAnnotationUpdateFn = (annotations: AnnotationData[]) => void; interface WaveformProps { renderTrackControls?: (trackIndex: number) => ReactNode; /** Custom render function for timescale tick labels. `label` is a formatted string * (bar/beat notation like "2.3" in beats mode, or "m:ss" in temporal mode). */ renderTick?: (label: string, pixelPosition: number) => ReactNode; /** @deprecated Use `renderTick` instead. */ renderTimestamp?: (timeMs: number, pixelPosition: number) => ReactNode; /** Custom playhead render function. Receives position (pixels) and color from theme. */ renderPlayhead?: RenderPlayheadFunction; annotationControls?: AnnotationAction[]; annotationListConfig?: AnnotationActionOptions; annotationTextHeight?: number; /** * Custom render function for annotation items in the text list. * Use this to completely customize how each annotation is displayed. */ renderAnnotationItem?: (props: RenderAnnotationItemProps) => ReactNode; /** * Custom function to generate the label shown on annotation boxes in the waveform. * Receives the annotation data and its index, returns a string label. * Default: annotation.id */ getAnnotationBoxLabel?: GetAnnotationBoxLabelFn; /** Where to position the active annotation when auto-scrolling: 'center', 'start', 'end', or 'nearest'. Defaults to 'center'. */ scrollActivePosition?: ScrollLogicalPosition; /** Which scrollable containers to scroll: 'nearest' (only the annotation list) or 'all' (including viewport). Defaults to 'nearest'. */ scrollActiveContainer?: 'nearest' | 'all'; className?: string; showClipHeaders?: boolean; interactiveClips?: boolean; showFades?: boolean; /** * Enable mobile-optimized touch interactions. * When true, increases touch target sizes for clip boundaries. * Use with useDragSensors({ touchOptimized: true }) for best results. */ touchOptimized?: boolean; /** Callback when a track's close button is clicked. Only renders close button when provided. */ onRemoveTrack?: (trackIndex: number) => void; /** Enable vertical track reordering: a drag grip + move up/down buttons on * each default track control panel. Drag requires ClipInteractionProvider * (the ambient DragDropProvider); the buttons work regardless. Default: false. */ trackReordering?: boolean; recordingState?: { isRecording: boolean; trackId: string; startSample: number; durationSamples: number; peaks: (Int8Array | Int16Array)[]; bits: 8 | 16; /** * Latency offset (seconds) to skip in the live preview. Absolute replacement * for the auto-computed outputLatency + lookAhead value. Pass the same value * given to useIntegratedRecording so preview and finalized clip match. */ latencyOffset?: number; }; } /** * Waveform visualization component that uses the playlist context. * * Composes PlaylistVisualization (waveform + tracks) and * PlaylistAnnotationList (annotation text list below the waveform). */ declare const Waveform: React__default.FC; interface MediaElementWaveformProps { /** Height in pixels for the annotation text list */ annotationTextHeight?: number; /** Custom function to generate the label shown on annotation boxes */ getAnnotationBoxLabel?: GetAnnotationBoxLabelFn; /** * Custom render function for annotation items in the text list. * When provided, completely replaces the default annotation item rendering. * Use this to customize the appearance of each annotation (e.g., add furigana). */ renderAnnotationItem?: (props: RenderAnnotationItemProps) => React__default.ReactNode; /** Whether annotation boundaries can be edited by dragging. Defaults to false. */ editable?: boolean; /** Whether dragging one annotation boundary also moves the adjacent annotation's boundary. Defaults to false. */ linkEndpoints?: boolean; /** * Callback when annotations are updated (e.g., boundaries dragged). * Called with the full updated annotations array. */ onAnnotationUpdate?: OnAnnotationUpdateFn; /** Where to position the active annotation when auto-scrolling: 'center', 'start', 'end', or 'nearest'. Defaults to 'center'. */ scrollActivePosition?: ScrollLogicalPosition; /** Which scrollable containers to scroll: 'nearest' (only the annotation list) or 'all' (including viewport). Defaults to 'nearest'. */ scrollActiveContainer?: 'nearest' | 'all'; /** Custom playhead render function. Receives position, color, and animation refs for smooth 60fps animation. */ renderPlayhead?: RenderPlayheadFunction; /** Show fade in/out overlays on the waveform. Defaults to false. */ showFades?: boolean; className?: string; } /** * Simplified Waveform component for MediaElementPlaylistProvider * * This is a stripped-down version of Waveform that works with the * MediaElement context. It supports: * - Single track visualization * - Click to seek * - Annotation display and click-to-play * - Playhead animation * * For multi-track editing, use the full Waveform with WaveformPlaylistProvider. */ declare const MediaElementWaveform: React__default.FC; interface MediaElementPlaylistProps { /** Custom function to generate the label shown on annotation boxes */ getAnnotationBoxLabel?: GetAnnotationBoxLabelFn; /** Whether annotation boundaries can be edited by dragging. Defaults to false. */ editable?: boolean; /** Whether dragging one annotation boundary also moves the adjacent annotation's boundary. Defaults to false. */ linkEndpoints?: boolean; /** * Callback when annotations are updated (e.g., boundaries dragged). * Called with the full updated annotations array. */ onAnnotationUpdate?: OnAnnotationUpdateFn; /** Custom playhead render function. Receives position, color, and animation refs for smooth 60fps animation. */ renderPlayhead?: RenderPlayheadFunction; /** Show fade in/out overlays on the waveform. Defaults to false. */ showFades?: boolean; className?: string; } /** * Standalone waveform + annotation boxes component for MediaElementPlaylistProvider. * * Renders the waveform visualization, annotation boxes, selection, and playhead. * Does NOT render the annotation text list — use `MediaElementAnnotationList` for that. * * Must be used inside a `MediaElementPlaylistProvider`. * * This component can be placed independently in consumer layouts, allowing the * waveform and annotation list to be positioned separately (e.g., in different * panels or with custom elements between them). */ declare const MediaElementPlaylist: React__default.FC; interface MediaElementAnnotationListProps { /** Height in pixels for the annotation text list */ height?: number; /** * Custom render function for annotation items in the text list. * When provided, completely replaces the default annotation item rendering. */ renderAnnotationItem?: (props: RenderAnnotationItemProps) => React__default.ReactNode; /** * Callback when annotations are updated (e.g., text edited). * Called with the full updated annotations array. */ onAnnotationUpdate?: OnAnnotationUpdateFn; /** Whether annotation text can be edited. Defaults to false. */ editable?: boolean; /** * Action controls to show on each annotation item (e.g., delete, split). * Only rendered when `editable` is true. */ controls?: AnnotationAction[]; /** * Override annotation list config. Falls back to context values * `{ linkEndpoints: false, continuousPlay }` if not provided. */ annotationListConfig?: AnnotationActionOptions; /** Where to position the active annotation when auto-scrolling. Defaults to 'center'. */ scrollActivePosition?: ScrollLogicalPosition; /** Which scrollable containers to scroll: 'nearest' or 'all'. Defaults to 'nearest'. */ scrollActiveContainer?: 'nearest' | 'all'; } /** * Standalone annotation text list component for MediaElementPlaylistProvider. * * Requires @waveform-playlist/annotations with AnnotationProvider. * Throws if used without `` wrapping the component tree. */ declare const MediaElementAnnotationList: React__default.FC; interface PlaylistVisualizationProps { renderTrackControls?: (trackIndex: number) => ReactNode; renderTick?: (label: string, pixelPosition: number) => ReactNode; /** Custom playhead render function. Receives position (pixels) and color from theme. */ renderPlayhead?: RenderPlayheadFunction; annotationControls?: AnnotationAction[]; /** * Custom function to generate the label shown on annotation boxes in the waveform. * Receives the annotation data and its index, returns a string label. * Default: annotation.id */ getAnnotationBoxLabel?: GetAnnotationBoxLabelFn; className?: string; showClipHeaders?: boolean; interactiveClips?: boolean; showFades?: boolean; /** * Enable mobile-optimized touch interactions. * When true, increases touch target sizes for clip boundaries. * Use with useDragSensors({ touchOptimized: true }) for best results. */ touchOptimized?: boolean; /** Callback when a track's close button is clicked. Only renders close button when provided. */ onRemoveTrack?: (trackIndex: number) => void; recordingState?: { isRecording: boolean; trackId: string; startSample: number; durationSamples: number; peaks: (Int8Array | Int16Array)[]; bits: 8 | 16; /** * Latency offset (seconds) to skip in the live preview. Absolute replacement * for the auto-computed outputLatency + lookAhead value. Pass the same value * given to useIntegratedRecording so preview and finalized clip match. */ latencyOffset?: number; }; /** Enable vertical track reordering: a drag grip + move up/down buttons on * each default track control panel. Drag requires ClipInteractionProvider * (the ambient DragDropProvider); the buttons work regardless. Default: false. */ trackReordering?: boolean; } /** * Standalone playlist visualization component (WebAudio version). * * Renders the waveform tracks, timescale, annotations boxes, selection, * playhead, loop regions, and track controls — everything that lives * inside plus wrapping providers. * * Does NOT render AnnotationText (the annotation list below the waveform). * Pair with PlaylistAnnotationList for a full annotation editing UI. */ declare const PlaylistVisualization: React__default.FC; interface PlaylistAnnotationListProps { /** Height in pixels for the annotation text list */ height?: number; /** * Custom render function for annotation items in the text list. * When provided, completely replaces the default annotation item rendering. */ renderAnnotationItem?: (props: RenderAnnotationItemProps) => React__default.ReactNode; /** * Callback when annotations are updated (e.g., text edited). * Called with the full updated annotations array. */ onAnnotationUpdate?: OnAnnotationUpdateFn; /** * Action controls to show on each annotation item (e.g., delete, split). * Only rendered when `annotationsEditable` is true in context. */ controls?: AnnotationAction[]; /** * Override annotation list config. Falls back to context values * `{ linkEndpoints, continuousPlay }` if not provided. */ annotationListConfig?: AnnotationActionOptions; /** Where to position the active annotation when auto-scrolling. Defaults to 'center'. */ scrollActivePosition?: ScrollLogicalPosition; /** Which scrollable containers to scroll: 'nearest' or 'all'. Defaults to 'nearest'. */ scrollActiveContainer?: 'nearest' | 'all'; } /** * Standalone annotation text list component for WaveformPlaylistProvider (WebAudio). * * Requires @waveform-playlist/annotations with AnnotationProvider. * Throws if used without `` wrapping the component tree. */ declare const PlaylistAnnotationList: React__default.FC; interface KeyboardShortcutsProps { /** Enable default playback shortcuts (Space, Escape, 0). Defaults to false. */ playback?: boolean; /** Enable clip splitting shortcut ('s' key). Defaults to false. */ clipSplitting?: boolean; /** Enable annotation keyboard controls (arrow nav, boundary editing). Defaults to false. */ annotations?: boolean; /** Enable undo/redo shortcuts (Cmd/Ctrl+Z, Cmd/Ctrl+Shift+Z). Defaults to false. */ undo?: boolean; /** Additional shortcuts appended to the defaults. */ additionalShortcuts?: KeyboardShortcut[]; } /** * Self-closing component that sets up keyboard shortcuts for the playlist. * Must be rendered inside a WaveformPlaylistProvider. * * @example * ```tsx * * * * * ``` */ declare const KeyboardShortcuts: React__default.FC; interface SortableTrackControlsRenderProps { /** Attach to the slot wrapper element (the sortable item). */ ref: (element: Element | null) => void; /** Attach to the drag grip element. */ handleRef: (element: Element | null) => void; isDragSource: boolean; } interface SortableTrackControlsProps { trackId: string; index: number; disabled?: boolean; children: (props: SortableTrackControlsRenderProps) => React__default.ReactNode; } /** * Registers a track-controls row as a vertical sortable item in the ambient * DragDropProvider (ClipInteractionProvider). The per-source modifiers * REPLACE the provider's clip modifiers for this operation, so track drags * are vertical-only and skip clip collision/snap. Data kind 'track-reorder' * is the discriminator the shared drag handlers branch on. */ declare const SortableTrackControls: React__default.FC; /** * Props the browser package passes to the AnnotationText component. * Mirrors what PlaylistAnnotationList and MediaElementAnnotationList actually use. */ interface AnnotationTextIntegrationProps { annotations: AnnotationData[]; activeAnnotationId?: string; shouldScrollToActive?: boolean; scrollActivePosition?: ScrollLogicalPosition; scrollActiveContainer?: 'nearest' | 'all'; editable?: boolean; controls?: AnnotationAction[]; annotationListConfig?: AnnotationActionOptions; height?: number; onAnnotationUpdate?: (updatedAnnotations: AnnotationData[]) => void; renderAnnotationItem?: (props: RenderAnnotationItemProps) => React.ReactNode; } /** * Props the browser package passes to the AnnotationBox component. * Mirrors what PlaylistVisualization and MediaElementPlaylist actually use. */ interface AnnotationBoxIntegrationProps { annotationId: string; annotationIndex: number; startPosition: number; endPosition: number; label?: string; color?: string; isActive?: boolean; onClick?: () => void; editable?: boolean; } /** * Props the browser package passes to the AnnotationBoxesWrapper component. * Mirrors what PlaylistVisualization and MediaElementPlaylist actually use. */ interface AnnotationBoxesWrapperIntegrationProps { children?: React.ReactNode; height?: number; width?: number; } /** * Interface for annotation integration provided by @waveform-playlist/annotations. * * The browser package defines what it needs, and the optional annotations package * provides it via . */ interface AnnotationIntegration { parseAeneas: (data: unknown) => AnnotationData; serializeAeneas: (annotation: AnnotationData) => unknown; AnnotationText: React.ComponentType; AnnotationBox: React.ComponentType; AnnotationBoxesWrapper: React.ComponentType; ContinuousPlayCheckbox: React.ComponentType<{ checked: boolean; onChange: (checked: boolean) => void; className?: string; }>; LinkEndpointsCheckbox: React.ComponentType<{ checked: boolean; onChange: (checked: boolean) => void; className?: string; }>; EditableCheckbox: React.ComponentType<{ checked: boolean; onChange: (checked: boolean) => void; className?: string; }>; DownloadAnnotationsButton: React.ComponentType<{ annotations: AnnotationData[]; filename?: string; className?: string; }>; } declare const AnnotationIntegrationProvider: React$1.Provider; /** * Hook to access annotation integration provided by @waveform-playlist/annotations. * Throws if used without wrapping the component tree. * * Follows the Kent C. Dodds pattern: * https://kentcdodds.com/blog/how-to-use-react-context-effectively */ declare function useAnnotationIntegration(): AnnotationIntegration; /** * Single-call canvas registration shape. Consolidates the OffscreenCanvas * transfer and per-canvas metadata that earlier required two separate * registration paths. * * Provider/orchestrator look up trackId from clipId and derive * globalPixelOffset = chunkIndex * MAX_CANVAS_WIDTH. */ interface SpectrogramCanvasRegistration { canvasId: string; canvas: OffscreenCanvas; clipId: string; channelIndex: number; chunkIndex: number; widthPx: number; heightPx: number; } interface SpectrogramIntegration { trackSpectrogramOverrides: Map; spectrogramConfig?: SpectrogramConfig; spectrogramColorMap?: ColorMapValue; setTrackRenderMode: (trackId: string, mode: RenderMode) => void; setTrackSpectrogramConfig: (trackId: string, config: SpectrogramConfig, colorMap?: ColorMapValue) => void; /** Single-canvas registration. OffscreenCanvas is non-transferable — call once per canvas. */ registerSpectrogramCanvas: (reg: SpectrogramCanvasRegistration) => void; unregisterSpectrogramCanvas: (canvasId: string) => void; /** Render spectrogram menu items for a track's context menu */ renderMenuItems?: (props: { renderMode: string; onRenderModeChange: (mode: RenderMode) => void; onOpenSettings: () => void; onClose?: () => void; }) => TrackMenuItem[]; /** Settings modal component provided by the spectrogram package */ SettingsModal?: React.ComponentType<{ open: boolean; onClose: () => void; config: SpectrogramConfig; colorMap: ColorMapValue; onApply: (config: SpectrogramConfig, colorMap: ColorMapValue) => void; }>; /** Get color lookup table for a color map name */ getColorMap: (name: ColorMapValue) => Uint8Array; /** Get frequency scale function for a scale name */ getFrequencyScale: (name: string) => (f: number, minF: number, maxF: number) => number; } declare const SpectrogramIntegrationProvider: React$1.Provider; /** * Hook to access spectrogram integration provided by @waveform-playlist/spectrogram. * Throws if used without wrapping the component tree. * * Follows the Kent C. Dodds pattern: * https://kentcdodds.com/blog/how-to-use-react-context-effectively */ declare function useSpectrogramIntegration(): SpectrogramIntegration; interface ClipInteractionProviderProps { /** Enable snap-to-grid for clip moves and boundary trims. When true, * auto-detects beats snapping from BeatsAndBarsProvider context * (if present with scaleMode="beats" and snapTo!="off"), otherwise * falls back to timescale-based snapping. Default: false. */ snap?: boolean; touchOptimized?: boolean; children: React__default.ReactNode; } declare const ClipInteractionProvider: React__default.FC; declare function useClipInteractionEnabled(): boolean; interface ClipCollisionOptions { tracks: ClipTrack[]; samplesPerPixel: number; } /** * Modifier that constrains clip drag movement to prevent overlaps. * * For clip move operations: constrains horizontal transform to valid positions * using the engine's collision detection. * * For boundary trim operations: returns zero transform because visual feedback * comes from React state updates resizing the clip, not from CSS translate. */ declare class ClipCollisionModifier extends Modifier, ClipCollisionOptions> { apply(operation: DragOperation): { x: number; y: number; }; static configure: (options: ClipCollisionOptions) => _dnd_kit_abstract.PluginDescriptor; } interface SnapToGridBeatsOptions { mode: 'beats'; snapTo: SnapTo; bpm: number; timeSignature: [number, number]; samplesPerPixel: number; sampleRate: number; } interface SnapToGridTimescaleOptions { mode: 'timescale'; gridSamples: number; samplesPerPixel: number; } type SnapToGridOptions = SnapToGridBeatsOptions | SnapToGridTimescaleOptions; /** * dnd-kit modifier that quantizes clip drag movement to a grid. * * Two modes: * - "beats": Snaps to beat/bar grid using PPQN tick space for exact musical timing. * - "timescale": Snaps to a sample-based grid derived from timescale markers. * * Designed to compose with ClipCollisionModifier — snap first, * then collision constrains the snapped position. */ declare class SnapToGridModifier extends Modifier, SnapToGridOptions> { apply(operation: DragOperation): { x: number; y: number; }; static configure: (options: SnapToGridBeatsOptions | SnapToGridTimescaleOptions) => _dnd_kit_abstract.PluginDescriptor; } /** * DragDropProvider plugins customizer that disables the Feedback plugin's drop animation. * * Without this, the Feedback plugin animates the dragged element back to its original * position on drop, causing a visual snap-back before React re-renders at the new position. * * Usage: * ```tsx * * ``` */ declare const noDropAnimationPlugins: (defaults: Plugins) => Plugins; /** * Waveform Data Loader * * Utilities for loading pre-computed waveform data in waveform-data.js format. * Supports both binary (.dat) and JSON formats from BBC's audiowaveform tool. */ /** * Load waveform data from a .dat or .json file * * @param src - URL to waveform data file (.dat or .json) * @returns WaveformData instance */ declare function loadWaveformData(src: string): Promise; /** * Convert WaveformData to our internal Peaks format * * @param waveformData - WaveformData instance from waveform-data.js * @param channelIndex - Channel index (0 for mono/left, 1 for right) * @returns Peaks data with alternating min/max values, preserving original bit depth */ declare function waveformDataToPeaks(waveformData: WaveformData, channelIndex?: number): { data: Int8Array | Int16Array; bits: 8 | 16; length: number; sampleRate: number; }; /** * Load waveform data file and convert to Peaks format in one step * * @param src - URL to waveform data file (.dat or .json) * @param channelIndex - Channel index (default: 0) * @returns Peaks data ready for rendering */ declare function loadPeaksFromWaveformData(src: string, channelIndex?: number): Promise<{ data: Int8Array | Int16Array; bits: 8 | 16; length: number; sampleRate: number; }>; /** * Get metadata from waveform data file without converting to peaks * * @param src - URL to waveform data file * @returns Metadata (sample rate, channels, duration, bits, etc.) */ declare function getWaveformDataMetadata(src: string): Promise<{ sampleRate: number; channels: number; duration: number; samplesPerPixel: number; length: number; bits: 8 | 16; }>; export { type AnnotationIntegration, AnnotationIntegrationProvider, AudioPosition, AutomaticScrollCheckbox, ClearAllButton, type ClearAllButtonProps, ClipCollisionModifier, ClipInteractionProvider, type ClipInteractionProviderProps, ContinuousPlayCheckbox, DownloadAnnotationsButton, EditableCheckbox, 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, PauseButton, PlayButton, PlaylistAnnotationList, type PlaylistAnnotationListProps, PlaylistVisualization, type PlaylistVisualizationProps, RewindButton, SelectionTimeInputs, SetLoopRegionButton, SkipBackwardButton, SkipForwardButton, SnapToGridModifier, SortableTrackControls, type SortableTrackControlsProps, type SortableTrackControlsRenderProps, type SpectrogramCanvasRegistration, type SpectrogramIntegration, SpectrogramIntegrationProvider, StopButton, type TimeFormatControls, TimeFormatSelect, type TrackState, type UsePlaybackShortcutsOptions, type UsePlaybackShortcutsReturn, Waveform, WaveformPlaylistProvider, type WaveformProps, type WaveformTrack, type ZoomControls, ZoomInButton, ZoomOutButton, getWaveformDataMetadata, loadPeaksFromWaveformData, loadWaveformData, noDropAnimationPlugins, useAnnotationDragHandlers, useAnnotationIntegration, useAnnotationKeyboardControls, useClipDragHandlers, useClipInteractionEnabled, useClipSplitting, useDragSensors, useKeyboardShortcuts, useMasterVolume, useMediaElementAnimation, useMediaElementControls, useMediaElementData, useMediaElementState, usePlaybackAnimation, usePlaybackShortcuts, usePlaylistControls, usePlaylistData, usePlaylistDataOptional, usePlaylistState, useSpectrogramIntegration, useTimeFormat, useZoomControls, waveformDataToPeaks };