@waveform-playlist/browser 10.1.0 → 10.1.2

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.ts CHANGED
@@ -1,2464 +1,1824 @@
1
- import { Analyser } from 'tone';
2
- import { default as default_2 } from 'react';
3
- import { default as default_3 } from 'waveform-data';
4
- import { DragDropManager } from '@dnd-kit/abstract';
5
- import { DragEndEvent } from '@dnd-kit/abstract';
6
- import { DragMoveEvent } from '@dnd-kit/abstract';
7
- import { DragOperation } from '@dnd-kit/abstract';
8
- import { DragStartEvent } from '@dnd-kit/abstract';
9
- import { EngineState } from '@waveform-playlist/engine';
10
- import { FadeConfig } from '@waveform-playlist/media-element-playout';
11
- import { Gain } from 'tone';
12
- import { InputNode } from 'tone';
13
- import { MediaElementPlayout } from '@waveform-playlist/media-element-playout';
14
- import { Modifier } from '@dnd-kit/abstract';
15
- import { MutableRefObject } from 'react';
16
- import { PlaylistEngine } from '@waveform-playlist/engine';
17
- import { PluginDescriptor } from '@dnd-kit/abstract';
18
- import { Plugins } from '@dnd-kit/abstract';
19
- import { PointerSensor } from '@dnd-kit/dom';
20
- import { Provider } from 'react';
21
- import react__default from 'react';
22
- import { ReactNode } from 'react';
23
- import { RefObject } from 'react';
24
- import * as Tone from 'tone';
25
- import { ToneAudioNode } from 'tone';
26
- import { Volume } from 'tone';
27
-
28
- export declare interface ActiveEffect {
29
- instanceId: string;
30
- effectId: string;
31
- definition: EffectDefinition;
32
- params: Record<string, number | string | boolean>;
33
- bypassed: boolean;
34
- }
35
-
36
- /**
37
- * An action control shown on annotation items (e.g., delete, split).
38
- */
39
- declare interface AnnotationAction {
40
- class?: string;
41
- text?: string;
42
- title: string;
43
- action: (annotation: AnnotationData, index: number, annotations: AnnotationData[], opts: AnnotationActionOptions) => void;
44
- }
45
-
46
- /**
47
- * Configuration options passed to annotation action handlers.
48
- * Used by both browser and annotations packages.
49
- */
50
- declare interface AnnotationActionOptions {
51
- /** Whether annotation endpoints are linked (moving one endpoint moves the other) */
52
- linkEndpoints?: boolean;
53
- /** Whether to continue playing after an annotation ends */
54
- continuousPlay?: boolean;
55
- /** Additional custom properties */
56
- [key: string]: unknown;
57
- }
58
-
59
- /**
60
- * Props the browser package passes to the AnnotationBoxesWrapper component.
61
- * Mirrors what PlaylistVisualization and MediaElementPlaylist actually use.
62
- */
63
- declare interface AnnotationBoxesWrapperIntegrationProps {
64
- children?: React.ReactNode;
65
- height?: number;
66
- width?: number;
67
- }
68
-
69
- /**
70
- * Props the browser package passes to the AnnotationBox component.
71
- * Mirrors what PlaylistVisualization and MediaElementPlaylist actually use.
72
- */
73
- declare interface AnnotationBoxIntegrationProps {
74
- annotationId: string;
75
- annotationIndex: number;
76
- startPosition: number;
77
- endPosition: number;
78
- label?: string;
79
- color?: string;
80
- isActive?: boolean;
81
- onClick?: () => void;
82
- editable?: boolean;
83
- }
84
-
85
- /**
86
- * Shared annotation types used across waveform-playlist packages
87
- */
88
- /**
89
- * Base annotation data structure
90
- */
91
- export declare interface AnnotationData {
92
- id: string;
93
- start: number;
94
- end: number;
95
- lines: string[];
96
- language?: string;
97
- }
98
-
99
- /**
100
- * Interface for annotation integration provided by @waveform-playlist/annotations.
101
- *
102
- * The browser package defines what it needs, and the optional annotations package
103
- * provides it via <AnnotationProvider>.
104
- */
105
- export declare interface AnnotationIntegration {
106
- parseAeneas: (data: unknown) => AnnotationData;
107
- serializeAeneas: (annotation: AnnotationData) => unknown;
108
- AnnotationText: React.ComponentType<AnnotationTextIntegrationProps>;
109
- AnnotationBox: React.ComponentType<AnnotationBoxIntegrationProps>;
110
- AnnotationBoxesWrapper: React.ComponentType<AnnotationBoxesWrapperIntegrationProps>;
111
- ContinuousPlayCheckbox: React.ComponentType<{
112
- checked: boolean;
113
- onChange: (checked: boolean) => void;
114
- className?: string;
115
- }>;
116
- LinkEndpointsCheckbox: React.ComponentType<{
117
- checked: boolean;
118
- onChange: (checked: boolean) => void;
119
- className?: string;
120
- }>;
121
- EditableCheckbox: React.ComponentType<{
122
- checked: boolean;
123
- onChange: (checked: boolean) => void;
124
- className?: string;
125
- }>;
126
- DownloadAnnotationsButton: React.ComponentType<{
127
- annotations: AnnotationData[];
128
- filename?: string;
129
- className?: string;
130
- }>;
131
- }
132
-
133
- export declare const AnnotationIntegrationProvider: Provider<AnnotationIntegration | null>;
134
-
135
- /**
136
- * Props the browser package passes to the AnnotationText component.
137
- * Mirrors what PlaylistAnnotationList and MediaElementAnnotationList actually use.
138
- */
139
- declare interface AnnotationTextIntegrationProps {
140
- annotations: AnnotationData[];
141
- activeAnnotationId?: string;
142
- shouldScrollToActive?: boolean;
143
- scrollActivePosition?: ScrollLogicalPosition;
144
- scrollActiveContainer?: 'nearest' | 'all';
145
- editable?: boolean;
146
- controls?: AnnotationAction[];
147
- annotationListConfig?: AnnotationActionOptions;
148
- height?: number;
149
- onAnnotationUpdate?: (updatedAnnotations: AnnotationData[]) => void;
150
- renderAnnotationItem?: (props: RenderAnnotationItemProps) => React.ReactNode;
151
- }
152
-
153
- /**
154
- * Represents a single audio clip on the timeline
155
- *
156
- * IMPORTANT: All positions/durations are stored as SAMPLE COUNTS (integers)
157
- * to avoid floating-point precision errors. Convert to seconds only when
158
- * needed for playback using: seconds = samples / sampleRate
159
- *
160
- * Clips can be created with just waveformData (for instant visual rendering)
161
- * and have audioBuffer added later when audio finishes loading.
162
- */
163
- export declare interface AudioClip {
164
- /** Unique identifier for this clip */
165
- id: string;
166
- /**
167
- * The audio buffer containing the audio data.
168
- * Optional for peaks-first rendering - can be added later.
169
- * Required for playback and editing operations.
170
- */
171
- audioBuffer?: AudioBuffer;
172
- /** Position on timeline where this clip starts (in samples at timeline sampleRate) */
173
- startSample: number;
174
- /** Duration of this clip (in samples) - how much of the audio buffer to play */
175
- durationSamples: number;
176
- /** Offset into the audio buffer where playback starts (in samples) - the "trim start" point */
177
- offsetSamples: number;
178
- /**
179
- * Sample rate for this clip's audio.
180
- * Required when audioBuffer is not provided (for peaks-first rendering).
181
- * When audioBuffer is present, this should match audioBuffer.sampleRate.
182
- */
183
- sampleRate: number;
184
- /**
185
- * Total duration of the source audio in samples.
186
- * Required when audioBuffer is not provided (for trim bounds calculation).
187
- * When audioBuffer is present, this should equal audioBuffer.length.
188
- */
189
- sourceDurationSamples: number;
190
- /** Optional fade in effect */
191
- fadeIn?: Fade;
192
- /** Optional fade out effect */
193
- fadeOut?: Fade;
194
- /** Clip-specific gain/volume multiplier (0.0 to 1.0+) */
195
- gain: number;
196
- /** Optional label/name for this clip */
197
- name?: string;
198
- /** Optional color for visual distinction */
199
- color?: string;
200
- /**
201
- * Pre-computed waveform data from waveform-data.js library.
202
- * When provided, the library will use this instead of computing peaks from the audioBuffer.
203
- * Supports resampling to different zoom levels and slicing for clip trimming.
204
- * Load with: `const waveformData = await loadWaveformData('/path/to/peaks.dat')`
205
- */
206
- waveformData?: WaveformDataObject;
207
- /**
208
- * MIDI note data — when present, this clip plays MIDI instead of audio.
209
- * The playout adapter uses this field to detect MIDI clips and route them
210
- * to MidiToneTrack (PolySynth) instead of ToneTrack (AudioBufferSourceNode).
211
- */
212
- midiNotes?: MidiNoteData[];
213
- /** MIDI channel (0-indexed). Channel 9 = GM percussion. */
214
- midiChannel?: number;
215
- /** MIDI program number (0-127). GM instrument number for SoundFont playback. */
216
- midiProgram?: number;
217
- }
218
-
219
- /**
220
- * Audio position display that uses the playlist context.
221
- * Uses requestAnimationFrame for smooth 60fps updates during playback.
222
- * Direct DOM manipulation avoids React re-renders.
223
- */
224
- export declare const AudioPosition: default_2.FC<{
225
- className?: string;
226
- }>;
227
-
228
- /**
229
- * Configuration for a single audio track to load
230
- *
231
- * Audio can be provided in three ways:
232
- * 1. `src` - URL to fetch and decode (standard loading)
233
- * 2. `audioBuffer` - Pre-loaded AudioBuffer (skip fetch/decode)
234
- * 3. `waveformData` only - Peaks-first rendering (audio loads later)
235
- *
236
- * For peaks-first rendering, just provide `waveformData` - the sample rate
237
- * and duration are derived from the waveform data automatically.
238
- */
239
- export declare interface AudioTrackConfig {
240
- /** URL to audio file - used if audioBuffer not provided */
241
- src?: string;
242
- /** Pre-loaded AudioBuffer - skips fetch/decode if provided */
243
- audioBuffer?: AudioBuffer;
244
- name?: string;
245
- muted?: boolean;
246
- soloed?: boolean;
247
- volume?: number;
248
- pan?: number;
249
- color?: string;
250
- effects?: TrackEffectsFunction_2;
251
- startTime?: number;
252
- duration?: number;
253
- offset?: number;
254
- fadeIn?: Fade;
255
- fadeOut?: Fade;
256
- waveformData?: WaveformDataObject;
257
- /** Visualization render mode: 'waveform' | 'spectrogram' | 'both'. Default: 'waveform' */
258
- renderMode?: RenderMode;
259
- /** Spectrogram configuration (FFT size, window, frequency scale, etc.) */
260
- spectrogramConfig?: SpectrogramConfig;
261
- /** Spectrogram color map name or custom color array */
262
- spectrogramColorMap?: ColorMapValue;
263
- }
264
-
265
- /**
266
- * Automatic scroll checkbox that uses the playlist context
267
- * Uses split contexts to avoid re-rendering during animation
268
- */
269
- export declare const AutomaticScrollCheckbox: default_2.FC<{
270
- className?: string;
271
- }>;
272
-
273
- /**
274
- * Bits type - number of bits for peak data
275
- */
276
- declare type Bits = 8 | 16;
277
-
278
- export declare const ClearAllButton: default_2.FC<ClearAllButtonProps>;
279
-
280
- export declare interface ClearAllButtonProps {
281
- onClearAll: () => void;
282
- label?: string;
283
- className?: string;
284
- }
285
-
286
- /**
287
- * Modifier that constrains clip drag movement to prevent overlaps.
288
- *
289
- * For clip move operations: constrains horizontal transform to valid positions
290
- * using the engine's collision detection.
291
- *
292
- * For boundary trim operations: returns zero transform because visual feedback
293
- * comes from React state updates resizing the clip, not from CSS translate.
294
- */
295
- export declare class ClipCollisionModifier extends Modifier<DragDropManager<any, any>, ClipCollisionOptions> {
296
- apply(operation: DragOperation): {
297
- x: number;
298
- y: number;
299
- };
300
- static configure: (options: ClipCollisionOptions) => PluginDescriptor<any, any, typeof ClipCollisionModifier>;
301
- }
302
-
303
- declare interface ClipCollisionOptions {
304
- tracks: ClipTrack[];
305
- samplesPerPixel: number;
306
- }
307
-
308
- export declare const ClipInteractionProvider: default_2.FC<ClipInteractionProviderProps>;
309
-
310
- export declare interface ClipInteractionProviderProps {
311
- /** Enable snap-to-grid for clip moves and boundary trims. When true,
312
- * auto-detects beats snapping from BeatsAndBarsProvider context
313
- * (if present with scaleMode="beats" and snapTo!="off"), otherwise
314
- * falls back to timescale-based snapping. Default: false. */
315
- snap?: boolean;
316
- touchOptimized?: boolean;
317
- children: default_2.ReactNode;
318
- }
319
-
320
- declare interface ClipPeaks {
321
- clipId: string;
322
- trackName: string;
323
- peaks: PeakData;
324
- startSample: number;
325
- durationSamples: number;
326
- fadeIn?: Fade;
327
- fadeOut?: Fade;
328
- midiNotes?: MidiNoteData[];
329
- sampleRate?: number;
330
- offsetSamples?: number;
331
- }
332
-
333
- /**
334
- * Represents a track containing multiple audio clips
335
- */
336
- export declare interface ClipTrack {
337
- /** Unique identifier for this track */
338
- id: string;
339
- /** Display name for this track */
340
- name: string;
341
- /** Array of audio clips on this track */
342
- clips: AudioClip[];
343
- /** Whether this track is muted */
344
- muted: boolean;
345
- /** Whether this track is soloed */
346
- soloed: boolean;
347
- /** Track volume (0.0 to 1.0+) */
348
- volume: number;
349
- /** Stereo pan (-1.0 = left, 0 = center, 1.0 = right) */
350
- pan: number;
351
- /** Optional track color for visual distinction */
352
- color?: string;
353
- /** Track height in pixels (for UI) */
354
- height?: number;
355
- /** Optional effects function for this track */
356
- effects?: TrackEffectsFunction_2;
357
- /** Visualization render mode. Default: 'waveform' */
358
- renderMode?: RenderMode;
359
- /** Per-track spectrogram configuration (FFT size, window, frequency scale, etc.) */
360
- spectrogramConfig?: SpectrogramConfig;
361
- /** Per-track spectrogram color map name or custom color array */
362
- spectrogramColorMap?: ColorMapValue;
363
- }
364
-
365
- /** A single color map entry: [r, g, b] or [r, g, b, a] */
366
- declare type ColorMapEntry = [number, number, number] | [number, number, number, number];
367
-
368
- /** Built-in color map names */
369
- declare type ColorMapName = 'viridis' | 'magma' | 'inferno' | 'grayscale' | 'igray' | 'roseus';
370
-
371
- /** Color map can be a named preset or a custom array of [r, g, b, a?] entries */
372
- declare type ColorMapValue = ColorMapName | ColorMapEntry[];
373
-
374
- /**
375
- * Continuous play checkbox that uses the playlist context.
376
- * Must be used within <AnnotationProvider>.
377
- */
378
- export declare const ContinuousPlayCheckbox: default_2.FC<{
379
- className?: string;
380
- }>;
381
-
382
- /**
383
- * Create a chain of effects connected in series
384
- */
385
- export declare function createEffectChain(effects: EffectInstance[]): {
386
- input: ToneAudioNode;
387
- output: ToneAudioNode;
388
- dispose: () => void;
389
- };
390
-
391
- /**
392
- * Create an effect instance from a definition with initial parameter values
393
- */
394
- export declare function createEffectInstance(definition: EffectDefinition, initialParams?: Record<string, number | string | boolean>): EffectInstance;
395
-
396
- /**
397
- * Download annotations button that uses the playlist context.
398
- * Must be used within <AnnotationProvider>.
399
- */
400
- export declare const DownloadAnnotationsButton: default_2.FC<{
401
- filename?: string;
402
- className?: string;
403
- }>;
404
-
405
- declare interface DragSensorOptions {
406
- /**
407
- * Enable mobile-optimized touch handling with delay-based activation.
408
- * When true, touch events get delay-based activation while mouse/pen get distance-based.
409
- * When false (default), all pointer types use distance-based activation (1px).
410
- */
411
- touchOptimized?: boolean;
412
- /**
413
- * Delay in milliseconds before touch drag activates (only when touchOptimized is true).
414
- * Default: 250ms - long enough to distinguish from scroll intent
415
- */
416
- touchDelay?: number;
417
- /**
418
- * Distance tolerance during touch delay (only when touchOptimized is true).
419
- * If finger moves more than this during delay, drag is cancelled.
420
- * Default: 5px - allows slight finger movement
421
- */
422
- touchTolerance?: number;
423
- /**
424
- * Distance in pixels before mouse drag activates.
425
- * Default: 1px for immediate feedback on desktop
426
- */
427
- mouseDistance?: number;
428
- }
429
-
430
- /**
431
- * Editable annotations checkbox that uses the playlist context.
432
- * Must be used within <AnnotationProvider>.
433
- */
434
- export declare const EditableCheckbox: default_2.FC<{
435
- className?: string;
436
- }>;
437
-
438
- export declare const effectCategories: {
439
- id: EffectDefinition['category'];
440
- name: string;
441
- }[];
442
-
443
- export declare interface EffectDefinition {
444
- id: string;
445
- name: string;
446
- category: 'delay' | 'reverb' | 'modulation' | 'distortion' | 'filter' | 'dynamics' | 'spatial';
447
- description: string;
448
- parameters: EffectParameter[];
449
- }
450
-
451
- export declare const effectDefinitions: EffectDefinition[];
452
-
453
- export declare interface EffectInstance {
454
- effect: ToneAudioNode;
455
- id: string;
456
- instanceId: string;
457
- dispose: () => void;
458
- setParameter: (name: string, value: number | string | boolean) => void;
459
- getParameter: (name: string) => number | string | boolean | undefined;
460
- connect: (destination: InputNode) => void;
461
- disconnect: () => void;
462
- }
463
-
464
- export declare interface EffectParameter {
465
- name: string;
466
- label: string;
467
- type: ParameterType;
468
- min?: number;
469
- max?: number;
470
- step?: number;
471
- default: number | string | boolean;
472
- unit?: string;
473
- options?: {
474
- value: string | number;
475
- label: string;
476
- }[];
477
- }
478
-
479
- export declare type EffectsFunction = (masterGainNode: Volume, destination: ToneAudioNode, isOffline: boolean) => void | (() => void);
480
-
481
- export declare interface ExportOptions extends WavEncoderOptions {
482
- /** Filename for download (without extension) */
483
- filename?: string;
484
- /** Export mode: 'master' for stereo mix, 'individual' for single track */
485
- mode?: 'master' | 'individual';
486
- /** Track index for individual export (only used when mode is 'individual') */
487
- trackIndex?: number;
488
- /** Whether to trigger automatic download */
489
- autoDownload?: boolean;
490
- /** Whether to apply effects (fades, etc.) - defaults to true */
491
- applyEffects?: boolean;
492
- /**
493
- * Optional Tone.js effects function for master effects. When provided, export will use Tone.Offline
494
- * to render through the effects chain. The function receives isOffline=true.
495
- */
496
- effectsFunction?: EffectsFunction;
497
- /**
498
- * Optional function to create offline track effects.
499
- * Takes a trackId and returns a TrackEffectsFunction for offline rendering.
500
- * This is used instead of track.effects to avoid AudioContext mismatch issues.
501
- */
502
- createOfflineTrackEffects?: (trackId: string) => TrackEffectsFunction_3 | undefined;
503
- /** Progress callback (0-1) */
504
- onProgress?: (progress: number) => void;
505
- }
506
-
507
- export declare interface ExportResult {
508
- /** The rendered audio buffer */
509
- audioBuffer: AudioBuffer;
510
- /** The WAV file as a Blob */
511
- blob: Blob;
512
- /** Duration in seconds */
513
- duration: number;
514
- }
515
-
516
- export declare const ExportWavButton: default_2.FC<ExportWavButtonProps>;
517
-
518
- export declare interface ExportWavButtonProps {
519
- /** Button label */
520
- label?: string;
521
- /** Filename for the downloaded file (without extension) */
522
- filename?: string;
523
- /** Export mode: 'master' for stereo mix, 'individual' for single track */
524
- mode?: 'master' | 'individual';
525
- /** Track index for individual export */
526
- trackIndex?: number;
527
- /** Bit depth: 16 or 32 */
528
- bitDepth?: 16 | 32;
529
- /** Whether to apply effects (fades, etc.) - defaults to true */
530
- applyEffects?: boolean;
531
- /**
532
- * Optional Tone.js effects function for master effects. When provided, export will use Tone.Offline
533
- * to render through the effects chain. The function receives isOffline=true.
534
- */
535
- effectsFunction?: EffectsFunction;
536
- /**
537
- * Optional function to create offline track effects.
538
- * Takes a trackId and returns a TrackEffectsFunction for offline rendering.
539
- */
540
- createOfflineTrackEffects?: (trackId: string) => TrackEffectsFunction_3 | undefined;
541
- /** CSS class name */
542
- className?: string;
543
- /** Callback when export completes */
544
- onExportComplete?: (blob: Blob) => void;
545
- /** Callback when export fails */
546
- onExportError?: (error: Error) => void;
547
- }
548
-
549
- /**
550
- * Simple fade configuration
551
- */
552
- export declare interface Fade {
553
- /** Duration of the fade in seconds */
554
- duration: number;
555
- /** Type of fade curve (default: 'linear') */
556
- type?: FadeType;
557
- }
558
-
559
- declare type FadeType = 'logarithmic' | 'linear' | 'sCurve' | 'exponential';
560
-
561
- export declare const FastForwardButton: default_2.FC<{
562
- className?: string;
563
- }>;
564
-
565
- /**
566
- * Spectrogram Types
567
- *
568
- * Types for frequency-domain visualization of audio data.
569
- */
570
- /** Valid FFT sizes (must be power of 2, 256–8192) */
571
- declare type FFTSize = 256 | 512 | 1024 | 2048 | 4096 | 8192;
572
-
573
- /**
574
- * Custom function to generate the label shown on annotation boxes in the waveform.
575
- * Receives the annotation data and its index in the list, returns a string label.
576
- * Default behavior: displays annotation.id
577
- */
578
- export declare type GetAnnotationBoxLabelFn = (annotation: AnnotationData, index: number) => string;
579
-
580
- export declare const getEffectDefinition: (id: string) => EffectDefinition | undefined;
581
-
582
- export declare const getEffectsByCategory: (category: EffectDefinition["category"]) => EffectDefinition[];
583
-
584
- /**
585
- * Get a human-readable string representation of a keyboard shortcut
586
- *
587
- * @param shortcut - The keyboard shortcut
588
- * @returns Human-readable string (e.g., "Cmd+Shift+S")
589
- */
590
- export declare const getShortcutLabel: (shortcut: KeyboardShortcut) => string;
591
-
592
- /**
593
- * Get metadata from waveform data file without converting to peaks
594
- *
595
- * @param src - URL to waveform data file
596
- * @returns Metadata (sample rate, channels, duration, bits, etc.)
597
- */
598
- export declare function getWaveformDataMetadata(src: string): Promise<{
599
- sampleRate: number;
600
- channels: number;
601
- duration: number;
602
- samplesPerPixel: number;
603
- length: number;
604
- bits: 8 | 16;
605
- }>;
606
-
607
- /**
608
- * Waveform Playlist Theme
609
- *
610
- * This file defines the theme interface and default values for the waveform playlist components.
611
- */
612
- /**
613
- * Gradient color stop for waveform gradients
614
- */
615
- declare interface GradientStop {
616
- offset: number;
617
- color: string;
618
- }
619
-
620
- declare interface KeyboardShortcut {
621
- key: string;
622
- ctrlKey?: boolean;
623
- shiftKey?: boolean;
624
- metaKey?: boolean;
625
- altKey?: boolean;
626
- action: () => void;
627
- description?: string;
628
- preventDefault?: boolean;
629
- }
630
-
631
- /**
632
- * Self-closing component that sets up keyboard shortcuts for the playlist.
633
- * Must be rendered inside a WaveformPlaylistProvider.
634
- *
635
- * @example
636
- * ```tsx
637
- * <WaveformPlaylistProvider tracks={tracks} {...}>
638
- * <KeyboardShortcuts playback clipSplitting />
639
- * <Waveform />
640
- * </WaveformPlaylistProvider>
641
- * ```
642
- */
643
- export declare const KeyboardShortcuts: default_2.FC<KeyboardShortcutsProps>;
644
-
645
- export declare interface KeyboardShortcutsProps {
646
- /** Enable default playback shortcuts (Space, Escape, 0). Defaults to false. */
647
- playback?: boolean;
648
- /** Enable clip splitting shortcut ('s' key). Defaults to false. */
649
- clipSplitting?: boolean;
650
- /** Enable annotation keyboard controls (arrow nav, boundary editing). Defaults to false. */
651
- annotations?: boolean;
652
- /** Additional shortcuts appended to the defaults. */
653
- additionalShortcuts?: KeyboardShortcut[];
654
- }
655
-
656
- /**
657
- * Link endpoints checkbox that uses the playlist context.
658
- * Must be used within <AnnotationProvider>.
659
- */
660
- export declare const LinkEndpointsCheckbox: default_2.FC<{
661
- className?: string;
662
- }>;
663
-
664
- /**
665
- * Load waveform data file and convert to Peaks format in one step
666
- *
667
- * @param src - URL to waveform data file (.dat or .json)
668
- * @param channelIndex - Channel index (default: 0)
669
- * @returns Peaks data ready for rendering
670
- */
671
- export declare function loadPeaksFromWaveformData(src: string, channelIndex?: number): Promise<{
672
- data: Int8Array | Int16Array;
673
- bits: 8 | 16;
674
- length: number;
675
- sampleRate: number;
676
- }>;
677
-
678
- /**
679
- * Load waveform data from a .dat or .json file
680
- *
681
- * @param src - URL to waveform data file (.dat or .json)
682
- * @returns WaveformData instance
683
- */
684
- export declare function loadWaveformData(src: string): Promise<default_3>;
685
-
686
- export declare const LoopButton: default_2.FC<{
687
- className?: string;
688
- }>;
689
-
690
- /**
691
- * Master volume control that uses the playlist context
692
- */
693
- export declare const MasterVolumeControl: default_2.FC<{
694
- className?: string;
695
- }>;
696
-
697
- export declare interface MasterVolumeControls {
698
- masterVolume: number;
699
- setMasterVolume: (volume: number) => void;
700
- /** Ref holding the current masterVolume for seeding a fresh engine. */
701
- masterVolumeRef: React.RefObject<number>;
702
- }
703
-
704
- export declare interface MediaElementAnimationContextValue {
705
- isPlaying: boolean;
706
- currentTime: number;
707
- currentTimeRef: default_2.RefObject<number>;
708
- }
709
-
710
- /**
711
- * Standalone annotation text list component for MediaElementPlaylistProvider.
712
- *
713
- * Requires @waveform-playlist/annotations with AnnotationProvider.
714
- * Throws if used without `<AnnotationProvider>` wrapping the component tree.
715
- */
716
- export declare const MediaElementAnnotationList: default_2.FC<MediaElementAnnotationListProps>;
717
-
718
- export declare interface MediaElementAnnotationListProps {
719
- /** Height in pixels for the annotation text list */
720
- height?: number;
721
- /**
722
- * Custom render function for annotation items in the text list.
723
- * When provided, completely replaces the default annotation item rendering.
724
- */
725
- renderAnnotationItem?: (props: RenderAnnotationItemProps) => default_2.ReactNode;
726
- /**
727
- * Callback when annotations are updated (e.g., text edited).
728
- * Called with the full updated annotations array.
729
- */
730
- onAnnotationUpdate?: OnAnnotationUpdateFn;
731
- /** Whether annotation text can be edited. Defaults to false. */
732
- editable?: boolean;
733
- /**
734
- * Action controls to show on each annotation item (e.g., delete, split).
735
- * Only rendered when `editable` is true.
736
- */
737
- controls?: AnnotationAction[];
738
- /**
739
- * Override annotation list config. Falls back to context values
740
- * `{ linkEndpoints: false, continuousPlay }` if not provided.
741
- */
742
- annotationListConfig?: AnnotationActionOptions;
743
- /** Where to position the active annotation when auto-scrolling. Defaults to 'center'. */
744
- scrollActivePosition?: ScrollLogicalPosition;
745
- /** Which scrollable containers to scroll: 'nearest' or 'all'. Defaults to 'nearest'. */
746
- scrollActiveContainer?: 'nearest' | 'all';
747
- }
748
-
749
- export declare interface MediaElementControlsContextValue {
750
- play: (startTime?: number) => void;
751
- pause: () => void;
752
- stop: () => void;
753
- seekTo: (time: number) => void;
754
- setPlaybackRate: (rate: number) => void;
755
- setContinuousPlay: (enabled: boolean) => void;
756
- setAnnotations: default_2.Dispatch<default_2.SetStateAction<AnnotationData[]>>;
757
- setActiveAnnotationId: (id: string | null) => void;
758
- setAutomaticScroll: (enabled: boolean) => void;
759
- setScrollContainer: (element: HTMLDivElement | null) => void;
760
- scrollContainerRef: default_2.RefObject<HTMLDivElement | null>;
761
- }
762
-
763
- export declare interface MediaElementDataContextValue {
764
- duration: number;
765
- peaksDataArray: TrackClipPeaks[];
766
- sampleRate: number;
767
- waveHeight: number;
768
- timeScaleHeight: number;
769
- samplesPerPixel: number;
770
- playoutRef: default_2.RefObject<MediaElementPlayout | null>;
771
- controls: {
772
- show: boolean;
773
- width: number;
774
- };
775
- barWidth: number;
776
- barGap: number;
777
- progressBarWidth: number;
778
- fadeIn?: FadeConfig;
779
- fadeOut?: FadeConfig;
780
- }
781
-
782
- /**
783
- * Standalone waveform + annotation boxes component for MediaElementPlaylistProvider.
784
- *
785
- * Renders the waveform visualization, annotation boxes, selection, and playhead.
786
- * Does NOT render the annotation text list use `MediaElementAnnotationList` for that.
787
- *
788
- * Must be used inside a `MediaElementPlaylistProvider`.
789
- *
790
- * This component can be placed independently in consumer layouts, allowing the
791
- * waveform and annotation list to be positioned separately (e.g., in different
792
- * panels or with custom elements between them).
793
- */
794
- export declare const MediaElementPlaylist: default_2.FC<MediaElementPlaylistProps>;
795
-
796
- export declare interface MediaElementPlaylistProps {
797
- /** Custom function to generate the label shown on annotation boxes */
798
- getAnnotationBoxLabel?: GetAnnotationBoxLabelFn;
799
- /** Whether annotation boundaries can be edited by dragging. Defaults to false. */
800
- editable?: boolean;
801
- /** Whether dragging one annotation boundary also moves the adjacent annotation's boundary. Defaults to false. */
802
- linkEndpoints?: boolean;
803
- /**
804
- * Callback when annotations are updated (e.g., boundaries dragged).
805
- * Called with the full updated annotations array.
806
- */
807
- onAnnotationUpdate?: OnAnnotationUpdateFn;
808
- /** Custom playhead render function. Receives position, color, and animation refs for smooth 60fps animation. */
809
- renderPlayhead?: RenderPlayheadFunction;
810
- /** Show fade in/out overlays on the waveform. Defaults to false. */
811
- showFades?: boolean;
812
- className?: string;
813
- }
814
-
815
- /**
816
- * MediaElementPlaylistProvider
817
- *
818
- * A simplified playlist provider for single-track playback using HTMLAudioElement.
819
- * Key features:
820
- * - Pitch-preserving playback rate (0.5x - 2.0x)
821
- * - Pre-computed peaks visualization (no AudioBuffer needed)
822
- * - Simpler API than full WaveformPlaylistProvider
823
- *
824
- * Use this for:
825
- * - Language learning apps (speed control)
826
- * - Podcast players
827
- * - Single-track audio viewers
828
- *
829
- * For multi-track editing, use WaveformPlaylistProvider instead.
830
- */
831
- export declare const MediaElementPlaylistProvider: default_2.FC<MediaElementPlaylistProviderProps>;
832
-
833
- declare interface MediaElementPlaylistProviderProps {
834
- /** Single track configuration with source URL and waveform data */
835
- track: MediaElementTrackConfig;
836
- /** Initial samples per pixel (zoom level) */
837
- samplesPerPixel?: number;
838
- /** Height of each waveform track */
839
- waveHeight?: number;
840
- /** Show timescale */
841
- timescale?: boolean;
842
- /** Initial playback rate (0.5 to 2.0) */
843
- playbackRate?: number;
844
- /** Enable automatic scroll to keep playhead centered */
845
- automaticScroll?: boolean;
846
- /** Theme configuration */
847
- theme?: Partial<WaveformPlaylistTheme>;
848
- /** Track controls configuration */
849
- controls?: {
850
- show: boolean;
851
- width: number;
852
- };
853
- /** Annotations */
854
- annotationList?: {
855
- annotations?: AnnotationData[];
856
- isContinuousPlay?: boolean;
857
- };
858
- /** Width of waveform bars */
859
- barWidth?: number;
860
- /** Gap between waveform bars */
861
- barGap?: number;
862
- /** Width of progress bars */
863
- progressBarWidth?: number;
864
- /** Callback when annotations are changed (drag, edit, etc.) */
865
- onAnnotationsChange?: (annotations: AnnotationData[]) => void;
866
- /**
867
- * AudioContext for Web Audio routing (fades, effects).
868
- * When provided, audio routes through Web Audio nodes:
869
- * HTMLAudioElement → MediaElementSourceNode → fadeGain → volumeGain → destination
870
- *
871
- * Without this, playback uses HTMLAudioElement directly (no fades or effects).
872
- * Each provider instance should use its own AudioContext or share one —
873
- * createMediaElementSource() is called once per audio element.
874
- */
875
- audioContext?: AudioContext;
876
- /** Callback when audio is ready */
877
- onReady?: () => void;
878
- children: ReactNode;
879
- }
880
-
881
- export declare interface MediaElementStateContextValue {
882
- continuousPlay: boolean;
883
- annotations: AnnotationData[];
884
- activeAnnotationId: string | null;
885
- playbackRate: number;
886
- isAutomaticScroll: boolean;
887
- }
888
-
889
- export declare interface MediaElementTrackConfig {
890
- /** Audio source URL or Blob URL */
891
- source: string;
892
- /** Pre-computed waveform data (required for visualization) */
893
- waveformData: WaveformDataObject;
894
- /** Track name for display */
895
- name?: string;
896
- /** Fade in configuration (requires audioContext on provider) */
897
- fadeIn?: FadeConfig;
898
- /** Fade out configuration (requires audioContext on provider) */
899
- fadeOut?: FadeConfig;
900
- }
901
-
902
- /**
903
- * Simplified Waveform component for MediaElementPlaylistProvider
904
- *
905
- * This is a stripped-down version of Waveform that works with the
906
- * MediaElement context. It supports:
907
- * - Single track visualization
908
- * - Click to seek
909
- * - Annotation display and click-to-play
910
- * - Playhead animation
911
- *
912
- * For multi-track editing, use the full Waveform with WaveformPlaylistProvider.
913
- */
914
- export declare const MediaElementWaveform: default_2.FC<MediaElementWaveformProps>;
915
-
916
- export declare interface MediaElementWaveformProps {
917
- /** Height in pixels for the annotation text list */
918
- annotationTextHeight?: number;
919
- /** Custom function to generate the label shown on annotation boxes */
920
- getAnnotationBoxLabel?: GetAnnotationBoxLabelFn;
921
- /**
922
- * Custom render function for annotation items in the text list.
923
- * When provided, completely replaces the default annotation item rendering.
924
- * Use this to customize the appearance of each annotation (e.g., add furigana).
925
- */
926
- renderAnnotationItem?: (props: RenderAnnotationItemProps) => default_2.ReactNode;
927
- /** Whether annotation boundaries can be edited by dragging. Defaults to false. */
928
- editable?: boolean;
929
- /** Whether dragging one annotation boundary also moves the adjacent annotation's boundary. Defaults to false. */
930
- linkEndpoints?: boolean;
931
- /**
932
- * Callback when annotations are updated (e.g., boundaries dragged).
933
- * Called with the full updated annotations array.
934
- */
935
- onAnnotationUpdate?: OnAnnotationUpdateFn;
936
- /** Where to position the active annotation when auto-scrolling: 'center', 'start', 'end', or 'nearest'. Defaults to 'center'. */
937
- scrollActivePosition?: ScrollLogicalPosition;
938
- /** Which scrollable containers to scroll: 'nearest' (only the annotation list) or 'all' (including viewport). Defaults to 'nearest'. */
939
- scrollActiveContainer?: 'nearest' | 'all';
940
- /** Custom playhead render function. Receives position, color, and animation refs for smooth 60fps animation. */
941
- renderPlayhead?: RenderPlayheadFunction;
942
- /** Show fade in/out overlays on the waveform. Defaults to false. */
943
- showFades?: boolean;
944
- className?: string;
945
- }
946
-
947
- /**
948
- * MIDI note data for clips that play MIDI instead of audio.
949
- * When present on an AudioClip, the clip is treated as a MIDI clip
950
- * by the playout adapter.
951
- */
952
- declare interface MidiNoteData {
953
- /** MIDI note number (0-127) */
954
- midi: number;
955
- /** Note name in scientific pitch notation ("C4", "G#3") */
956
- name: string;
957
- /** Start time in seconds, relative to clip start */
958
- time: number;
959
- /** Duration in seconds */
960
- duration: number;
961
- /** Velocity (0-1 normalized) */
962
- velocity: number;
963
- /** MIDI channel (0-indexed). Channel 9 = GM percussion. Enables per-note routing in flattened tracks. */
964
- channel?: number;
965
- }
966
-
967
- /**
968
- * DragDropProvider plugins customizer that disables the Feedback plugin's drop animation.
969
- *
970
- * Without this, the Feedback plugin animates the dragged element back to its original
971
- * position on drop, causing a visual snap-back before React re-renders at the new position.
972
- *
973
- * Usage:
974
- * ```tsx
975
- * <DragDropProvider plugins={noDropAnimationPlugins} ...>
976
- * ```
977
- */
978
- export declare const noDropAnimationPlugins: (defaults: Plugins) => Plugins;
979
-
980
- /**
981
- * Callback when annotations are updated (e.g., boundaries dragged).
982
- * Called with the full updated annotations array.
983
- */
984
- export declare type OnAnnotationUpdateFn = (annotations: AnnotationData[]) => void;
985
-
986
- /**
987
- * Effect definitions for all available Tone.js effects
988
- * Each effect has parameters with min/max/default values for UI controls
989
- */
990
- export declare type ParameterType = 'number' | 'select' | 'boolean';
991
-
992
- export declare const PauseButton: default_2.FC<{
993
- className?: string;
994
- }>;
995
-
996
- /**
997
- * PeakData - result of peak extraction
998
- */
999
- declare interface PeakData {
1000
- /** Number of peak pairs extracted */
1001
- length: number;
1002
- /** Array of peak data for each channel (interleaved min/max) */
1003
- data: Peaks[];
1004
- /** Bit depth of peak data */
1005
- bits: Bits;
1006
- }
1007
-
1008
- /**
1009
- * Peaks type - represents a typed array of interleaved min/max peak data
1010
- */
1011
- declare type Peaks = Int8Array | Int16Array;
1012
-
1013
- declare interface PlaybackAnimationContextValue {
1014
- isPlaying: boolean;
1015
- currentTime: number;
1016
- currentTimeRef: default_2.RefObject<number>;
1017
- playbackStartTimeRef: default_2.RefObject<number>;
1018
- audioStartPositionRef: default_2.RefObject<number>;
1019
- /** Returns current playback time from engine (auto-wraps at loop boundaries). */
1020
- getPlaybackTime: () => number;
1021
- }
1022
-
1023
- export declare const PlayButton: default_2.FC<{
1024
- className?: string;
1025
- }>;
1026
-
1027
- /**
1028
- * Props passed to the default playhead component or custom render function.
1029
- */
1030
- declare interface PlayheadProps {
1031
- /** Position in pixels from left edge (only valid when not playing) */
1032
- position: number;
1033
- /** Playhead color (default: #ff0000) */
1034
- color?: string;
1035
- /** Whether audio is currently playing */
1036
- isPlaying: boolean;
1037
- /** Ref to current time in seconds - use for smooth animation during playback */
1038
- currentTimeRef: react__default.RefObject<number>;
1039
- /** Audio context start time when playback began. Fallback when getPlaybackTime is not provided. */
1040
- playbackStartTimeRef: react__default.RefObject<number>;
1041
- /** Audio position when playback started. Fallback when getPlaybackTime is not provided. */
1042
- audioStartPositionRef: react__default.RefObject<number>;
1043
- /** Samples per pixel - for converting time to pixels */
1044
- samplesPerPixel: number;
1045
- /** Sample rate - for converting time to pixels */
1046
- sampleRate: number;
1047
- /** Controls offset in pixels (deprecated, always 0 — controls are now outside scroll area) */
1048
- controlsOffset?: number;
1049
- /** Function to get current audio context time - required for smooth animation */
1050
- getAudioContextTime?: () => number;
1051
- /** Returns current playback time (auto-wraps at loop boundaries). Preferred over manual elapsed calculation. */
1052
- getPlaybackTime?: () => number;
1053
- }
1054
-
1055
- /**
1056
- * Standalone annotation text list component for WaveformPlaylistProvider (WebAudio).
1057
- *
1058
- * Requires @waveform-playlist/annotations with AnnotationProvider.
1059
- * Throws if used without `<AnnotationProvider>` wrapping the component tree.
1060
- */
1061
- export declare const PlaylistAnnotationList: default_2.FC<PlaylistAnnotationListProps>;
1062
-
1063
- export declare interface PlaylistAnnotationListProps {
1064
- /** Height in pixels for the annotation text list */
1065
- height?: number;
1066
- /**
1067
- * Custom render function for annotation items in the text list.
1068
- * When provided, completely replaces the default annotation item rendering.
1069
- */
1070
- renderAnnotationItem?: (props: RenderAnnotationItemProps) => default_2.ReactNode;
1071
- /**
1072
- * Callback when annotations are updated (e.g., text edited).
1073
- * Called with the full updated annotations array.
1074
- */
1075
- onAnnotationUpdate?: OnAnnotationUpdateFn;
1076
- /**
1077
- * Action controls to show on each annotation item (e.g., delete, split).
1078
- * Only rendered when `annotationsEditable` is true in context.
1079
- */
1080
- controls?: AnnotationAction[];
1081
- /**
1082
- * Override annotation list config. Falls back to context values
1083
- * `{ linkEndpoints, continuousPlay }` if not provided.
1084
- */
1085
- annotationListConfig?: AnnotationActionOptions;
1086
- /** Where to position the active annotation when auto-scrolling. Defaults to 'center'. */
1087
- scrollActivePosition?: ScrollLogicalPosition;
1088
- /** Which scrollable containers to scroll: 'nearest' or 'all'. Defaults to 'nearest'. */
1089
- scrollActiveContainer?: 'nearest' | 'all';
1090
- }
1091
-
1092
- declare interface PlaylistControlsContextValue {
1093
- play: (startTime?: number, playDuration?: number) => Promise<void>;
1094
- pause: () => void;
1095
- stop: () => void;
1096
- seekTo: (time: number) => void;
1097
- setCurrentTime: (time: number) => void;
1098
- setTrackMute: (trackIndex: number, muted: boolean) => void;
1099
- setTrackSolo: (trackIndex: number, soloed: boolean) => void;
1100
- setTrackVolume: (trackIndex: number, volume: number) => void;
1101
- setTrackPan: (trackIndex: number, pan: number) => void;
1102
- setSelection: (start: number, end: number) => void;
1103
- setSelectedTrackId: (trackId: string | null) => void;
1104
- setTimeFormat: (format: TimeFormat) => void;
1105
- formatTime: (seconds: number) => string;
1106
- zoomIn: () => void;
1107
- zoomOut: () => void;
1108
- setMasterVolume: (volume: number) => void;
1109
- setAutomaticScroll: (enabled: boolean) => void;
1110
- setScrollContainer: (element: HTMLDivElement | null) => void;
1111
- scrollContainerRef: default_2.RefObject<HTMLDivElement | null>;
1112
- setContinuousPlay: (enabled: boolean) => void;
1113
- setLinkEndpoints: (enabled: boolean) => void;
1114
- setAnnotationsEditable: (enabled: boolean) => void;
1115
- setAnnotations: default_2.Dispatch<default_2.SetStateAction<AnnotationData[]>>;
1116
- setActiveAnnotationId: (id: string | null) => void;
1117
- setLoopEnabled: (enabled: boolean) => void;
1118
- setLoopRegion: (start: number, end: number) => void;
1119
- setLoopRegionFromSelection: () => void;
1120
- clearLoopRegion: () => void;
1121
- }
1122
-
1123
- declare interface PlaylistDataContextValue {
1124
- duration: number;
1125
- audioBuffers: AudioBuffer[];
1126
- peaksDataArray: TrackClipPeaks[];
1127
- trackStates: TrackState[];
1128
- tracks: ClipTrack[];
1129
- sampleRate: number;
1130
- waveHeight: number;
1131
- timeScaleHeight: number;
1132
- minimumPlaylistHeight: number;
1133
- controls: {
1134
- show: boolean;
1135
- width: number;
1136
- };
1137
- playoutRef: default_2.RefObject<PlaylistEngine | null>;
1138
- samplesPerPixel: number;
1139
- timeFormat: TimeFormat;
1140
- masterVolume: number;
1141
- canZoomIn: boolean;
1142
- canZoomOut: boolean;
1143
- barWidth: number;
1144
- barGap: number;
1145
- /** Width in pixels of progress bars. Defaults to barWidth + barGap (fills gaps). */
1146
- progressBarWidth: number;
1147
- /** Whether the playlist has finished loading all tracks */
1148
- isReady: boolean;
1149
- /** Whether tracks are rendered in mono mode */
1150
- mono: boolean;
1151
- /** Ref set by useClipDragHandlers during boundary trim drags.
1152
- * When true, loadAudio skips engine rebuild — visual updates flow via React state only. */
1153
- isDraggingRef: default_2.MutableRefObject<boolean>;
1154
- onTracksChange: ((tracks: ClipTrack[]) => void) | undefined;
1155
- }
1156
-
1157
- declare interface PlaylistStateContextValue {
1158
- continuousPlay: boolean;
1159
- linkEndpoints: boolean;
1160
- annotationsEditable: boolean;
1161
- isAutomaticScroll: boolean;
1162
- isLoopEnabled: boolean;
1163
- annotations: AnnotationData[];
1164
- activeAnnotationId: string | null;
1165
- selectionStart: number;
1166
- selectionEnd: number;
1167
- selectedTrackId: string | null;
1168
- loopStart: number;
1169
- loopEnd: number;
1170
- /** Whether playback continues past the end of loaded audio */
1171
- indefinitePlayback: boolean;
1172
- }
1173
-
1174
- /**
1175
- * Standalone playlist visualization component (WebAudio version).
1176
- *
1177
- * Renders the waveform tracks, timescale, annotations boxes, selection,
1178
- * playhead, loop regions, and track controls — everything that lives
1179
- * inside <Playlist> plus wrapping providers.
1180
- *
1181
- * Does NOT render AnnotationText (the annotation list below the waveform).
1182
- * Pair with PlaylistAnnotationList for a full annotation editing UI.
1183
- */
1184
- export declare const PlaylistVisualization: default_2.FC<PlaylistVisualizationProps>;
1185
-
1186
- export declare interface PlaylistVisualizationProps {
1187
- renderTrackControls?: (trackIndex: number) => ReactNode;
1188
- renderTick?: (label: string, pixelPosition: number) => ReactNode;
1189
- /** Custom playhead render function. Receives position (pixels) and color from theme. */
1190
- renderPlayhead?: RenderPlayheadFunction;
1191
- annotationControls?: AnnotationAction[];
1192
- /**
1193
- * Custom function to generate the label shown on annotation boxes in the waveform.
1194
- * Receives the annotation data and its index, returns a string label.
1195
- * Default: annotation.id
1196
- */
1197
- getAnnotationBoxLabel?: GetAnnotationBoxLabelFn;
1198
- className?: string;
1199
- showClipHeaders?: boolean;
1200
- interactiveClips?: boolean;
1201
- showFades?: boolean;
1202
- /**
1203
- * Enable mobile-optimized touch interactions.
1204
- * When true, increases touch target sizes for clip boundaries.
1205
- * Use with useDragSensors({ touchOptimized: true }) for best results.
1206
- */
1207
- touchOptimized?: boolean;
1208
- /** Callback when a track's close button is clicked. Only renders close button when provided. */
1209
- onRemoveTrack?: (trackIndex: number) => void;
1210
- recordingState?: {
1211
- isRecording: boolean;
1212
- trackId: string;
1213
- startSample: number;
1214
- durationSamples: number;
1215
- peaks: (Int8Array | Int16Array)[];
1216
- bits: 8 | 16;
1217
- };
1218
- }
1219
-
1220
- /**
1221
- * Props passed to the renderAnnotationItem function for custom rendering.
1222
- */
1223
- declare interface RenderAnnotationItemProps {
1224
- annotation: AnnotationData;
1225
- index: number;
1226
- isActive: boolean;
1227
- onClick: () => void;
1228
- formatTime: (seconds: number) => string;
1229
- }
1230
-
1231
- /** Render mode for a track's visualization */
1232
- declare type RenderMode = 'waveform' | 'spectrogram' | 'both' | 'piano-roll';
1233
-
1234
- /**
1235
- * Type for custom playhead render functions.
1236
- * Receives position, color, and animation refs for smooth 60fps animation.
1237
- * Custom playheads should use requestAnimationFrame with the refs during playback.
1238
- */
1239
- declare type RenderPlayheadFunction = (props: PlayheadProps) => react__default.ReactNode;
1240
-
1241
- export declare const RewindButton: default_2.FC<{
1242
- className?: string;
1243
- }>;
1244
-
1245
- /**
1246
- * Selection time inputs that use the playlist context
1247
- */
1248
- export declare const SelectionTimeInputs: default_2.FC<{
1249
- className?: string;
1250
- }>;
1251
-
1252
- export declare const SetLoopRegionButton: default_2.FC<{
1253
- className?: string;
1254
- }>;
1255
-
1256
- export declare const SkipBackwardButton: default_2.FC<{
1257
- skipAmount?: number;
1258
- className?: string;
1259
- }>;
1260
-
1261
- export declare const SkipForwardButton: default_2.FC<{
1262
- skipAmount?: number;
1263
- className?: string;
1264
- }>;
1265
-
1266
- declare type SnapTo = 'bar' | 'beat' | 'off';
1267
-
1268
- declare interface SnapToGridBeatsOptions {
1269
- mode: 'beats';
1270
- snapTo: SnapTo;
1271
- bpm: number;
1272
- timeSignature: [number, number];
1273
- samplesPerPixel: number;
1274
- sampleRate: number;
1275
- }
1276
-
1277
- /**
1278
- * dnd-kit modifier that quantizes clip drag movement to a grid.
1279
- *
1280
- * Two modes:
1281
- * - "beats": Snaps to beat/bar grid using PPQN tick space for exact musical timing.
1282
- * - "timescale": Snaps to a sample-based grid derived from timescale markers.
1283
- *
1284
- * Designed to compose with ClipCollisionModifier — snap first,
1285
- * then collision constrains the snapped position.
1286
- */
1287
- export declare class SnapToGridModifier extends Modifier<DragDropManager<any, any>, SnapToGridOptions> {
1288
- apply(operation: DragOperation): {
1289
- x: number;
1290
- y: number;
1291
- };
1292
- static configure: (options: SnapToGridBeatsOptions | SnapToGridTimescaleOptions) => PluginDescriptor<any, any, typeof SnapToGridModifier>;
1293
- }
1294
-
1295
- declare type SnapToGridOptions = SnapToGridBeatsOptions | SnapToGridTimescaleOptions;
1296
-
1297
- declare interface SnapToGridTimescaleOptions {
1298
- mode: 'timescale';
1299
- gridSamples: number;
1300
- samplesPerPixel: number;
1301
- }
1302
-
1303
- /**
1304
- * Caches parsed SoundFont2 data and AudioBuffers for efficient playback.
1305
- *
1306
- * AudioBuffers are created lazily on first access and cached by sample index.
1307
- * Pitch calculation uses the SF2 generator chain:
1308
- * OverridingRootKey → sample.header.originalPitch → fallback 60
1309
- *
1310
- * Audio graph per note:
1311
- * AudioBufferSourceNode (playbackRate for pitch) → GainNode (velocity) → track chain
1312
- */
1313
- declare class SoundFontCache {
1314
- private sf2;
1315
- private audioBufferCache;
1316
- private context;
1317
- /**
1318
- * @param context Optional AudioContext for createBuffer(). If omitted, uses
1319
- * an OfflineAudioContext which doesn't require user gesture — safe to
1320
- * construct before user interaction (avoids Firefox autoplay warnings).
1321
- */
1322
- constructor(context?: BaseAudioContext);
1323
- /**
1324
- * Load and parse an SF2 file from a URL.
1325
- */
1326
- load(url: string, signal?: AbortSignal): Promise<void>;
1327
- /**
1328
- * Load from an already-fetched ArrayBuffer.
1329
- */
1330
- loadFromBuffer(data: ArrayBuffer): void;
1331
- get isLoaded(): boolean;
1332
- /**
1333
- * Look up a MIDI note and return the AudioBuffer + playbackRate.
1334
- *
1335
- * @param midiNote - MIDI note number (0-127)
1336
- * @param bankNumber - Bank number (0 for melodic, 128 for percussion/drums)
1337
- * @param presetNumber - GM program number (0-127)
1338
- * @returns SoundFontSample or null if no sample found for this note
1339
- */
1340
- getAudioBuffer(midiNote: number, bankNumber?: number, presetNumber?: number): SoundFontSample | null;
1341
- /**
1342
- * Convert Int16Array sample data to an AudioBuffer.
1343
- * Uses the extracted int16ToFloat32 for the conversion, then copies into an AudioBuffer.
1344
- */
1345
- private int16ToAudioBuffer;
1346
- /**
1347
- * Clear all cached AudioBuffers and release the parsed SF2.
1348
- */
1349
- dispose(): void;
1350
- }
1351
-
1352
- /**
1353
- * Result of looking up a MIDI note in the SoundFont.
1354
- * Contains the AudioBuffer, playbackRate, loop points, and volume envelope.
1355
- */
1356
- declare interface SoundFontSample {
1357
- /** Cached AudioBuffer for this sample */
1358
- buffer: AudioBuffer;
1359
- /** Playback rate to pitch-shift from originalPitch to target note */
1360
- playbackRate: number;
1361
- /** Loop mode: 0=no loop, 1=continuous, 3=sustain loop */
1362
- loopMode: number;
1363
- /** Loop start in seconds, relative to AudioBuffer start */
1364
- loopStart: number;
1365
- /** Loop end in seconds, relative to AudioBuffer start */
1366
- loopEnd: number;
1367
- /** Volume envelope attack time in seconds */
1368
- attackVolEnv: number;
1369
- /** Volume envelope hold time in seconds */
1370
- holdVolEnv: number;
1371
- /** Volume envelope decay time in seconds */
1372
- decayVolEnv: number;
1373
- /** Volume envelope sustain level as linear gain 0-1 */
1374
- sustainVolEnv: number;
1375
- /** Volume envelope release time in seconds */
1376
- releaseVolEnv: number;
1377
- }
1378
-
1379
- /**
1380
- * Configuration for spectrogram computation and rendering.
1381
- */
1382
- declare interface SpectrogramConfig {
1383
- /** FFT size: 256–8192, must be power of 2. Default: 2048 */
1384
- fftSize?: FFTSize;
1385
- /** Hop size between frames in samples. Default: fftSize / 4 */
1386
- hopSize?: number;
1387
- /** Window function applied before FFT. Default: 'hann' */
1388
- windowFunction?: 'hann' | 'hamming' | 'blackman' | 'rectangular' | 'bartlett' | 'blackman-harris';
1389
- /** Window function parameter (0-1), used by some window functions */
1390
- alpha?: number;
1391
- /** Frequency axis scale. Default: 'mel' */
1392
- frequencyScale?: 'linear' | 'logarithmic' | 'mel' | 'bark' | 'erb';
1393
- /** Minimum frequency in Hz. Default: 0 */
1394
- minFrequency?: number;
1395
- /** Maximum frequency in Hz. Default: sampleRate / 2 */
1396
- maxFrequency?: number;
1397
- /** Display brightness boost in dB. Default: 20 */
1398
- gainDb?: number;
1399
- /** Signal range in dB. Default: 80 */
1400
- rangeDb?: number;
1401
- /** Zero padding factor: actual FFT length = fftSize * zeroPaddingFactor. Default: 2 */
1402
- zeroPaddingFactor?: number;
1403
- /** Show frequency axis labels. Default: false */
1404
- labels?: boolean;
1405
- /** Label text color */
1406
- labelsColor?: string;
1407
- /** Label background color */
1408
- labelsBackground?: string;
1409
- }
1410
-
1411
- export declare interface SpectrogramIntegration {
1412
- trackSpectrogramOverrides: Map<string, TrackSpectrogramOverrides>;
1413
- spectrogramWorkerApi: SpectrogramWorkerApi | null;
1414
- spectrogramConfig?: SpectrogramConfig;
1415
- spectrogramColorMap?: ColorMapValue;
1416
- setTrackRenderMode: (trackId: string, mode: RenderMode) => void;
1417
- setTrackSpectrogramConfig: (trackId: string, config: SpectrogramConfig, colorMap?: ColorMapValue) => void;
1418
- registerSpectrogramCanvases: (clipId: string, channelIndex: number, canvasIds: string[], canvasWidths: number[]) => void;
1419
- unregisterSpectrogramCanvases: (clipId: string, channelIndex: number) => void;
1420
- /** Render spectrogram menu items for a track's context menu */
1421
- renderMenuItems?: (props: {
1422
- renderMode: string;
1423
- onRenderModeChange: (mode: RenderMode) => void;
1424
- onOpenSettings: () => void;
1425
- onClose?: () => void;
1426
- }) => TrackMenuItem[];
1427
- /** Settings modal component provided by the spectrogram package */
1428
- SettingsModal?: React.ComponentType<{
1429
- open: boolean;
1430
- onClose: () => void;
1431
- config: SpectrogramConfig;
1432
- colorMap: ColorMapValue;
1433
- onApply: (config: SpectrogramConfig, colorMap: ColorMapValue) => void;
1434
- }>;
1435
- /** Get color lookup table for a color map name */
1436
- getColorMap: (name: ColorMapValue) => Uint8Array;
1437
- /** Get frequency scale function for a scale name */
1438
- getFrequencyScale: (name: string) => (f: number, minF: number, maxF: number) => number;
1439
- }
1440
-
1441
- export declare const SpectrogramIntegrationProvider: Provider<SpectrogramIntegration | null>;
1442
-
1443
- /** Minimal type for the worker API surface used by browser components */
1444
- declare interface SpectrogramWorkerApi {
1445
- registerCanvas: (canvasId: string, canvas: OffscreenCanvas) => void;
1446
- unregisterCanvas: (canvasId: string) => void;
1447
- }
1448
-
1449
- export declare const StopButton: default_2.FC<{
1450
- className?: string;
1451
- }>;
1452
-
1453
- /**
1454
- * Time format utilities for displaying and parsing audio timestamps
1455
- */
1456
- export declare type TimeFormat = 'seconds' | 'thousandths' | 'hh:mm:ss' | 'hh:mm:ss.u' | 'hh:mm:ss.uu' | 'hh:mm:ss.uuu';
1457
-
1458
- export declare interface TimeFormatControls {
1459
- timeFormat: TimeFormat;
1460
- setTimeFormat: (format: TimeFormat) => void;
1461
- formatTime: (seconds: number) => string;
1462
- parseTime: (timeString: string) => number;
1463
- }
1464
-
1465
- /**
1466
- * Time format selector that uses the playlist context
1467
- */
1468
- export declare const TimeFormatSelect: default_2.FC<{
1469
- className?: string;
1470
- }>;
1471
-
1472
- export { Tone }
1473
-
1474
- export declare interface TrackActiveEffect {
1475
- instanceId: string;
1476
- effectId: string;
1477
- definition: EffectDefinition;
1478
- params: Record<string, number | string | boolean>;
1479
- bypassed: boolean;
1480
- }
1481
-
1482
- declare type TrackClipPeaks = ClipPeaks[];
1483
-
1484
- export declare type TrackEffectsFunction = (graphEnd: Gain, masterGainNode: ToneAudioNode, isOffline: boolean) => void | (() => void);
1485
-
1486
- /**
1487
- * Generic effects function type for track-level audio processing.
1488
- *
1489
- * The actual implementation receives Tone.js audio nodes. Using generic types
1490
- * here to avoid circular dependencies with the playout package.
1491
- *
1492
- * @param graphEnd - The end of the track's audio graph (Tone.js Gain node)
1493
- * @param destination - Where to connect the effects output (Tone.js ToneAudioNode)
1494
- * @param isOffline - Whether rendering offline (for export)
1495
- * @returns Optional cleanup function called when track is disposed
1496
- *
1497
- * @example
1498
- * ```typescript
1499
- * const trackEffects: TrackEffectsFunction = (graphEnd, destination, isOffline) => {
1500
- * const reverb = new Tone.Reverb({ decay: 1.5 });
1501
- * graphEnd.connect(reverb);
1502
- * reverb.connect(destination);
1503
- *
1504
- * return () => {
1505
- * reverb.dispose();
1506
- * };
1507
- * };
1508
- * ```
1509
- */
1510
- declare type TrackEffectsFunction_2 = (graphEnd: unknown, destination: unknown, isOffline: boolean) => void | (() => void);
1511
-
1512
- /** Function type for per-track effects (same as in @waveform-playlist/core) */
1513
- declare type TrackEffectsFunction_3 = (graphEnd: unknown, destination: unknown, isOffline: boolean) => void | (() => void);
1514
-
1515
- export declare interface TrackEffectsState {
1516
- trackId: string;
1517
- activeEffects: TrackActiveEffect[];
1518
- }
1519
-
1520
- /** Info about a track that failed to load. */
1521
- export declare interface TrackLoadError {
1522
- /** Display name of the source that failed. */
1523
- name: string;
1524
- /** The underlying error. */
1525
- error: Error;
1526
- }
1527
-
1528
- declare interface TrackMenuItem {
1529
- id: string;
1530
- label?: string;
1531
- content: ReactNode;
1532
- }
1533
-
1534
- /** A source that can be decoded into a track. */
1535
- export declare type TrackSource = File | Blob | string | {
1536
- src: string;
1537
- name?: string;
1538
- };
1539
-
1540
- /** Per-track overrides for spectrogram rendering (render mode, config, color map) */
1541
- declare interface TrackSpectrogramOverrides {
1542
- renderMode: RenderMode;
1543
- config?: SpectrogramConfig;
1544
- colorMap?: ColorMapValue;
1545
- }
1546
-
1547
- export declare interface TrackState {
1548
- name: string;
1549
- muted: boolean;
1550
- soloed: boolean;
1551
- volume: number;
1552
- pan: number;
1553
- }
1554
-
1555
- declare interface TrackState_2 {
1556
- muted: boolean;
1557
- soloed: boolean;
1558
- volume: number;
1559
- pan: number;
1560
- }
1561
-
1562
- /**
1563
- * Custom hook for handling annotation drag operations (boundary trimming)
1564
- *
1565
- * Provides drag handlers for use with @dnd-kit/react DragDropProvider.
1566
- * Handles annotation boundary resizing with linked endpoints support.
1567
- *
1568
- * @example
1569
- * ```tsx
1570
- * const { onDragStart, onDragMove, onDragEnd } = useAnnotationDragHandlers({
1571
- * annotations,
1572
- * onAnnotationsChange: setAnnotations,
1573
- * samplesPerPixel,
1574
- * sampleRate,
1575
- * duration,
1576
- * linkEndpoints,
1577
- * });
1578
- *
1579
- * return (
1580
- * <DragDropProvider
1581
- * onDragStart={onDragStart}
1582
- * onDragMove={onDragMove}
1583
- * onDragEnd={onDragEnd}
1584
- * modifiers={[RestrictToHorizontalAxis]}
1585
- * >
1586
- * {renderAnnotations()}
1587
- * </DragDropProvider>
1588
- * );
1589
- * ```
1590
- */
1591
- export declare function useAnnotationDragHandlers({ annotations, onAnnotationsChange, samplesPerPixel, sampleRate, duration, linkEndpoints, }: UseAnnotationDragHandlersOptions): {
1592
- onDragStart: (event: Parameters<DragStartEvent>[0]) => void;
1593
- onDragMove: (event: Parameters<DragMoveEvent>[0]) => void;
1594
- onDragEnd: (event: Parameters<DragEndEvent>[0]) => void;
1595
- };
1596
-
1597
- declare interface UseAnnotationDragHandlersOptions {
1598
- annotations: AnnotationData[];
1599
- onAnnotationsChange: (annotations: AnnotationData[]) => void;
1600
- samplesPerPixel: number;
1601
- sampleRate: number;
1602
- duration: number;
1603
- linkEndpoints: boolean;
1604
- }
1605
-
1606
- /**
1607
- * Hook to access annotation integration provided by @waveform-playlist/annotations.
1608
- * Throws if used without <AnnotationProvider> wrapping the component tree.
1609
- *
1610
- * Follows the Kent C. Dodds pattern:
1611
- * https://kentcdodds.com/blog/how-to-use-react-context-effectively
1612
- */
1613
- export declare function useAnnotationIntegration(): AnnotationIntegration;
1614
-
1615
- /**
1616
- * Hook for keyboard-based annotation navigation and boundary editing
1617
- *
1618
- * Navigation Shortcuts:
1619
- * - ArrowUp / ArrowLeft = Select previous annotation
1620
- * - ArrowDown / ArrowRight = Select next annotation
1621
- * - Home = Select first annotation
1622
- * - End = Select last annotation
1623
- * - Escape = Deselect annotation
1624
- * - Enter = Play selected annotation
1625
- *
1626
- * Boundary Editing Shortcuts (requires active annotation):
1627
- * - [ = Move start boundary earlier (left)
1628
- * - ] = Move start boundary later (right)
1629
- * - Shift+[ = Move end boundary earlier (left)
1630
- * - Shift+] = Move end boundary later (right)
1631
- *
1632
- * Respects linkEndpoints and continuousPlay settings.
1633
- *
1634
- * @example
1635
- * ```tsx
1636
- * useAnnotationKeyboardControls({
1637
- * annotations,
1638
- * activeAnnotationId,
1639
- * onAnnotationsChange: setAnnotations,
1640
- * onActiveAnnotationChange: setActiveAnnotationId,
1641
- * duration,
1642
- * linkEndpoints,
1643
- * });
1644
- * ```
1645
- */
1646
- export declare function useAnnotationKeyboardControls({ annotations, activeAnnotationId, onAnnotationsChange, onActiveAnnotationChange, duration, linkEndpoints, continuousPlay, enabled, scrollContainerRef, samplesPerPixel, sampleRate, onPlay, }: UseAnnotationKeyboardControlsOptions): {
1647
- moveStartBoundary: (delta: number) => void;
1648
- moveEndBoundary: (delta: number) => void;
1649
- selectPrevious: () => void;
1650
- selectNext: () => void;
1651
- selectFirst: () => void;
1652
- selectLast: () => void;
1653
- clearSelection: () => void;
1654
- scrollToAnnotation: (annotationId: string) => void;
1655
- playActiveAnnotation: () => void;
1656
- };
1657
-
1658
- declare interface UseAnnotationKeyboardControlsOptions {
1659
- annotations: AnnotationData[];
1660
- activeAnnotationId: string | null;
1661
- onAnnotationsChange: (annotations: AnnotationData[]) => void;
1662
- /** Callback to set the active annotation ID for selection */
1663
- onActiveAnnotationChange?: (id: string | null) => void;
1664
- duration: number;
1665
- linkEndpoints: boolean;
1666
- /** Whether continuous play is enabled (affects playback duration) */
1667
- continuousPlay?: boolean;
1668
- enabled?: boolean;
1669
- /** Optional: scroll container ref for auto-scrolling to annotation */
1670
- scrollContainerRef?: React.RefObject<HTMLDivElement | null>;
1671
- /** Optional: samples per pixel for scroll position calculation */
1672
- samplesPerPixel?: number;
1673
- /** Optional: sample rate for scroll position calculation */
1674
- sampleRate?: number;
1675
- /** Optional: callback to start playback at a time with optional duration */
1676
- onPlay?: (startTime: number, duration?: number) => void;
1677
- }
1678
-
1679
- /**
1680
- * Hook to load audio from URLs and convert to ClipTrack format
1681
- *
1682
- * This hook fetches audio files, decodes them, and creates ClipTrack objects
1683
- * with a single clip per track. Supports custom positioning for multi-clip arrangements.
1684
- *
1685
- * @param configs - Array of audio track configurations
1686
- * @param options - Optional configuration for loading behavior
1687
- * @returns Object with tracks array, loading state, and progress info
1688
- *
1689
- * @example
1690
- * ```typescript
1691
- * // Basic usage (clips positioned at start)
1692
- * const { tracks, loading, error } = useAudioTracks([
1693
- * { src: 'audio/vocals.mp3', name: 'Vocals' },
1694
- * { src: 'audio/drums.mp3', name: 'Drums' },
1695
- * ]);
1696
- *
1697
- * // Immediate rendering with deferred engine build (recommended for multi-track)
1698
- * const { tracks, loading } = useAudioTracks(
1699
- * [
1700
- * { src: 'audio/vocals.mp3', name: 'Vocals', duration: 30 },
1701
- * { src: 'audio/drums.mp3', name: 'Drums', duration: 30 },
1702
- * ],
1703
- * { immediate: true }
1704
- * );
1705
- * // All tracks render instantly as placeholders, peaks fill in as files load
1706
- * return (
1707
- * <WaveformPlaylistProvider tracks={tracks} deferEngineRebuild={loading}>
1708
- * ...
1709
- * </WaveformPlaylistProvider>
1710
- * );
1711
- *
1712
- * // Pre-loaded AudioBuffer (skip fetch/decode)
1713
- * const { tracks } = useAudioTracks([
1714
- * { audioBuffer: myPreloadedBuffer, name: 'Pre-loaded' },
1715
- * ]);
1716
- *
1717
- * // Peaks-first rendering (instant visual, audio loads later)
1718
- * const { tracks } = useAudioTracks([
1719
- * { waveformData: preloadedPeaks, name: 'Peaks Only' }, // Renders immediately
1720
- * ]);
1721
- * ```
1722
- */
1723
- export declare function useAudioTracks(configs: AudioTrackConfig[], options?: UseAudioTracksOptions): {
1724
- tracks: ClipTrack[];
1725
- loading: boolean;
1726
- error: string | null;
1727
- loadedCount: number;
1728
- totalCount: number;
1729
- };
1730
-
1731
- /**
1732
- * Options for useAudioTracks hook
1733
- */
1734
- declare interface UseAudioTracksOptions {
1735
- /**
1736
- * When true, all tracks render immediately as placeholders with clip geometry
1737
- * from the config. Audio fills in progressively as files decode, and peaks
1738
- * render as each buffer becomes available. Use with `deferEngineRebuild={loading}`
1739
- * on the provider for a single engine build when all tracks are ready.
1740
- *
1741
- * Requires `duration` or `waveformData` in each config so clip dimensions are known upfront.
1742
- * Default: false
1743
- */
1744
- immediate?: boolean;
1745
- /** @deprecated Use `immediate` instead. */
1746
- progressive?: boolean;
1747
- }
1748
-
1749
- /**
1750
- * Custom hook for handling clip drag operations (movement and trimming)
1751
- *
1752
- * Provides drag handlers for use with @dnd-kit/react DragDropProvider.
1753
- * Handles both clip movement (dragging entire clips) and boundary trimming (adjusting clip edges).
1754
- *
1755
- * Collision detection for clip moves is handled by `ClipCollisionModifier` (passed to DragDropProvider).
1756
- *
1757
- * **Move:** `onDragEnd` delegates to `engine.moveClip()` in one shot.
1758
- *
1759
- * **Trim:** `onDragMove` updates React state per-frame via `onTracksChange` for smooth
1760
- * visual feedback (using cumulative deltas from the original clip snapshot). `isDraggingRef`
1761
- * prevents loadAudio from rebuilding the engine during the drag, so the engine keeps the
1762
- * original clip positions. On drag end, `engine.trimClip()` commits the final delta.
1763
- *
1764
- * @example
1765
- * ```tsx
1766
- * const { onDragStart, onDragMove, onDragEnd } = useClipDragHandlers({
1767
- * tracks,
1768
- * onTracksChange: setTracks,
1769
- * samplesPerPixel,
1770
- * sampleRate,
1771
- * engineRef: playoutRef,
1772
- * isDraggingRef,
1773
- * });
1774
- *
1775
- * return (
1776
- * <DragDropProvider
1777
- * onDragStart={onDragStart}
1778
- * onDragMove={onDragMove}
1779
- * onDragEnd={onDragEnd}
1780
- * modifiers={[RestrictToHorizontalAxis, ClipCollisionModifier.configure({ tracks, samplesPerPixel })]}
1781
- * >
1782
- * <Waveform showClipHeaders={true} />
1783
- * </DragDropProvider>
1784
- * );
1785
- * ```
1786
- */
1787
- export declare function useClipDragHandlers({ tracks, onTracksChange, samplesPerPixel, sampleRate, engineRef, isDraggingRef, snapSamplePosition, }: UseClipDragHandlersOptions): {
1788
- onDragStart: (event: Parameters<DragStartEvent>[0]) => void;
1789
- onDragMove: (event: Parameters<DragMoveEvent>[0]) => void;
1790
- onDragEnd: (event: Parameters<DragEndEvent>[0]) => void;
1791
- };
1792
-
1793
- declare interface UseClipDragHandlersOptions {
1794
- tracks: ClipTrack[];
1795
- onTracksChange: (tracks: ClipTrack[]) => void;
1796
- samplesPerPixel: number;
1797
- sampleRate: number;
1798
- engineRef: default_2.RefObject<PlaylistEngine | null>;
1799
- /** Ref toggled during boundary trim drags. When true, the provider's loadAudio
1800
- * skips engine rebuilds so engine keeps original clip positions. On drag end,
1801
- * engine.trimClip() commits the final delta. Obtain from usePlaylistData(). */
1802
- isDraggingRef: default_2.MutableRefObject<boolean>;
1803
- /** Optional function that snaps a sample position to the nearest grid position.
1804
- * Used for boundary trim snapping (move snapping is handled by the SnapToGridModifier). */
1805
- snapSamplePosition?: (samplePosition: number) => number;
1806
- }
1807
-
1808
- export declare function useClipInteractionEnabled(): boolean;
1809
-
1810
- /**
1811
- * Hook for splitting clips at the playhead or at a specific time
1812
- *
1813
- * Splitting delegates to `engine.splitClip()` the engine handles clip creation,
1814
- * adapter sync, and emits statechange. The provider's statechange handler propagates
1815
- * the updated tracks to the parent via `onTracksChange`.
1816
- *
1817
- * @param options - Configuration options
1818
- * @returns Object with split functions
1819
- *
1820
- * @example
1821
- * ```tsx
1822
- * const { splitClipAtPlayhead } = useClipSplitting({
1823
- * tracks,
1824
- * sampleRate,
1825
- * samplesPerPixel,
1826
- * engineRef: playoutRef,
1827
- * });
1828
- *
1829
- * // In keyboard handler
1830
- * const handleKeyPress = (e: KeyboardEvent) => {
1831
- * if (e.key === 's' || e.key === 'S') {
1832
- * splitClipAtPlayhead();
1833
- * }
1834
- * };
1835
- * ```
1836
- */
1837
- export declare const useClipSplitting: (options: UseClipSplittingOptions) => UseClipSplittingResult;
1838
-
1839
- declare interface UseClipSplittingOptions {
1840
- tracks: ClipTrack[];
1841
- sampleRate: number;
1842
- samplesPerPixel: number;
1843
- engineRef: default_2.RefObject<PlaylistEngine | null>;
1844
- }
1845
-
1846
- declare interface UseClipSplittingResult {
1847
- splitClipAtPlayhead: () => boolean;
1848
- splitClipAt: (trackIndex: number, clipIndex: number, splitTime: number) => boolean;
1849
- }
1850
-
1851
- /**
1852
- * Returns configured sensors for @dnd-kit drag operations
1853
- *
1854
- * @param options - Configuration options for drag sensors
1855
- * @returns Array of sensor constructors/descriptors for DragDropProvider's sensors prop
1856
- *
1857
- * @example
1858
- * // Desktop-optimized (default — 1px distance activation for all pointer types)
1859
- * const sensors = useDragSensors();
1860
- *
1861
- * @example
1862
- * // Mobile-optimized with custom touch delay
1863
- * const sensors = useDragSensors({ touchOptimized: true, touchDelay: 300 });
1864
- */
1865
- export declare function useDragSensors(options?: DragSensorOptions): (typeof PointerSensor | PluginDescriptor<any, any, any>)[];
1866
-
1867
- /**
1868
- * Hook for managing a dynamic chain of audio effects with real-time parameter updates
1869
- */
1870
- export declare function useDynamicEffects(fftSize?: number): UseDynamicEffectsReturn;
1871
-
1872
- export declare interface UseDynamicEffectsReturn {
1873
- activeEffects: ActiveEffect[];
1874
- availableEffects: EffectDefinition[];
1875
- addEffect: (effectId: string) => void;
1876
- removeEffect: (instanceId: string) => void;
1877
- updateParameter: (instanceId: string, paramName: string, value: number | string | boolean) => void;
1878
- toggleBypass: (instanceId: string) => void;
1879
- reorderEffects: (fromIndex: number, toIndex: number) => void;
1880
- clearAllEffects: () => void;
1881
- masterEffects: EffectsFunction;
1882
- /**
1883
- * Creates a fresh effects function for offline rendering.
1884
- * This creates new effect instances that work in the offline AudioContext.
1885
- */
1886
- createOfflineEffectsFunction: () => EffectsFunction | undefined;
1887
- analyserRef: React.RefObject<Analyser | null>;
1888
- }
1889
-
1890
- export declare function useDynamicTracks(): UseDynamicTracksReturn;
1891
-
1892
- export declare interface UseDynamicTracksReturn {
1893
- /**
1894
- * Current tracks array (placeholders + loaded). Pass to WaveformPlaylistProvider.
1895
- * Placeholder tracks have `clips: []` and names ending with " (loading...)".
1896
- */
1897
- tracks: ClipTrack[];
1898
- /** Add one or more sources — creates placeholder tracks immediately. */
1899
- addTracks: (sources: TrackSource[]) => void;
1900
- /** Remove a track by its id. Aborts in-flight fetch/decode if still loading. */
1901
- removeTrack: (trackId: string) => void;
1902
- /** Number of sources currently decoding. */
1903
- loadingCount: number;
1904
- /** True when any source is still decoding. */
1905
- isLoading: boolean;
1906
- /** Tracks that failed to load (removed from `tracks` automatically). */
1907
- errors: TrackLoadError[];
1908
- }
1909
-
1910
- /**
1911
- * Hook for exporting the waveform playlist to WAV format
1912
- * Uses OfflineAudioContext for fast, non-real-time rendering
1913
- */
1914
- export declare function useExportWav(): UseExportWavReturn;
1915
-
1916
- export declare interface UseExportWavReturn {
1917
- /** Export the playlist to WAV */
1918
- exportWav: (tracks: ClipTrack[], trackStates: TrackState_2[], options?: ExportOptions) => Promise<ExportResult>;
1919
- /** Whether export is in progress */
1920
- isExporting: boolean;
1921
- /** Export progress (0-1) */
1922
- progress: number;
1923
- /** Error message if export failed */
1924
- error: string | null;
1925
- }
1926
-
1927
- /**
1928
- * Hook for managing keyboard shortcuts
1929
- *
1930
- * @param options - Configuration options
1931
- *
1932
- * @example
1933
- * ```tsx
1934
- * useKeyboardShortcuts({
1935
- * shortcuts: [
1936
- * {
1937
- * key: ' ',
1938
- * action: togglePlayPause,
1939
- * description: 'Play/Pause',
1940
- * preventDefault: true,
1941
- * },
1942
- * {
1943
- * key: 's',
1944
- * action: splitClipAtPlayhead,
1945
- * description: 'Split clip at playhead',
1946
- * preventDefault: true,
1947
- * },
1948
- * ],
1949
- * });
1950
- * ```
1951
- */
1952
- export declare const useKeyboardShortcuts: (options: UseKeyboardShortcutsOptions) => void;
1953
-
1954
- declare interface UseKeyboardShortcutsOptions {
1955
- shortcuts: KeyboardShortcut[];
1956
- enabled?: boolean;
1957
- }
1958
-
1959
- /**
1960
- * Hook for master effects with frequency analyzer
1961
- * Returns the analyser ref and the effects function to pass to WaveformPlaylistProvider
1962
- *
1963
- * For more advanced effects (reverb, delay, filters, etc.), use useDynamicEffects instead.
1964
- */
1965
- export declare const useMasterAnalyser: (fftSize?: number) => {
1966
- analyserRef: MutableRefObject<Analyser | null>;
1967
- masterEffects: EffectsFunction;
1968
- };
1969
-
1970
- /**
1971
- * Hook for managing master volume via PlaylistEngine delegation.
1972
- *
1973
- * setMasterVolume delegates to the engine. State is mirrored back from
1974
- * the engine via onEngineState(), which the provider's statechange
1975
- * handler calls on every engine event.
1976
- */
1977
- export declare function useMasterVolume({ engineRef, initialVolume, }: UseMasterVolumeProps): MasterVolumeControls & {
1978
- onEngineState: (state: EngineState) => void;
1979
- };
1980
-
1981
- declare interface UseMasterVolumeProps {
1982
- engineRef: RefObject<PlaylistEngine | null>;
1983
- initialVolume?: number;
1984
- }
1985
-
1986
- export declare const useMediaElementAnimation: () => MediaElementAnimationContextValue;
1987
-
1988
- export declare const useMediaElementControls: () => MediaElementControlsContextValue;
1989
-
1990
- export declare const useMediaElementData: () => MediaElementDataContextValue;
1991
-
1992
- export declare const useMediaElementState: () => MediaElementStateContextValue;
1993
-
1994
- export declare function useOutputMeter(options?: UseOutputMeterOptions): UseOutputMeterReturn;
1995
-
1996
- /**
1997
- * Hook for monitoring master output levels
1998
- *
1999
- * Connects an AudioWorklet meter processor to the Destination node for
2000
- * real-time output level monitoring. Computes sample-accurate peak and
2001
- * RMS via the meter worklet — no transient is missed.
2002
- *
2003
- * IMPORTANT: Uses getGlobalContext() from playout to ensure the meter
2004
- * is created on the same AudioContext as the audio engine. Tone.js's
2005
- * getContext()/getDestination() return the DEFAULT context, which is
2006
- * replaced when getGlobalContext() calls setContext() on first audio init.
2007
- */
2008
- export declare interface UseOutputMeterOptions {
2009
- /**
2010
- * Number of channels to meter.
2011
- * Default: 2 (stereo output)
2012
- */
2013
- channelCount?: number;
2014
- /**
2015
- * How often to update the levels (in Hz).
2016
- * Default: 60 (60fps)
2017
- */
2018
- updateRate?: number;
2019
- /**
2020
- * Whether audio is currently playing. When this transitions to false,
2021
- * all levels (current, peak, RMS) and smoothed state are reset to zero.
2022
- * Without this, the browser's tail-time optimization stops calling the
2023
- * worklet's process() when no audio flows, leaving the last non-zero
2024
- * levels frozen in state.
2025
- * Default: false
2026
- */
2027
- isPlaying?: boolean;
2028
- }
2029
-
2030
- export declare interface UseOutputMeterReturn {
2031
- /** Per-channel peak output levels (0-1) */
2032
- levels: number[];
2033
- /** Per-channel held peak levels (0-1) */
2034
- peakLevels: number[];
2035
- /** Per-channel RMS output levels (0-1) */
2036
- rmsLevels: number[];
2037
- /** Reset all held peak levels to 0 */
2038
- resetPeak: () => void;
2039
- /** Error from meter setup (worklet load failure, context issues, etc.) */
2040
- error: Error | null;
2041
- }
2042
-
2043
- export declare const usePlaybackAnimation: () => PlaybackAnimationContextValue;
2044
-
2045
- /**
2046
- * Hook that provides common playback keyboard shortcuts for the playlist.
2047
- *
2048
- * Default shortcuts:
2049
- * - `Space` - Toggle play/pause
2050
- * - `Escape` - Stop playback
2051
- * - `0` - Rewind to start (seek to time 0)
2052
- *
2053
- * @example
2054
- * ```tsx
2055
- * // Basic usage - enables default shortcuts
2056
- * usePlaybackShortcuts();
2057
- *
2058
- * // With additional custom shortcuts
2059
- * usePlaybackShortcuts({
2060
- * additionalShortcuts: [
2061
- * { key: 's', action: splitClipAtPlayhead, description: 'Split clip' },
2062
- * ],
2063
- * });
2064
- *
2065
- * // Completely override shortcuts
2066
- * usePlaybackShortcuts({
2067
- * shortcuts: [
2068
- * { key: 'Home', action: rewindToStart, description: 'Go to start' },
2069
- * ],
2070
- * });
2071
- * ```
2072
- */
2073
- export declare const usePlaybackShortcuts: (options?: UsePlaybackShortcutsOptions) => UsePlaybackShortcutsReturn;
2074
-
2075
- export declare interface UsePlaybackShortcutsOptions {
2076
- /**
2077
- * Enable the shortcuts. Defaults to true.
2078
- */
2079
- enabled?: boolean;
2080
- /**
2081
- * Additional shortcuts to include alongside the default playback shortcuts.
2082
- */
2083
- additionalShortcuts?: KeyboardShortcut[];
2084
- /**
2085
- * Override default shortcuts. If provided, only these shortcuts will be used.
2086
- */
2087
- shortcuts?: KeyboardShortcut[];
2088
- }
2089
-
2090
- export declare interface UsePlaybackShortcutsReturn {
2091
- /** Rewind to the beginning (time = 0) */
2092
- rewindToStart: () => void;
2093
- /** Toggle play/pause */
2094
- togglePlayPause: () => void;
2095
- /** Stop playback and return to start position */
2096
- stopPlayback: () => void;
2097
- /** The list of active keyboard shortcuts */
2098
- shortcuts: KeyboardShortcut[];
2099
- }
2100
-
2101
- export declare const usePlaylistControls: () => PlaylistControlsContextValue;
2102
-
2103
- export declare const usePlaylistData: () => PlaylistDataContextValue;
2104
-
2105
- export declare const usePlaylistState: () => PlaylistStateContextValue;
2106
-
2107
- /**
2108
- * Hook to access spectrogram integration provided by @waveform-playlist/spectrogram.
2109
- * Throws if used without <SpectrogramProvider> wrapping the component tree.
2110
- *
2111
- * Follows the Kent C. Dodds pattern:
2112
- * https://kentcdodds.com/blog/how-to-use-react-context-effectively
2113
- */
2114
- export declare function useSpectrogramIntegration(): SpectrogramIntegration;
2115
-
2116
- /**
2117
- * Hook to manage time format state
2118
- *
2119
- * @example
2120
- * ```tsx
2121
- * const { timeFormat, setTimeFormat, formatTime, parseTime } = useTimeFormat();
2122
- *
2123
- * <TimeFormatSelect
2124
- * value={timeFormat}
2125
- * onChange={setTimeFormat}
2126
- * />
2127
- * <span>{formatTime(currentTime)}</span>
2128
- * <input onChange={(e) => seekTo(parseTime(e.target.value))} />
2129
- * ```
2130
- */
2131
- export declare function useTimeFormat(): TimeFormatControls;
2132
-
2133
- /**
2134
- * Hook for managing dynamic effects per track with real-time parameter updates
2135
- */
2136
- export declare function useTrackDynamicEffects(): UseTrackDynamicEffectsReturn;
2137
-
2138
- export declare interface UseTrackDynamicEffectsReturn {
2139
- trackEffectsState: Map<string, TrackActiveEffect[]>;
2140
- addEffectToTrack: (trackId: string, effectId: string) => void;
2141
- removeEffectFromTrack: (trackId: string, instanceId: string) => void;
2142
- updateTrackEffectParameter: (trackId: string, instanceId: string, paramName: string, value: number | string | boolean) => void;
2143
- toggleBypass: (trackId: string, instanceId: string) => void;
2144
- clearTrackEffects: (trackId: string) => void;
2145
- getTrackEffectsFunction: (trackId: string) => TrackEffectsFunction | undefined;
2146
- /**
2147
- * Creates a fresh effects function for a track for offline rendering.
2148
- * This creates new effect instances that work in the offline AudioContext.
2149
- */
2150
- createOfflineTrackEffectsFunction: (trackId: string) => TrackEffectsFunction | undefined;
2151
- availableEffects: EffectDefinition[];
2152
- }
2153
-
2154
- /**
2155
- * Hook for managing zoom controls via PlaylistEngine delegation.
2156
- *
2157
- * zoomIn/zoomOut delegate to the engine. State is mirrored back from
2158
- * the engine via onEngineState(), which the provider's statechange
2159
- * handler calls on every engine event.
2160
- *
2161
- * samplesPerPixel updates use startTransition so React treats them as
2162
- * non-urgent — during playback, animation RAF callbacks interleave
2163
- * with the zoom re-render instead of being blocked.
2164
- */
2165
- export declare function useZoomControls({ engineRef, initialSamplesPerPixel, }: UseZoomControlsProps): ZoomControls & {
2166
- onEngineState: (state: EngineState) => void;
2167
- };
2168
-
2169
- declare interface UseZoomControlsProps {
2170
- engineRef: RefObject<PlaylistEngine | null>;
2171
- initialSamplesPerPixel: number;
2172
- }
2173
-
2174
- /**
2175
- * Waveform visualization component that uses the playlist context.
2176
- *
2177
- * Composes PlaylistVisualization (waveform + tracks) and
2178
- * PlaylistAnnotationList (annotation text list below the waveform).
2179
- */
2180
- export declare const Waveform: default_2.FC<WaveformProps>;
2181
-
2182
- /**
2183
- * Waveform color can be a simple string or a gradient configuration
2184
- */
2185
- declare type WaveformColor = string | WaveformGradient;
2186
-
2187
- /**
2188
- * Clip-Based Model Types
2189
- *
2190
- * These types support a professional multi-track editing model where:
2191
- * - Each track can contain multiple audio clips
2192
- * - Clips can be positioned anywhere on the timeline
2193
- * - Clips have independent trim points (offset/duration)
2194
- * - Gaps between clips are silent
2195
- * - Clips can overlap (for crossfades)
2196
- */
2197
-
2198
- /**
2199
- * WaveformData object from waveform-data.js library.
2200
- * Supports resample() and slice() for dynamic zoom levels.
2201
- * See: https://github.com/bbc/waveform-data.js
2202
- */
2203
- declare interface WaveformDataObject {
2204
- /** Sample rate of the original audio */
2205
- readonly sample_rate: number;
2206
- /** Number of audio samples per pixel */
2207
- readonly scale: number;
2208
- /** Length of waveform data in pixels */
2209
- readonly length: number;
2210
- /** Bit depth (8 or 16) */
2211
- readonly bits: number;
2212
- /** Duration in seconds */
2213
- readonly duration: number;
2214
- /** Number of channels */
2215
- readonly channels: number;
2216
- /** Get channel data */
2217
- channel: (index: number) => {
2218
- min_array: () => number[];
2219
- max_array: () => number[];
2220
- };
2221
- /** Resample to different scale */
2222
- resample: (options: {
2223
- scale: number;
2224
- } | {
2225
- width: number;
2226
- }) => WaveformDataObject;
2227
- /** Slice a portion of the waveform */
2228
- slice: (options: {
2229
- startTime: number;
2230
- endTime: number;
2231
- } | {
2232
- startIndex: number;
2233
- endIndex: number;
2234
- }) => WaveformDataObject;
2235
- }
2236
-
2237
- /**
2238
- * Convert WaveformData to our internal Peaks format
2239
- *
2240
- * @param waveformData - WaveformData instance from waveform-data.js
2241
- * @param channelIndex - Channel index (0 for mono/left, 1 for right)
2242
- * @returns Peaks data with alternating min/max values, preserving original bit depth
2243
- */
2244
- export declare function waveformDataToPeaks(waveformData: default_3, channelIndex?: number): {
2245
- data: Int8Array | Int16Array;
2246
- bits: 8 | 16;
2247
- length: number;
2248
- sampleRate: number;
2249
- };
2250
-
2251
- /**
2252
- * Waveform drawing mode determines how colors are applied:
2253
- * - 'inverted': Canvas draws waveOutlineColor in areas WITHOUT audio (current default).
2254
- * waveFillColor shows through where audio peaks are. Good for gradient bars.
2255
- * - 'normal': Canvas draws waveFillColor bars where audio peaks ARE.
2256
- * waveOutlineColor is used as background. Good for gradient backgrounds.
2257
- */
2258
- declare type WaveformDrawMode = 'inverted' | 'normal';
2259
-
2260
- /**
2261
- * Gradient configuration for waveforms
2262
- * Can be applied vertically (top to bottom) or horizontally (left to right)
2263
- */
2264
- declare interface WaveformGradient {
2265
- type: 'linear';
2266
- direction: 'vertical' | 'horizontal';
2267
- stops: GradientStop[];
2268
- }
2269
-
2270
- export declare const WaveformPlaylistProvider: default_2.FC<WaveformPlaylistProviderProps>;
2271
-
2272
- declare interface WaveformPlaylistProviderProps {
2273
- tracks: ClipTrack[];
2274
- timescale?: boolean;
2275
- mono?: boolean;
2276
- waveHeight?: number;
2277
- samplesPerPixel?: number;
2278
- zoomLevels?: number[];
2279
- automaticScroll?: boolean;
2280
- theme?: Partial<WaveformPlaylistTheme>;
2281
- controls?: {
2282
- show: boolean;
2283
- width: number;
2284
- };
2285
- annotationList?: {
2286
- annotations?: AnnotationData[];
2287
- editable?: boolean;
2288
- isContinuousPlay?: boolean;
2289
- linkEndpoints?: boolean;
2290
- controls?: AnnotationAction[];
2291
- };
2292
- effects?: EffectsFunction;
2293
- onReady?: () => void;
2294
- /** @deprecated Use onAnnotationsChange instead */
2295
- onAnnotationUpdate?: (annotations: AnnotationData[]) => void;
2296
- /** Callback when annotations are changed (drag, edit, etc.) */
2297
- onAnnotationsChange?: (annotations: AnnotationData[]) => void;
2298
- /** Width in pixels of waveform bars. Default: 1 */
2299
- barWidth?: number;
2300
- /** Spacing in pixels between waveform bars. Default: 0 */
2301
- barGap?: number;
2302
- /** Width in pixels of progress bars. Default: barWidth + barGap (fills gaps). */
2303
- progressBarWidth?: number;
2304
- /** Callback when engine clip operations (move, trim, split) change tracks.
2305
- * The provider calls this so the parent can update its tracks state without
2306
- * triggering a full engine rebuild.
2307
- *
2308
- * **Important:** The parent must pass the received `tracks` reference back as
2309
- * the `tracks` prop (i.e. `setState(tracks)`). The provider uses reference
2310
- * identity (`tracks === engineTracksRef.current`) to detect engine-originated
2311
- * updates and skip the expensive `loadAudio` rebuild. */
2312
- onTracksChange?: (tracks: ClipTrack[]) => void;
2313
- /** SoundFont cache for sample-based MIDI playback. When provided, MIDI clips
2314
- * use SoundFont samples instead of PolySynth synthesis. */
2315
- soundFontCache?: SoundFontCache;
2316
- /** When true, tracks render visually but the engine build is deferred.
2317
- * Use this during progressive loading to avoid rebuilding the engine for
2318
- * each track — flip to false when all tracks are ready for a single build. */
2319
- deferEngineRebuild?: boolean;
2320
- /** Disable automatic stop when the cursor reaches the end of the longest
2321
- * track. Useful for DAW-style recording beyond existing audio. */
2322
- indefinitePlayback?: boolean;
2323
- children: ReactNode;
2324
- }
2325
-
2326
- declare interface WaveformPlaylistTheme {
2327
- waveformDrawMode?: WaveformDrawMode;
2328
- waveOutlineColor: WaveformColor;
2329
- waveFillColor: WaveformColor;
2330
- waveProgressColor: string;
2331
- selectedWaveOutlineColor: WaveformColor;
2332
- selectedWaveFillColor: WaveformColor;
2333
- selectedTrackControlsBackground: string;
2334
- selectedTrackBackground: string;
2335
- timeColor: string;
2336
- timescaleBackgroundColor: string;
2337
- playheadColor: string;
2338
- selectionColor: string;
2339
- loopRegionColor: string;
2340
- loopMarkerColor: string;
2341
- clipHeaderBackgroundColor: string;
2342
- clipHeaderBorderColor: string;
2343
- clipHeaderTextColor: string;
2344
- clipHeaderFontFamily: string;
2345
- selectedClipHeaderBackgroundColor: string;
2346
- fadeOverlayColor: string;
2347
- backgroundColor: string;
2348
- surfaceColor: string;
2349
- borderColor: string;
2350
- textColor: string;
2351
- textColorMuted: string;
2352
- inputBackground: string;
2353
- inputBorder: string;
2354
- inputText: string;
2355
- inputPlaceholder: string;
2356
- inputFocusBorder: string;
2357
- buttonBackground: string;
2358
- buttonText: string;
2359
- buttonBorder: string;
2360
- buttonHoverBackground: string;
2361
- sliderTrackColor: string;
2362
- sliderThumbColor: string;
2363
- annotationBoxBackground: string;
2364
- annotationBoxActiveBackground: string;
2365
- annotationBoxHoverBackground: string;
2366
- annotationBoxBorder: string;
2367
- annotationBoxActiveBorder: string;
2368
- annotationLabelColor: string;
2369
- annotationResizeHandleColor: string;
2370
- annotationResizeHandleActiveColor: string;
2371
- annotationTextItemHoverBackground: string;
2372
- playlistBackgroundColor?: string;
2373
- pianoRollNoteColor: string;
2374
- pianoRollSelectedNoteColor: string;
2375
- pianoRollBackgroundColor: string;
2376
- borderRadius: string;
2377
- fontFamily: string;
2378
- fontSize: string;
2379
- fontSizeSmall: string;
2380
- }
2381
-
2382
- export declare interface WaveformProps {
2383
- renderTrackControls?: (trackIndex: number) => ReactNode;
2384
- /** Custom render function for timescale tick labels. `label` is a formatted string
2385
- * (bar/beat notation like "2.3" in beats mode, or "m:ss" in temporal mode). */
2386
- renderTick?: (label: string, pixelPosition: number) => ReactNode;
2387
- /** @deprecated Use `renderTick` instead. */
2388
- renderTimestamp?: (timeMs: number, pixelPosition: number) => ReactNode;
2389
- /** Custom playhead render function. Receives position (pixels) and color from theme. */
2390
- renderPlayhead?: RenderPlayheadFunction;
2391
- annotationControls?: AnnotationAction[];
2392
- annotationListConfig?: AnnotationActionOptions;
2393
- annotationTextHeight?: number;
2394
- /**
2395
- * Custom render function for annotation items in the text list.
2396
- * Use this to completely customize how each annotation is displayed.
2397
- */
2398
- renderAnnotationItem?: (props: RenderAnnotationItemProps) => ReactNode;
2399
- /**
2400
- * Custom function to generate the label shown on annotation boxes in the waveform.
2401
- * Receives the annotation data and its index, returns a string label.
2402
- * Default: annotation.id
2403
- */
2404
- getAnnotationBoxLabel?: GetAnnotationBoxLabelFn;
2405
- /** Where to position the active annotation when auto-scrolling: 'center', 'start', 'end', or 'nearest'. Defaults to 'center'. */
2406
- scrollActivePosition?: ScrollLogicalPosition;
2407
- /** Which scrollable containers to scroll: 'nearest' (only the annotation list) or 'all' (including viewport). Defaults to 'nearest'. */
2408
- scrollActiveContainer?: 'nearest' | 'all';
2409
- className?: string;
2410
- showClipHeaders?: boolean;
2411
- interactiveClips?: boolean;
2412
- showFades?: boolean;
2413
- /**
2414
- * Enable mobile-optimized touch interactions.
2415
- * When true, increases touch target sizes for clip boundaries.
2416
- * Use with useDragSensors({ touchOptimized: true }) for best results.
2417
- */
2418
- touchOptimized?: boolean;
2419
- /** Callback when a track's close button is clicked. Only renders close button when provided. */
2420
- onRemoveTrack?: (trackIndex: number) => void;
2421
- recordingState?: {
2422
- isRecording: boolean;
2423
- trackId: string;
2424
- startSample: number;
2425
- durationSamples: number;
2426
- peaks: (Int8Array | Int16Array)[];
2427
- bits: 8 | 16;
2428
- };
2429
- }
2430
-
2431
- export declare interface WaveformTrack {
2432
- src: string | AudioBuffer;
2433
- name?: string;
2434
- effects?: TrackEffectsFunction;
2435
- }
2436
-
2437
- /**
2438
- * WAV file encoder
2439
- * Converts AudioBuffer to WAV format Blob
2440
- */
2441
- declare interface WavEncoderOptions {
2442
- /** Bit depth: 16 or 32. Default: 16 */
2443
- bitDepth?: 16 | 32;
2444
- }
2445
-
2446
- export declare interface ZoomControls {
2447
- samplesPerPixel: number;
2448
- zoomIn: () => void;
2449
- zoomOut: () => void;
2450
- canZoomIn: boolean;
2451
- canZoomOut: boolean;
2452
- }
2453
-
2454
- export declare const ZoomInButton: default_2.FC<{
2455
- className?: string;
2456
- disabled?: boolean;
2457
- }>;
2458
-
2459
- export declare const ZoomOutButton: default_2.FC<{
2460
- className?: string;
2461
- disabled?: boolean;
2462
- }>;
2463
-
2464
- export { }
1
+ import { Analyser, ToneAudioNode, InputNode } from 'tone';
2
+ import * as tone from 'tone';
3
+ export { tone as Tone };
4
+ import { EffectsFunction, SoundFontCache, TrackEffectsFunction as TrackEffectsFunction$1 } from '@waveform-playlist/playout';
5
+ export { EffectsFunction, TrackEffectsFunction } from '@waveform-playlist/playout';
6
+ import * as React$1 from 'react';
7
+ import React__default, { ReactNode, RefObject } from 'react';
8
+ import { PlaylistEngine, EngineState } from '@waveform-playlist/engine';
9
+ import { ClipTrack, AnnotationData, AnnotationAction, PeakData, Fade, MidiNoteData, WaveformDataObject, TrackEffectsFunction as TrackEffectsFunction$2, RenderMode, SpectrogramConfig, ColorMapValue, AnnotationActionOptions, RenderAnnotationItemProps, TrackSpectrogramOverrides } from '@waveform-playlist/core';
10
+ export { AnnotationData, AudioClip, ClipTrack, Fade } from '@waveform-playlist/core';
11
+ import { WaveformPlaylistTheme, TimeFormat, RenderPlayheadFunction, TrackMenuItem, SnapTo } from '@waveform-playlist/ui-components';
12
+ export { TimeFormat } from '@waveform-playlist/ui-components';
13
+ import { FadeConfig, MediaElementPlayout } from '@waveform-playlist/media-element-playout';
14
+ import * as _dnd_kit_abstract from '@dnd-kit/abstract';
15
+ import { DragStartEvent, DragMoveEvent, DragEndEvent, PluginDescriptor, Modifier, DragDropManager, DragOperation, Plugins } from '@dnd-kit/abstract';
16
+ import { PointerSensor } from '@dnd-kit/dom';
17
+ import WaveformData from 'waveform-data';
18
+
19
+ interface ClipPeaks {
20
+ clipId: string;
21
+ trackName: string;
22
+ peaks: PeakData;
23
+ startSample: number;
24
+ durationSamples: number;
25
+ fadeIn?: Fade;
26
+ fadeOut?: Fade;
27
+ midiNotes?: MidiNoteData[];
28
+ sampleRate?: number;
29
+ offsetSamples?: number;
30
+ }
31
+ type TrackClipPeaks = ClipPeaks[];
32
+ interface WaveformTrack {
33
+ src: string | AudioBuffer;
34
+ name?: string;
35
+ effects?: TrackEffectsFunction$1;
36
+ }
37
+ interface TrackState$1 {
38
+ name: string;
39
+ muted: boolean;
40
+ soloed: boolean;
41
+ volume: number;
42
+ pan: number;
43
+ }
44
+ interface PlaybackAnimationContextValue {
45
+ isPlaying: boolean;
46
+ currentTime: number;
47
+ currentTimeRef: React__default.RefObject<number>;
48
+ playbackStartTimeRef: React__default.RefObject<number>;
49
+ audioStartPositionRef: React__default.RefObject<number>;
50
+ /** Returns current playback time from engine (auto-wraps at loop boundaries). */
51
+ getPlaybackTime: () => number;
52
+ }
53
+ interface PlaylistStateContextValue {
54
+ continuousPlay: boolean;
55
+ linkEndpoints: boolean;
56
+ annotationsEditable: boolean;
57
+ isAutomaticScroll: boolean;
58
+ isLoopEnabled: boolean;
59
+ annotations: AnnotationData[];
60
+ activeAnnotationId: string | null;
61
+ selectionStart: number;
62
+ selectionEnd: number;
63
+ selectedTrackId: string | null;
64
+ loopStart: number;
65
+ loopEnd: number;
66
+ /** Whether playback continues past the end of loaded audio */
67
+ indefinitePlayback: boolean;
68
+ }
69
+ interface PlaylistControlsContextValue {
70
+ play: (startTime?: number, playDuration?: number) => Promise<void>;
71
+ pause: () => void;
72
+ stop: () => void;
73
+ seekTo: (time: number) => void;
74
+ setCurrentTime: (time: number) => void;
75
+ setTrackMute: (trackIndex: number, muted: boolean) => void;
76
+ setTrackSolo: (trackIndex: number, soloed: boolean) => void;
77
+ setTrackVolume: (trackIndex: number, volume: number) => void;
78
+ setTrackPan: (trackIndex: number, pan: number) => void;
79
+ setSelection: (start: number, end: number) => void;
80
+ setSelectedTrackId: (trackId: string | null) => void;
81
+ setTimeFormat: (format: TimeFormat) => void;
82
+ formatTime: (seconds: number) => string;
83
+ zoomIn: () => void;
84
+ zoomOut: () => void;
85
+ setMasterVolume: (volume: number) => void;
86
+ setAutomaticScroll: (enabled: boolean) => void;
87
+ setScrollContainer: (element: HTMLDivElement | null) => void;
88
+ scrollContainerRef: React__default.RefObject<HTMLDivElement | null>;
89
+ setContinuousPlay: (enabled: boolean) => void;
90
+ setLinkEndpoints: (enabled: boolean) => void;
91
+ setAnnotationsEditable: (enabled: boolean) => void;
92
+ setAnnotations: React__default.Dispatch<React__default.SetStateAction<AnnotationData[]>>;
93
+ setActiveAnnotationId: (id: string | null) => void;
94
+ setLoopEnabled: (enabled: boolean) => void;
95
+ setLoopRegion: (start: number, end: number) => void;
96
+ setLoopRegionFromSelection: () => void;
97
+ clearLoopRegion: () => void;
98
+ }
99
+ interface PlaylistDataContextValue {
100
+ duration: number;
101
+ audioBuffers: AudioBuffer[];
102
+ peaksDataArray: TrackClipPeaks[];
103
+ trackStates: TrackState$1[];
104
+ tracks: ClipTrack[];
105
+ sampleRate: number;
106
+ waveHeight: number;
107
+ timeScaleHeight: number;
108
+ minimumPlaylistHeight: number;
109
+ controls: {
110
+ show: boolean;
111
+ width: number;
112
+ };
113
+ playoutRef: React__default.RefObject<PlaylistEngine | null>;
114
+ samplesPerPixel: number;
115
+ timeFormat: TimeFormat;
116
+ masterVolume: number;
117
+ canZoomIn: boolean;
118
+ canZoomOut: boolean;
119
+ barWidth: number;
120
+ barGap: number;
121
+ /** Width in pixels of progress bars. Defaults to barWidth + barGap (fills gaps). */
122
+ progressBarWidth: number;
123
+ /** Whether the playlist has finished loading all tracks */
124
+ isReady: boolean;
125
+ /** Whether tracks are rendered in mono mode */
126
+ mono: boolean;
127
+ /** Ref set by useClipDragHandlers during boundary trim drags.
128
+ * When true, loadAudio skips engine rebuild — visual updates flow via React state only. */
129
+ isDraggingRef: React__default.MutableRefObject<boolean>;
130
+ onTracksChange: ((tracks: ClipTrack[]) => void) | undefined;
131
+ }
132
+ interface WaveformPlaylistProviderProps {
133
+ tracks: ClipTrack[];
134
+ timescale?: boolean;
135
+ mono?: boolean;
136
+ waveHeight?: number;
137
+ samplesPerPixel?: number;
138
+ zoomLevels?: number[];
139
+ automaticScroll?: boolean;
140
+ theme?: Partial<WaveformPlaylistTheme>;
141
+ controls?: {
142
+ show: boolean;
143
+ width: number;
144
+ };
145
+ annotationList?: {
146
+ annotations?: AnnotationData[];
147
+ editable?: boolean;
148
+ isContinuousPlay?: boolean;
149
+ linkEndpoints?: boolean;
150
+ controls?: AnnotationAction[];
151
+ };
152
+ effects?: EffectsFunction;
153
+ onReady?: () => void;
154
+ /** @deprecated Use onAnnotationsChange instead */
155
+ onAnnotationUpdate?: (annotations: AnnotationData[]) => void;
156
+ /** Callback when annotations are changed (drag, edit, etc.) */
157
+ onAnnotationsChange?: (annotations: AnnotationData[]) => void;
158
+ /** Width in pixels of waveform bars. Default: 1 */
159
+ barWidth?: number;
160
+ /** Spacing in pixels between waveform bars. Default: 0 */
161
+ barGap?: number;
162
+ /** Width in pixels of progress bars. Default: barWidth + barGap (fills gaps). */
163
+ progressBarWidth?: number;
164
+ /** Callback when engine clip operations (move, trim, split) change tracks.
165
+ * The provider calls this so the parent can update its tracks state without
166
+ * triggering a full engine rebuild.
167
+ *
168
+ * **Important:** The parent must pass the received `tracks` reference back as
169
+ * the `tracks` prop (i.e. `setState(tracks)`). The provider uses reference
170
+ * identity (`tracks === engineTracksRef.current`) to detect engine-originated
171
+ * updates and skip the expensive `loadAudio` rebuild. */
172
+ onTracksChange?: (tracks: ClipTrack[]) => void;
173
+ /** SoundFont cache for sample-based MIDI playback. When provided, MIDI clips
174
+ * use SoundFont samples instead of PolySynth synthesis. */
175
+ soundFontCache?: SoundFontCache;
176
+ /** When true, tracks render visually but the engine build is deferred.
177
+ * Use this during progressive loading to avoid rebuilding the engine for
178
+ * each track — flip to false when all tracks are ready for a single build. */
179
+ deferEngineRebuild?: boolean;
180
+ /** Disable automatic stop when the cursor reaches the end of the longest
181
+ * track. Useful for DAW-style recording beyond existing audio. */
182
+ indefinitePlayback?: boolean;
183
+ children: ReactNode;
184
+ }
185
+ declare const WaveformPlaylistProvider: React__default.FC<WaveformPlaylistProviderProps>;
186
+ declare const usePlaybackAnimation: () => PlaybackAnimationContextValue;
187
+ declare const usePlaylistState: () => PlaylistStateContextValue;
188
+ declare const usePlaylistControls: () => PlaylistControlsContextValue;
189
+ declare const usePlaylistData: () => PlaylistDataContextValue;
190
+
191
+ interface MediaElementTrackConfig {
192
+ /** Audio source URL or Blob URL */
193
+ source: string;
194
+ /** Pre-computed waveform data (required for visualization) */
195
+ waveformData: WaveformDataObject;
196
+ /** Track name for display */
197
+ name?: string;
198
+ /** Fade in configuration (requires audioContext on provider) */
199
+ fadeIn?: FadeConfig;
200
+ /** Fade out configuration (requires audioContext on provider) */
201
+ fadeOut?: FadeConfig;
202
+ }
203
+ interface MediaElementAnimationContextValue {
204
+ isPlaying: boolean;
205
+ currentTime: number;
206
+ currentTimeRef: React__default.RefObject<number>;
207
+ }
208
+ interface MediaElementStateContextValue {
209
+ continuousPlay: boolean;
210
+ annotations: AnnotationData[];
211
+ activeAnnotationId: string | null;
212
+ playbackRate: number;
213
+ isAutomaticScroll: boolean;
214
+ }
215
+ interface MediaElementControlsContextValue {
216
+ play: (startTime?: number) => void;
217
+ pause: () => void;
218
+ stop: () => void;
219
+ seekTo: (time: number) => void;
220
+ setPlaybackRate: (rate: number) => void;
221
+ setContinuousPlay: (enabled: boolean) => void;
222
+ setAnnotations: React__default.Dispatch<React__default.SetStateAction<AnnotationData[]>>;
223
+ setActiveAnnotationId: (id: string | null) => void;
224
+ setAutomaticScroll: (enabled: boolean) => void;
225
+ setScrollContainer: (element: HTMLDivElement | null) => void;
226
+ scrollContainerRef: React__default.RefObject<HTMLDivElement | null>;
227
+ }
228
+ interface MediaElementDataContextValue {
229
+ duration: number;
230
+ peaksDataArray: TrackClipPeaks[];
231
+ sampleRate: number;
232
+ waveHeight: number;
233
+ timeScaleHeight: number;
234
+ samplesPerPixel: number;
235
+ playoutRef: React__default.RefObject<MediaElementPlayout | null>;
236
+ controls: {
237
+ show: boolean;
238
+ width: number;
239
+ };
240
+ barWidth: number;
241
+ barGap: number;
242
+ progressBarWidth: number;
243
+ fadeIn?: FadeConfig;
244
+ fadeOut?: FadeConfig;
245
+ }
246
+ interface MediaElementPlaylistProviderProps {
247
+ /** Single track configuration with source URL and waveform data */
248
+ track: MediaElementTrackConfig;
249
+ /** Initial samples per pixel (zoom level) */
250
+ samplesPerPixel?: number;
251
+ /** Height of each waveform track */
252
+ waveHeight?: number;
253
+ /** Show timescale */
254
+ timescale?: boolean;
255
+ /** Initial playback rate (0.5 to 2.0) */
256
+ playbackRate?: number;
257
+ /** Enable automatic scroll to keep playhead centered */
258
+ automaticScroll?: boolean;
259
+ /** Theme configuration */
260
+ theme?: Partial<WaveformPlaylistTheme>;
261
+ /** Track controls configuration */
262
+ controls?: {
263
+ show: boolean;
264
+ width: number;
265
+ };
266
+ /** Annotations */
267
+ annotationList?: {
268
+ annotations?: AnnotationData[];
269
+ isContinuousPlay?: boolean;
270
+ };
271
+ /** Width of waveform bars */
272
+ barWidth?: number;
273
+ /** Gap between waveform bars */
274
+ barGap?: number;
275
+ /** Width of progress bars */
276
+ progressBarWidth?: number;
277
+ /** Callback when annotations are changed (drag, edit, etc.) */
278
+ onAnnotationsChange?: (annotations: AnnotationData[]) => void;
279
+ /**
280
+ * AudioContext for Web Audio routing (fades, effects).
281
+ * When provided, audio routes through Web Audio nodes:
282
+ * HTMLAudioElement → MediaElementSourceNode → fadeGain → volumeGain → destination
283
+ *
284
+ * Without this, playback uses HTMLAudioElement directly (no fades or effects).
285
+ * Each provider instance should use its own AudioContext or share one —
286
+ * createMediaElementSource() is called once per audio element.
287
+ */
288
+ audioContext?: AudioContext;
289
+ /** Callback when audio is ready */
290
+ onReady?: () => void;
291
+ children: ReactNode;
292
+ }
293
+ /**
294
+ * MediaElementPlaylistProvider
295
+ *
296
+ * A simplified playlist provider for single-track playback using HTMLAudioElement.
297
+ * Key features:
298
+ * - Pitch-preserving playback rate (0.5x - 2.0x)
299
+ * - Pre-computed peaks visualization (no AudioBuffer needed)
300
+ * - Simpler API than full WaveformPlaylistProvider
301
+ *
302
+ * Use this for:
303
+ * - Language learning apps (speed control)
304
+ * - Podcast players
305
+ * - Single-track audio viewers
306
+ *
307
+ * For multi-track editing, use WaveformPlaylistProvider instead.
308
+ */
309
+ declare const MediaElementPlaylistProvider: React__default.FC<MediaElementPlaylistProviderProps>;
310
+ declare const useMediaElementAnimation: () => MediaElementAnimationContextValue;
311
+ declare const useMediaElementState: () => MediaElementStateContextValue;
312
+ declare const useMediaElementControls: () => MediaElementControlsContextValue;
313
+ declare const useMediaElementData: () => MediaElementDataContextValue;
314
+
315
+ interface TimeFormatControls {
316
+ timeFormat: TimeFormat;
317
+ setTimeFormat: (format: TimeFormat) => void;
318
+ formatTime: (seconds: number) => string;
319
+ parseTime: (timeString: string) => number;
320
+ }
321
+ /**
322
+ * Hook to manage time format state
323
+ *
324
+ * @example
325
+ * ```tsx
326
+ * const { timeFormat, setTimeFormat, formatTime, parseTime } = useTimeFormat();
327
+ *
328
+ * <TimeFormatSelect
329
+ * value={timeFormat}
330
+ * onChange={setTimeFormat}
331
+ * />
332
+ * <span>{formatTime(currentTime)}</span>
333
+ * <input onChange={(e) => seekTo(parseTime(e.target.value))} />
334
+ * ```
335
+ */
336
+ declare function useTimeFormat(): TimeFormatControls;
337
+
338
+ interface ZoomControls {
339
+ samplesPerPixel: number;
340
+ zoomIn: () => void;
341
+ zoomOut: () => void;
342
+ canZoomIn: boolean;
343
+ canZoomOut: boolean;
344
+ }
345
+ interface UseZoomControlsProps {
346
+ engineRef: RefObject<PlaylistEngine | null>;
347
+ initialSamplesPerPixel: number;
348
+ }
349
+ /**
350
+ * Hook for managing zoom controls via PlaylistEngine delegation.
351
+ *
352
+ * zoomIn/zoomOut delegate to the engine. State is mirrored back from
353
+ * the engine via onEngineState(), which the provider's statechange
354
+ * handler calls on every engine event.
355
+ *
356
+ * samplesPerPixel updates use startTransition so React treats them as
357
+ * non-urgent during playback, animation RAF callbacks interleave
358
+ * with the zoom re-render instead of being blocked.
359
+ */
360
+ declare function useZoomControls({ engineRef, initialSamplesPerPixel, }: UseZoomControlsProps): ZoomControls & {
361
+ onEngineState: (state: EngineState) => void;
362
+ };
363
+
364
+ interface UseMasterVolumeProps {
365
+ engineRef: RefObject<PlaylistEngine | null>;
366
+ initialVolume?: number;
367
+ }
368
+ interface MasterVolumeControls {
369
+ masterVolume: number;
370
+ setMasterVolume: (volume: number) => void;
371
+ /** Ref holding the current masterVolume for seeding a fresh engine. */
372
+ masterVolumeRef: React.RefObject<number>;
373
+ }
374
+ /**
375
+ * Hook for managing master volume via PlaylistEngine delegation.
376
+ *
377
+ * setMasterVolume delegates to the engine. State is mirrored back from
378
+ * the engine via onEngineState(), which the provider's statechange
379
+ * handler calls on every engine event.
380
+ */
381
+ declare function useMasterVolume({ engineRef, initialVolume, }: UseMasterVolumeProps): MasterVolumeControls & {
382
+ onEngineState: (state: EngineState) => void;
383
+ };
384
+
385
+ /**
386
+ * Hook for master effects with frequency analyzer
387
+ * Returns the analyser ref and the effects function to pass to WaveformPlaylistProvider
388
+ *
389
+ * For more advanced effects (reverb, delay, filters, etc.), use useDynamicEffects instead.
390
+ */
391
+ declare const useMasterAnalyser: (fftSize?: number) => {
392
+ analyserRef: React$1.MutableRefObject<Analyser | null>;
393
+ masterEffects: EffectsFunction;
394
+ };
395
+
396
+ /**
397
+ * Configuration for a single audio track to load
398
+ *
399
+ * Audio can be provided in three ways:
400
+ * 1. `src` - URL to fetch and decode (standard loading)
401
+ * 2. `audioBuffer` - Pre-loaded AudioBuffer (skip fetch/decode)
402
+ * 3. `waveformData` only - Peaks-first rendering (audio loads later)
403
+ *
404
+ * For peaks-first rendering, just provide `waveformData` - the sample rate
405
+ * and duration are derived from the waveform data automatically.
406
+ */
407
+ interface AudioTrackConfig {
408
+ /** URL to audio file - used if audioBuffer not provided */
409
+ src?: string;
410
+ /** Pre-loaded AudioBuffer - skips fetch/decode if provided */
411
+ audioBuffer?: AudioBuffer;
412
+ name?: string;
413
+ muted?: boolean;
414
+ soloed?: boolean;
415
+ volume?: number;
416
+ pan?: number;
417
+ color?: string;
418
+ effects?: TrackEffectsFunction$2;
419
+ startTime?: number;
420
+ duration?: number;
421
+ offset?: number;
422
+ fadeIn?: Fade;
423
+ fadeOut?: Fade;
424
+ waveformData?: WaveformDataObject;
425
+ /** Visualization render mode: 'waveform' | 'spectrogram' | 'both'. Default: 'waveform' */
426
+ renderMode?: RenderMode;
427
+ /** Spectrogram configuration (FFT size, window, frequency scale, etc.) */
428
+ spectrogramConfig?: SpectrogramConfig;
429
+ /** Spectrogram color map name or custom color array */
430
+ spectrogramColorMap?: ColorMapValue;
431
+ }
432
+ /**
433
+ * Options for useAudioTracks hook
434
+ */
435
+ interface UseAudioTracksOptions {
436
+ /**
437
+ * When true, all tracks render immediately as placeholders with clip geometry
438
+ * from the config. Audio fills in progressively as files decode, and peaks
439
+ * render as each buffer becomes available. Use with `deferEngineRebuild={loading}`
440
+ * on the provider for a single engine build when all tracks are ready.
441
+ *
442
+ * Requires `duration` or `waveformData` in each config so clip dimensions are known upfront.
443
+ * Default: false
444
+ */
445
+ immediate?: boolean;
446
+ /** @deprecated Use `immediate` instead. */
447
+ progressive?: boolean;
448
+ }
449
+ /**
450
+ * Hook to load audio from URLs and convert to ClipTrack format
451
+ *
452
+ * This hook fetches audio files, decodes them, and creates ClipTrack objects
453
+ * with a single clip per track. Supports custom positioning for multi-clip arrangements.
454
+ *
455
+ * @param configs - Array of audio track configurations
456
+ * @param options - Optional configuration for loading behavior
457
+ * @returns Object with tracks array, loading state, and progress info
458
+ *
459
+ * @example
460
+ * ```typescript
461
+ * // Basic usage (clips positioned at start)
462
+ * const { tracks, loading, error } = useAudioTracks([
463
+ * { src: 'audio/vocals.mp3', name: 'Vocals' },
464
+ * { src: 'audio/drums.mp3', name: 'Drums' },
465
+ * ]);
466
+ *
467
+ * // Immediate rendering with deferred engine build (recommended for multi-track)
468
+ * const { tracks, loading } = useAudioTracks(
469
+ * [
470
+ * { src: 'audio/vocals.mp3', name: 'Vocals', duration: 30 },
471
+ * { src: 'audio/drums.mp3', name: 'Drums', duration: 30 },
472
+ * ],
473
+ * { immediate: true }
474
+ * );
475
+ * // All tracks render instantly as placeholders, peaks fill in as files load
476
+ * return (
477
+ * <WaveformPlaylistProvider tracks={tracks} deferEngineRebuild={loading}>
478
+ * ...
479
+ * </WaveformPlaylistProvider>
480
+ * );
481
+ *
482
+ * // Pre-loaded AudioBuffer (skip fetch/decode)
483
+ * const { tracks } = useAudioTracks([
484
+ * { audioBuffer: myPreloadedBuffer, name: 'Pre-loaded' },
485
+ * ]);
486
+ *
487
+ * // Peaks-first rendering (instant visual, audio loads later)
488
+ * const { tracks } = useAudioTracks([
489
+ * { waveformData: preloadedPeaks, name: 'Peaks Only' }, // Renders immediately
490
+ * ]);
491
+ * ```
492
+ */
493
+ declare function useAudioTracks(configs: AudioTrackConfig[], options?: UseAudioTracksOptions): {
494
+ tracks: ClipTrack[];
495
+ loading: boolean;
496
+ error: string | null;
497
+ loadedCount: number;
498
+ totalCount: number;
499
+ };
500
+
501
+ interface UseClipDragHandlersOptions {
502
+ tracks: ClipTrack[];
503
+ onTracksChange: (tracks: ClipTrack[]) => void;
504
+ samplesPerPixel: number;
505
+ sampleRate: number;
506
+ engineRef: React__default.RefObject<PlaylistEngine | null>;
507
+ /** Ref toggled during boundary trim drags. When true, the provider's loadAudio
508
+ * skips engine rebuilds so engine keeps original clip positions. On drag end,
509
+ * engine.trimClip() commits the final delta. Obtain from usePlaylistData(). */
510
+ isDraggingRef: React__default.MutableRefObject<boolean>;
511
+ /** Optional function that snaps a sample position to the nearest grid position.
512
+ * Used for boundary trim snapping (move snapping is handled by the SnapToGridModifier). */
513
+ snapSamplePosition?: (samplePosition: number) => number;
514
+ }
515
+ /**
516
+ * Custom hook for handling clip drag operations (movement and trimming)
517
+ *
518
+ * Provides drag handlers for use with @dnd-kit/react DragDropProvider.
519
+ * Handles both clip movement (dragging entire clips) and boundary trimming (adjusting clip edges).
520
+ *
521
+ * Collision detection for clip moves is handled by `ClipCollisionModifier` (passed to DragDropProvider).
522
+ *
523
+ * **Move:** `onDragEnd` delegates to `engine.moveClip()` in one shot.
524
+ *
525
+ * **Trim:** `onDragMove` updates React state per-frame via `onTracksChange` for smooth
526
+ * visual feedback (using cumulative deltas from the original clip snapshot). `isDraggingRef`
527
+ * prevents loadAudio from rebuilding the engine during the drag, so the engine keeps the
528
+ * original clip positions. On drag end, `engine.trimClip()` commits the final delta.
529
+ *
530
+ * @example
531
+ * ```tsx
532
+ * const { onDragStart, onDragMove, onDragEnd } = useClipDragHandlers({
533
+ * tracks,
534
+ * onTracksChange: setTracks,
535
+ * samplesPerPixel,
536
+ * sampleRate,
537
+ * engineRef: playoutRef,
538
+ * isDraggingRef,
539
+ * });
540
+ *
541
+ * return (
542
+ * <DragDropProvider
543
+ * onDragStart={onDragStart}
544
+ * onDragMove={onDragMove}
545
+ * onDragEnd={onDragEnd}
546
+ * modifiers={[RestrictToHorizontalAxis, ClipCollisionModifier.configure({ tracks, samplesPerPixel })]}
547
+ * >
548
+ * <Waveform showClipHeaders={true} />
549
+ * </DragDropProvider>
550
+ * );
551
+ * ```
552
+ */
553
+ declare function useClipDragHandlers({ tracks, onTracksChange, samplesPerPixel, sampleRate, engineRef, isDraggingRef, snapSamplePosition, }: UseClipDragHandlersOptions): {
554
+ onDragStart: (event: Parameters<DragStartEvent>[0]) => void;
555
+ onDragMove: (event: Parameters<DragMoveEvent>[0]) => void;
556
+ onDragEnd: (event: Parameters<DragEndEvent>[0]) => void;
557
+ };
558
+
559
+ interface UseAnnotationDragHandlersOptions {
560
+ annotations: AnnotationData[];
561
+ onAnnotationsChange: (annotations: AnnotationData[]) => void;
562
+ samplesPerPixel: number;
563
+ sampleRate: number;
564
+ duration: number;
565
+ linkEndpoints: boolean;
566
+ }
567
+ /**
568
+ * Custom hook for handling annotation drag operations (boundary trimming)
569
+ *
570
+ * Provides drag handlers for use with @dnd-kit/react DragDropProvider.
571
+ * Handles annotation boundary resizing with linked endpoints support.
572
+ *
573
+ * @example
574
+ * ```tsx
575
+ * const { onDragStart, onDragMove, onDragEnd } = useAnnotationDragHandlers({
576
+ * annotations,
577
+ * onAnnotationsChange: setAnnotations,
578
+ * samplesPerPixel,
579
+ * sampleRate,
580
+ * duration,
581
+ * linkEndpoints,
582
+ * });
583
+ *
584
+ * return (
585
+ * <DragDropProvider
586
+ * onDragStart={onDragStart}
587
+ * onDragMove={onDragMove}
588
+ * onDragEnd={onDragEnd}
589
+ * modifiers={[RestrictToHorizontalAxis]}
590
+ * >
591
+ * {renderAnnotations()}
592
+ * </DragDropProvider>
593
+ * );
594
+ * ```
595
+ */
596
+ declare function useAnnotationDragHandlers({ annotations, onAnnotationsChange, samplesPerPixel, sampleRate, duration, linkEndpoints, }: UseAnnotationDragHandlersOptions): {
597
+ onDragStart: (event: Parameters<DragStartEvent>[0]) => void;
598
+ onDragMove: (event: Parameters<DragMoveEvent>[0]) => void;
599
+ onDragEnd: (event: Parameters<DragEndEvent>[0]) => void;
600
+ };
601
+
602
+ /**
603
+ * Hook for configuring @dnd-kit sensors for clip dragging
604
+ *
605
+ * Provides consistent drag activation behavior across all examples.
606
+ * Always overrides PointerSensor defaults with custom activation constraints:
607
+ * - Default mode: distance-based activation (1px) for all pointer types
608
+ * - Touch-optimized mode: delay-based activation for touch (250ms),
609
+ * distance-based for mouse/pen
610
+ */
611
+
612
+ interface DragSensorOptions {
613
+ /**
614
+ * Enable mobile-optimized touch handling with delay-based activation.
615
+ * When true, touch events get delay-based activation while mouse/pen get distance-based.
616
+ * When false (default), all pointer types use distance-based activation (1px).
617
+ */
618
+ touchOptimized?: boolean;
619
+ /**
620
+ * Delay in milliseconds before touch drag activates (only when touchOptimized is true).
621
+ * Default: 250ms - long enough to distinguish from scroll intent
622
+ */
623
+ touchDelay?: number;
624
+ /**
625
+ * Distance tolerance during touch delay (only when touchOptimized is true).
626
+ * If finger moves more than this during delay, drag is cancelled.
627
+ * Default: 5px - allows slight finger movement
628
+ */
629
+ touchTolerance?: number;
630
+ /**
631
+ * Distance in pixels before mouse drag activates.
632
+ * Default: 1px for immediate feedback on desktop
633
+ */
634
+ mouseDistance?: number;
635
+ }
636
+ /**
637
+ * Returns configured sensors for @dnd-kit drag operations
638
+ *
639
+ * @param options - Configuration options for drag sensors
640
+ * @returns Array of sensor constructors/descriptors for DragDropProvider's sensors prop
641
+ *
642
+ * @example
643
+ * // Desktop-optimized (default — 1px distance activation for all pointer types)
644
+ * const sensors = useDragSensors();
645
+ *
646
+ * @example
647
+ * // Mobile-optimized with custom touch delay
648
+ * const sensors = useDragSensors({ touchOptimized: true, touchDelay: 300 });
649
+ */
650
+ declare function useDragSensors(options?: DragSensorOptions): (typeof PointerSensor | PluginDescriptor<any, any, any>)[];
651
+
652
+ interface UseClipSplittingOptions {
653
+ tracks: ClipTrack[];
654
+ sampleRate: number;
655
+ samplesPerPixel: number;
656
+ engineRef: React__default.RefObject<PlaylistEngine | null>;
657
+ }
658
+ interface UseClipSplittingResult {
659
+ splitClipAtPlayhead: () => boolean;
660
+ splitClipAt: (trackIndex: number, clipIndex: number, splitTime: number) => boolean;
661
+ }
662
+ /**
663
+ * Hook for splitting clips at the playhead or at a specific time
664
+ *
665
+ * Splitting delegates to `engine.splitClip()` the engine handles clip creation,
666
+ * adapter sync, and emits statechange. The provider's statechange handler propagates
667
+ * the updated tracks to the parent via `onTracksChange`.
668
+ *
669
+ * @param options - Configuration options
670
+ * @returns Object with split functions
671
+ *
672
+ * @example
673
+ * ```tsx
674
+ * const { splitClipAtPlayhead } = useClipSplitting({
675
+ * tracks,
676
+ * sampleRate,
677
+ * samplesPerPixel,
678
+ * engineRef: playoutRef,
679
+ * });
680
+ *
681
+ * // In keyboard handler
682
+ * const handleKeyPress = (e: KeyboardEvent) => {
683
+ * if (e.key === 's' || e.key === 'S') {
684
+ * splitClipAtPlayhead();
685
+ * }
686
+ * };
687
+ * ```
688
+ */
689
+ declare const useClipSplitting: (options: UseClipSplittingOptions) => UseClipSplittingResult;
690
+
691
+ interface KeyboardShortcut {
692
+ key: string;
693
+ ctrlKey?: boolean;
694
+ shiftKey?: boolean;
695
+ metaKey?: boolean;
696
+ altKey?: boolean;
697
+ action: () => void;
698
+ description?: string;
699
+ preventDefault?: boolean;
700
+ }
701
+ interface UseKeyboardShortcutsOptions {
702
+ shortcuts: KeyboardShortcut[];
703
+ enabled?: boolean;
704
+ }
705
+ /**
706
+ * Hook for managing keyboard shortcuts
707
+ *
708
+ * @param options - Configuration options
709
+ *
710
+ * @example
711
+ * ```tsx
712
+ * useKeyboardShortcuts({
713
+ * shortcuts: [
714
+ * {
715
+ * key: ' ',
716
+ * action: togglePlayPause,
717
+ * description: 'Play/Pause',
718
+ * preventDefault: true,
719
+ * },
720
+ * {
721
+ * key: 's',
722
+ * action: splitClipAtPlayhead,
723
+ * description: 'Split clip at playhead',
724
+ * preventDefault: true,
725
+ * },
726
+ * ],
727
+ * });
728
+ * ```
729
+ */
730
+ declare const useKeyboardShortcuts: (options: UseKeyboardShortcutsOptions) => void;
731
+ /**
732
+ * Get a human-readable string representation of a keyboard shortcut
733
+ *
734
+ * @param shortcut - The keyboard shortcut
735
+ * @returns Human-readable string (e.g., "Cmd+Shift+S")
736
+ */
737
+ declare const getShortcutLabel: (shortcut: KeyboardShortcut) => string;
738
+
739
+ interface UsePlaybackShortcutsOptions {
740
+ /**
741
+ * Enable the shortcuts. Defaults to true.
742
+ */
743
+ enabled?: boolean;
744
+ /**
745
+ * Additional shortcuts to include alongside the default playback shortcuts.
746
+ */
747
+ additionalShortcuts?: KeyboardShortcut[];
748
+ /**
749
+ * Override default shortcuts. If provided, only these shortcuts will be used.
750
+ */
751
+ shortcuts?: KeyboardShortcut[];
752
+ }
753
+ interface UsePlaybackShortcutsReturn {
754
+ /** Rewind to the beginning (time = 0) */
755
+ rewindToStart: () => void;
756
+ /** Toggle play/pause */
757
+ togglePlayPause: () => void;
758
+ /** Stop playback and return to start position */
759
+ stopPlayback: () => void;
760
+ /** The list of active keyboard shortcuts */
761
+ shortcuts: KeyboardShortcut[];
762
+ }
763
+ /**
764
+ * Hook that provides common playback keyboard shortcuts for the playlist.
765
+ *
766
+ * Default shortcuts:
767
+ * - `Space` - Toggle play/pause
768
+ * - `Escape` - Stop playback
769
+ * - `0` - Rewind to start (seek to time 0)
770
+ *
771
+ * @example
772
+ * ```tsx
773
+ * // Basic usage - enables default shortcuts
774
+ * usePlaybackShortcuts();
775
+ *
776
+ * // With additional custom shortcuts
777
+ * usePlaybackShortcuts({
778
+ * additionalShortcuts: [
779
+ * { key: 's', action: splitClipAtPlayhead, description: 'Split clip' },
780
+ * ],
781
+ * });
782
+ *
783
+ * // Completely override shortcuts
784
+ * usePlaybackShortcuts({
785
+ * shortcuts: [
786
+ * { key: 'Home', action: rewindToStart, description: 'Go to start' },
787
+ * ],
788
+ * });
789
+ * ```
790
+ */
791
+ declare const usePlaybackShortcuts: (options?: UsePlaybackShortcutsOptions) => UsePlaybackShortcutsReturn;
792
+
793
+ interface UseAnnotationKeyboardControlsOptions {
794
+ annotations: AnnotationData[];
795
+ activeAnnotationId: string | null;
796
+ onAnnotationsChange: (annotations: AnnotationData[]) => void;
797
+ /** Callback to set the active annotation ID for selection */
798
+ onActiveAnnotationChange?: (id: string | null) => void;
799
+ duration: number;
800
+ linkEndpoints: boolean;
801
+ /** Whether continuous play is enabled (affects playback duration) */
802
+ continuousPlay?: boolean;
803
+ enabled?: boolean;
804
+ /** Optional: scroll container ref for auto-scrolling to annotation */
805
+ scrollContainerRef?: React.RefObject<HTMLDivElement | null>;
806
+ /** Optional: samples per pixel for scroll position calculation */
807
+ samplesPerPixel?: number;
808
+ /** Optional: sample rate for scroll position calculation */
809
+ sampleRate?: number;
810
+ /** Optional: callback to start playback at a time with optional duration */
811
+ onPlay?: (startTime: number, duration?: number) => void;
812
+ }
813
+ /**
814
+ * Hook for keyboard-based annotation navigation and boundary editing
815
+ *
816
+ * Navigation Shortcuts:
817
+ * - ArrowUp / ArrowLeft = Select previous annotation
818
+ * - ArrowDown / ArrowRight = Select next annotation
819
+ * - Home = Select first annotation
820
+ * - End = Select last annotation
821
+ * - Escape = Deselect annotation
822
+ * - Enter = Play selected annotation
823
+ *
824
+ * Boundary Editing Shortcuts (requires active annotation):
825
+ * - [ = Move start boundary earlier (left)
826
+ * - ] = Move start boundary later (right)
827
+ * - Shift+[ = Move end boundary earlier (left)
828
+ * - Shift+] = Move end boundary later (right)
829
+ *
830
+ * Respects linkEndpoints and continuousPlay settings.
831
+ *
832
+ * @example
833
+ * ```tsx
834
+ * useAnnotationKeyboardControls({
835
+ * annotations,
836
+ * activeAnnotationId,
837
+ * onAnnotationsChange: setAnnotations,
838
+ * onActiveAnnotationChange: setActiveAnnotationId,
839
+ * duration,
840
+ * linkEndpoints,
841
+ * });
842
+ * ```
843
+ */
844
+ declare function useAnnotationKeyboardControls({ annotations, activeAnnotationId, onAnnotationsChange, onActiveAnnotationChange, duration, linkEndpoints, continuousPlay, enabled, scrollContainerRef, samplesPerPixel, sampleRate, onPlay, }: UseAnnotationKeyboardControlsOptions): {
845
+ moveStartBoundary: (delta: number) => void;
846
+ moveEndBoundary: (delta: number) => void;
847
+ selectPrevious: () => void;
848
+ selectNext: () => void;
849
+ selectFirst: () => void;
850
+ selectLast: () => void;
851
+ clearSelection: () => void;
852
+ scrollToAnnotation: (annotationId: string) => void;
853
+ playActiveAnnotation: () => void;
854
+ };
855
+
856
+ /**
857
+ * Effect definitions for all available Tone.js effects
858
+ * Each effect has parameters with min/max/default values for UI controls
859
+ */
860
+ type ParameterType = 'number' | 'select' | 'boolean';
861
+ interface EffectParameter {
862
+ name: string;
863
+ label: string;
864
+ type: ParameterType;
865
+ min?: number;
866
+ max?: number;
867
+ step?: number;
868
+ default: number | string | boolean;
869
+ unit?: string;
870
+ options?: {
871
+ value: string | number;
872
+ label: string;
873
+ }[];
874
+ }
875
+ interface EffectDefinition {
876
+ id: string;
877
+ name: string;
878
+ category: 'delay' | 'reverb' | 'modulation' | 'distortion' | 'filter' | 'dynamics' | 'spatial';
879
+ description: string;
880
+ parameters: EffectParameter[];
881
+ }
882
+ declare const effectDefinitions: EffectDefinition[];
883
+ declare const getEffectDefinition: (id: string) => EffectDefinition | undefined;
884
+ declare const getEffectsByCategory: (category: EffectDefinition["category"]) => EffectDefinition[];
885
+ declare const effectCategories: {
886
+ id: EffectDefinition['category'];
887
+ name: string;
888
+ }[];
889
+
890
+ interface ActiveEffect {
891
+ instanceId: string;
892
+ effectId: string;
893
+ definition: EffectDefinition;
894
+ params: Record<string, number | string | boolean>;
895
+ bypassed: boolean;
896
+ }
897
+ interface UseDynamicEffectsReturn {
898
+ activeEffects: ActiveEffect[];
899
+ availableEffects: EffectDefinition[];
900
+ addEffect: (effectId: string) => void;
901
+ removeEffect: (instanceId: string) => void;
902
+ updateParameter: (instanceId: string, paramName: string, value: number | string | boolean) => void;
903
+ toggleBypass: (instanceId: string) => void;
904
+ reorderEffects: (fromIndex: number, toIndex: number) => void;
905
+ clearAllEffects: () => void;
906
+ masterEffects: EffectsFunction;
907
+ /**
908
+ * Creates a fresh effects function for offline rendering.
909
+ * This creates new effect instances that work in the offline AudioContext.
910
+ */
911
+ createOfflineEffectsFunction: () => EffectsFunction | undefined;
912
+ analyserRef: React.RefObject<Analyser | null>;
913
+ }
914
+ /**
915
+ * Hook for managing a dynamic chain of audio effects with real-time parameter updates
916
+ */
917
+ declare function useDynamicEffects(fftSize?: number): UseDynamicEffectsReturn;
918
+
919
+ interface TrackActiveEffect {
920
+ instanceId: string;
921
+ effectId: string;
922
+ definition: EffectDefinition;
923
+ params: Record<string, number | string | boolean>;
924
+ bypassed: boolean;
925
+ }
926
+ interface TrackEffectsState {
927
+ trackId: string;
928
+ activeEffects: TrackActiveEffect[];
929
+ }
930
+ interface UseTrackDynamicEffectsReturn {
931
+ trackEffectsState: Map<string, TrackActiveEffect[]>;
932
+ addEffectToTrack: (trackId: string, effectId: string) => void;
933
+ removeEffectFromTrack: (trackId: string, instanceId: string) => void;
934
+ updateTrackEffectParameter: (trackId: string, instanceId: string, paramName: string, value: number | string | boolean) => void;
935
+ toggleBypass: (trackId: string, instanceId: string) => void;
936
+ clearTrackEffects: (trackId: string) => void;
937
+ getTrackEffectsFunction: (trackId: string) => TrackEffectsFunction$1 | undefined;
938
+ /**
939
+ * Creates a fresh effects function for a track for offline rendering.
940
+ * This creates new effect instances that work in the offline AudioContext.
941
+ */
942
+ createOfflineTrackEffectsFunction: (trackId: string) => TrackEffectsFunction$1 | undefined;
943
+ availableEffects: EffectDefinition[];
944
+ }
945
+ /**
946
+ * Hook for managing dynamic effects per track with real-time parameter updates
947
+ */
948
+ declare function useTrackDynamicEffects(): UseTrackDynamicEffectsReturn;
949
+
950
+ /**
951
+ * WAV file encoder
952
+ * Converts AudioBuffer to WAV format Blob
953
+ */
954
+ interface WavEncoderOptions {
955
+ /** Bit depth: 16 or 32. Default: 16 */
956
+ bitDepth?: 16 | 32;
957
+ }
958
+
959
+ /** Function type for per-track effects (same as in @waveform-playlist/core) */
960
+ type TrackEffectsFunction = (graphEnd: unknown, destination: unknown, isOffline: boolean) => void | (() => void);
961
+ interface ExportOptions extends WavEncoderOptions {
962
+ /** Filename for download (without extension) */
963
+ filename?: string;
964
+ /** Export mode: 'master' for stereo mix, 'individual' for single track */
965
+ mode?: 'master' | 'individual';
966
+ /** Track index for individual export (only used when mode is 'individual') */
967
+ trackIndex?: number;
968
+ /** Whether to trigger automatic download */
969
+ autoDownload?: boolean;
970
+ /** Whether to apply effects (fades, etc.) - defaults to true */
971
+ applyEffects?: boolean;
972
+ /**
973
+ * Optional Tone.js effects function for master effects. When provided, export will use Tone.Offline
974
+ * to render through the effects chain. The function receives isOffline=true.
975
+ */
976
+ effectsFunction?: EffectsFunction;
977
+ /**
978
+ * Optional function to create offline track effects.
979
+ * Takes a trackId and returns a TrackEffectsFunction for offline rendering.
980
+ * This is used instead of track.effects to avoid AudioContext mismatch issues.
981
+ */
982
+ createOfflineTrackEffects?: (trackId: string) => TrackEffectsFunction | undefined;
983
+ /** Progress callback (0-1) */
984
+ onProgress?: (progress: number) => void;
985
+ }
986
+ interface ExportResult {
987
+ /** The rendered audio buffer */
988
+ audioBuffer: AudioBuffer;
989
+ /** The WAV file as a Blob */
990
+ blob: Blob;
991
+ /** Duration in seconds */
992
+ duration: number;
993
+ }
994
+ interface UseExportWavReturn {
995
+ /** Export the playlist to WAV */
996
+ exportWav: (tracks: ClipTrack[], trackStates: TrackState[], options?: ExportOptions) => Promise<ExportResult>;
997
+ /** Whether export is in progress */
998
+ isExporting: boolean;
999
+ /** Export progress (0-1) */
1000
+ progress: number;
1001
+ /** Error message if export failed */
1002
+ error: string | null;
1003
+ }
1004
+ interface TrackState {
1005
+ muted: boolean;
1006
+ soloed: boolean;
1007
+ volume: number;
1008
+ pan: number;
1009
+ }
1010
+ /**
1011
+ * Hook for exporting the waveform playlist to WAV format
1012
+ * Uses OfflineAudioContext for fast, non-real-time rendering
1013
+ */
1014
+ declare function useExportWav(): UseExportWavReturn;
1015
+
1016
+ /**
1017
+ * useDynamicTracks — imperative hook for runtime track additions.
1018
+ *
1019
+ * Complements `useAudioTracks` (declarative, configs-driven) with an
1020
+ * imperative `addTracks()` API for dynamic loading (drag-and-drop, file pickers).
1021
+ *
1022
+ * Placeholder tracks appear instantly while audio decodes in parallel.
1023
+ */
1024
+
1025
+ /** A source that can be decoded into a track. */
1026
+ type TrackSource = File | Blob | string | {
1027
+ src: string;
1028
+ name?: string;
1029
+ };
1030
+ /** Info about a track that failed to load. */
1031
+ interface TrackLoadError {
1032
+ /** Display name of the source that failed. */
1033
+ name: string;
1034
+ /** The underlying error. */
1035
+ error: Error;
1036
+ }
1037
+ interface UseDynamicTracksReturn {
1038
+ /**
1039
+ * Current tracks array (placeholders + loaded). Pass to WaveformPlaylistProvider.
1040
+ * Placeholder tracks have `clips: []` and names ending with " (loading...)".
1041
+ */
1042
+ tracks: ClipTrack[];
1043
+ /** Add one or more sources creates placeholder tracks immediately. */
1044
+ addTracks: (sources: TrackSource[]) => void;
1045
+ /** Remove a track by its id. Aborts in-flight fetch/decode if still loading. */
1046
+ removeTrack: (trackId: string) => void;
1047
+ /** Number of sources currently decoding. */
1048
+ loadingCount: number;
1049
+ /** True when any source is still decoding. */
1050
+ isLoading: boolean;
1051
+ /** Tracks that failed to load (removed from `tracks` automatically). */
1052
+ errors: TrackLoadError[];
1053
+ }
1054
+ declare function useDynamicTracks(): UseDynamicTracksReturn;
1055
+
1056
+ /**
1057
+ * Hook for monitoring master output levels
1058
+ *
1059
+ * Connects an AudioWorklet meter processor to the Destination node for
1060
+ * real-time output level monitoring. Computes sample-accurate peak and
1061
+ * RMS via the meter worklet — no transient is missed.
1062
+ *
1063
+ * IMPORTANT: Uses getGlobalContext() from playout to ensure the meter
1064
+ * is created on the same AudioContext as the audio engine. Tone.js's
1065
+ * getContext()/getDestination() return the DEFAULT context, which is
1066
+ * replaced when getGlobalContext() calls setContext() on first audio init.
1067
+ */
1068
+ interface UseOutputMeterOptions {
1069
+ /**
1070
+ * Number of channels to meter.
1071
+ * Default: 2 (stereo output)
1072
+ */
1073
+ channelCount?: number;
1074
+ /**
1075
+ * How often to update the levels (in Hz).
1076
+ * Default: 60 (60fps)
1077
+ */
1078
+ updateRate?: number;
1079
+ /**
1080
+ * Whether audio is currently playing. When this transitions to false,
1081
+ * all levels (current, peak, RMS) and smoothed state are reset to zero.
1082
+ * Without this, the browser's tail-time optimization stops calling the
1083
+ * worklet's process() when no audio flows, leaving the last non-zero
1084
+ * levels frozen in state.
1085
+ * Default: false
1086
+ */
1087
+ isPlaying?: boolean;
1088
+ }
1089
+ interface UseOutputMeterReturn {
1090
+ /** Per-channel peak output levels (0-1) */
1091
+ levels: number[];
1092
+ /** Per-channel held peak levels (0-1) */
1093
+ peakLevels: number[];
1094
+ /** Per-channel RMS output levels (0-1) */
1095
+ rmsLevels: number[];
1096
+ /** Reset all held peak levels to 0 */
1097
+ resetPeak: () => void;
1098
+ /** Error from meter setup (worklet load failure, context issues, etc.) */
1099
+ error: Error | null;
1100
+ }
1101
+ declare function useOutputMeter(options?: UseOutputMeterOptions): UseOutputMeterReturn;
1102
+
1103
+ /**
1104
+ * Factory for creating Tone.js effect instances from effect definitions
1105
+ */
1106
+
1107
+ interface EffectInstance {
1108
+ effect: ToneAudioNode;
1109
+ id: string;
1110
+ instanceId: string;
1111
+ dispose: () => void;
1112
+ setParameter: (name: string, value: number | string | boolean) => void;
1113
+ getParameter: (name: string) => number | string | boolean | undefined;
1114
+ connect: (destination: InputNode) => void;
1115
+ disconnect: () => void;
1116
+ }
1117
+ /**
1118
+ * Create an effect instance from a definition with initial parameter values
1119
+ */
1120
+ declare function createEffectInstance(definition: EffectDefinition, initialParams?: Record<string, number | string | boolean>): EffectInstance;
1121
+ /**
1122
+ * Create a chain of effects connected in series
1123
+ */
1124
+ declare function createEffectChain(effects: EffectInstance[]): {
1125
+ input: ToneAudioNode;
1126
+ output: ToneAudioNode;
1127
+ dispose: () => void;
1128
+ };
1129
+
1130
+ declare const PlayButton: React__default.FC<{
1131
+ className?: string;
1132
+ }>;
1133
+ declare const PauseButton: React__default.FC<{
1134
+ className?: string;
1135
+ }>;
1136
+ declare const StopButton: React__default.FC<{
1137
+ className?: string;
1138
+ }>;
1139
+ declare const RewindButton: React__default.FC<{
1140
+ className?: string;
1141
+ }>;
1142
+ declare const FastForwardButton: React__default.FC<{
1143
+ className?: string;
1144
+ }>;
1145
+ declare const SkipBackwardButton: React__default.FC<{
1146
+ skipAmount?: number;
1147
+ className?: string;
1148
+ }>;
1149
+ declare const SkipForwardButton: React__default.FC<{
1150
+ skipAmount?: number;
1151
+ className?: string;
1152
+ }>;
1153
+ declare const LoopButton: React__default.FC<{
1154
+ className?: string;
1155
+ }>;
1156
+ declare const SetLoopRegionButton: React__default.FC<{
1157
+ className?: string;
1158
+ }>;
1159
+ interface ClearAllButtonProps {
1160
+ onClearAll: () => void;
1161
+ label?: string;
1162
+ className?: string;
1163
+ }
1164
+ declare const ClearAllButton: React__default.FC<ClearAllButtonProps>;
1165
+
1166
+ declare const ZoomInButton: React__default.FC<{
1167
+ className?: string;
1168
+ disabled?: boolean;
1169
+ }>;
1170
+ declare const ZoomOutButton: React__default.FC<{
1171
+ className?: string;
1172
+ disabled?: boolean;
1173
+ }>;
1174
+
1175
+ /**
1176
+ * Master volume control that uses the playlist context
1177
+ */
1178
+ declare const MasterVolumeControl: React__default.FC<{
1179
+ className?: string;
1180
+ }>;
1181
+ /**
1182
+ * Time format selector that uses the playlist context
1183
+ */
1184
+ declare const TimeFormatSelect: React__default.FC<{
1185
+ className?: string;
1186
+ }>;
1187
+ /**
1188
+ * Audio position display that uses the playlist context.
1189
+ * Uses requestAnimationFrame for smooth 60fps updates during playback.
1190
+ * Direct DOM manipulation avoids React re-renders.
1191
+ */
1192
+ declare const AudioPosition: React__default.FC<{
1193
+ className?: string;
1194
+ }>;
1195
+ /**
1196
+ * Selection time inputs that use the playlist context
1197
+ */
1198
+ declare const SelectionTimeInputs: React__default.FC<{
1199
+ className?: string;
1200
+ }>;
1201
+ /**
1202
+ * Automatic scroll checkbox that uses the playlist context
1203
+ * Uses split contexts to avoid re-rendering during animation
1204
+ */
1205
+ declare const AutomaticScrollCheckbox: React__default.FC<{
1206
+ className?: string;
1207
+ }>;
1208
+
1209
+ /**
1210
+ * Continuous play checkbox that uses the playlist context.
1211
+ * Must be used within <AnnotationProvider>.
1212
+ */
1213
+ declare const ContinuousPlayCheckbox: React__default.FC<{
1214
+ className?: string;
1215
+ }>;
1216
+ /**
1217
+ * Link endpoints checkbox that uses the playlist context.
1218
+ * Must be used within <AnnotationProvider>.
1219
+ */
1220
+ declare const LinkEndpointsCheckbox: React__default.FC<{
1221
+ className?: string;
1222
+ }>;
1223
+ /**
1224
+ * Editable annotations checkbox that uses the playlist context.
1225
+ * Must be used within <AnnotationProvider>.
1226
+ */
1227
+ declare const EditableCheckbox: React__default.FC<{
1228
+ className?: string;
1229
+ }>;
1230
+ /**
1231
+ * Download annotations button that uses the playlist context.
1232
+ * Must be used within <AnnotationProvider>.
1233
+ */
1234
+ declare const DownloadAnnotationsButton: React__default.FC<{
1235
+ filename?: string;
1236
+ className?: string;
1237
+ }>;
1238
+
1239
+ interface ExportWavButtonProps {
1240
+ /** Button label */
1241
+ label?: string;
1242
+ /** Filename for the downloaded file (without extension) */
1243
+ filename?: string;
1244
+ /** Export mode: 'master' for stereo mix, 'individual' for single track */
1245
+ mode?: 'master' | 'individual';
1246
+ /** Track index for individual export */
1247
+ trackIndex?: number;
1248
+ /** Bit depth: 16 or 32 */
1249
+ bitDepth?: 16 | 32;
1250
+ /** Whether to apply effects (fades, etc.) - defaults to true */
1251
+ applyEffects?: boolean;
1252
+ /**
1253
+ * Optional Tone.js effects function for master effects. When provided, export will use Tone.Offline
1254
+ * to render through the effects chain. The function receives isOffline=true.
1255
+ */
1256
+ effectsFunction?: EffectsFunction;
1257
+ /**
1258
+ * Optional function to create offline track effects.
1259
+ * Takes a trackId and returns a TrackEffectsFunction for offline rendering.
1260
+ */
1261
+ createOfflineTrackEffects?: (trackId: string) => TrackEffectsFunction | undefined;
1262
+ /** CSS class name */
1263
+ className?: string;
1264
+ /** Callback when export completes */
1265
+ onExportComplete?: (blob: Blob) => void;
1266
+ /** Callback when export fails */
1267
+ onExportError?: (error: Error) => void;
1268
+ }
1269
+ declare const ExportWavButton: React__default.FC<ExportWavButtonProps>;
1270
+
1271
+ /**
1272
+ * Shared annotation types used across Waveform components
1273
+ */
1274
+
1275
+ /**
1276
+ * Custom function to generate the label shown on annotation boxes in the waveform.
1277
+ * Receives the annotation data and its index in the list, returns a string label.
1278
+ * Default behavior: displays annotation.id
1279
+ */
1280
+ type GetAnnotationBoxLabelFn = (annotation: AnnotationData, index: number) => string;
1281
+ /**
1282
+ * Callback when annotations are updated (e.g., boundaries dragged).
1283
+ * Called with the full updated annotations array.
1284
+ */
1285
+ type OnAnnotationUpdateFn = (annotations: AnnotationData[]) => void;
1286
+
1287
+ interface WaveformProps {
1288
+ renderTrackControls?: (trackIndex: number) => ReactNode;
1289
+ /** Custom render function for timescale tick labels. `label` is a formatted string
1290
+ * (bar/beat notation like "2.3" in beats mode, or "m:ss" in temporal mode). */
1291
+ renderTick?: (label: string, pixelPosition: number) => ReactNode;
1292
+ /** @deprecated Use `renderTick` instead. */
1293
+ renderTimestamp?: (timeMs: number, pixelPosition: number) => ReactNode;
1294
+ /** Custom playhead render function. Receives position (pixels) and color from theme. */
1295
+ renderPlayhead?: RenderPlayheadFunction;
1296
+ annotationControls?: AnnotationAction[];
1297
+ annotationListConfig?: AnnotationActionOptions;
1298
+ annotationTextHeight?: number;
1299
+ /**
1300
+ * Custom render function for annotation items in the text list.
1301
+ * Use this to completely customize how each annotation is displayed.
1302
+ */
1303
+ renderAnnotationItem?: (props: RenderAnnotationItemProps) => ReactNode;
1304
+ /**
1305
+ * Custom function to generate the label shown on annotation boxes in the waveform.
1306
+ * Receives the annotation data and its index, returns a string label.
1307
+ * Default: annotation.id
1308
+ */
1309
+ getAnnotationBoxLabel?: GetAnnotationBoxLabelFn;
1310
+ /** Where to position the active annotation when auto-scrolling: 'center', 'start', 'end', or 'nearest'. Defaults to 'center'. */
1311
+ scrollActivePosition?: ScrollLogicalPosition;
1312
+ /** Which scrollable containers to scroll: 'nearest' (only the annotation list) or 'all' (including viewport). Defaults to 'nearest'. */
1313
+ scrollActiveContainer?: 'nearest' | 'all';
1314
+ className?: string;
1315
+ showClipHeaders?: boolean;
1316
+ interactiveClips?: boolean;
1317
+ showFades?: boolean;
1318
+ /**
1319
+ * Enable mobile-optimized touch interactions.
1320
+ * When true, increases touch target sizes for clip boundaries.
1321
+ * Use with useDragSensors({ touchOptimized: true }) for best results.
1322
+ */
1323
+ touchOptimized?: boolean;
1324
+ /** Callback when a track's close button is clicked. Only renders close button when provided. */
1325
+ onRemoveTrack?: (trackIndex: number) => void;
1326
+ recordingState?: {
1327
+ isRecording: boolean;
1328
+ trackId: string;
1329
+ startSample: number;
1330
+ durationSamples: number;
1331
+ peaks: (Int8Array | Int16Array)[];
1332
+ bits: 8 | 16;
1333
+ };
1334
+ }
1335
+ /**
1336
+ * Waveform visualization component that uses the playlist context.
1337
+ *
1338
+ * Composes PlaylistVisualization (waveform + tracks) and
1339
+ * PlaylistAnnotationList (annotation text list below the waveform).
1340
+ */
1341
+ declare const Waveform: React__default.FC<WaveformProps>;
1342
+
1343
+ interface MediaElementWaveformProps {
1344
+ /** Height in pixels for the annotation text list */
1345
+ annotationTextHeight?: number;
1346
+ /** Custom function to generate the label shown on annotation boxes */
1347
+ getAnnotationBoxLabel?: GetAnnotationBoxLabelFn;
1348
+ /**
1349
+ * Custom render function for annotation items in the text list.
1350
+ * When provided, completely replaces the default annotation item rendering.
1351
+ * Use this to customize the appearance of each annotation (e.g., add furigana).
1352
+ */
1353
+ renderAnnotationItem?: (props: RenderAnnotationItemProps) => React__default.ReactNode;
1354
+ /** Whether annotation boundaries can be edited by dragging. Defaults to false. */
1355
+ editable?: boolean;
1356
+ /** Whether dragging one annotation boundary also moves the adjacent annotation's boundary. Defaults to false. */
1357
+ linkEndpoints?: boolean;
1358
+ /**
1359
+ * Callback when annotations are updated (e.g., boundaries dragged).
1360
+ * Called with the full updated annotations array.
1361
+ */
1362
+ onAnnotationUpdate?: OnAnnotationUpdateFn;
1363
+ /** Where to position the active annotation when auto-scrolling: 'center', 'start', 'end', or 'nearest'. Defaults to 'center'. */
1364
+ scrollActivePosition?: ScrollLogicalPosition;
1365
+ /** Which scrollable containers to scroll: 'nearest' (only the annotation list) or 'all' (including viewport). Defaults to 'nearest'. */
1366
+ scrollActiveContainer?: 'nearest' | 'all';
1367
+ /** Custom playhead render function. Receives position, color, and animation refs for smooth 60fps animation. */
1368
+ renderPlayhead?: RenderPlayheadFunction;
1369
+ /** Show fade in/out overlays on the waveform. Defaults to false. */
1370
+ showFades?: boolean;
1371
+ className?: string;
1372
+ }
1373
+ /**
1374
+ * Simplified Waveform component for MediaElementPlaylistProvider
1375
+ *
1376
+ * This is a stripped-down version of Waveform that works with the
1377
+ * MediaElement context. It supports:
1378
+ * - Single track visualization
1379
+ * - Click to seek
1380
+ * - Annotation display and click-to-play
1381
+ * - Playhead animation
1382
+ *
1383
+ * For multi-track editing, use the full Waveform with WaveformPlaylistProvider.
1384
+ */
1385
+ declare const MediaElementWaveform: React__default.FC<MediaElementWaveformProps>;
1386
+
1387
+ interface MediaElementPlaylistProps {
1388
+ /** Custom function to generate the label shown on annotation boxes */
1389
+ getAnnotationBoxLabel?: GetAnnotationBoxLabelFn;
1390
+ /** Whether annotation boundaries can be edited by dragging. Defaults to false. */
1391
+ editable?: boolean;
1392
+ /** Whether dragging one annotation boundary also moves the adjacent annotation's boundary. Defaults to false. */
1393
+ linkEndpoints?: boolean;
1394
+ /**
1395
+ * Callback when annotations are updated (e.g., boundaries dragged).
1396
+ * Called with the full updated annotations array.
1397
+ */
1398
+ onAnnotationUpdate?: OnAnnotationUpdateFn;
1399
+ /** Custom playhead render function. Receives position, color, and animation refs for smooth 60fps animation. */
1400
+ renderPlayhead?: RenderPlayheadFunction;
1401
+ /** Show fade in/out overlays on the waveform. Defaults to false. */
1402
+ showFades?: boolean;
1403
+ className?: string;
1404
+ }
1405
+ /**
1406
+ * Standalone waveform + annotation boxes component for MediaElementPlaylistProvider.
1407
+ *
1408
+ * Renders the waveform visualization, annotation boxes, selection, and playhead.
1409
+ * Does NOT render the annotation text list — use `MediaElementAnnotationList` for that.
1410
+ *
1411
+ * Must be used inside a `MediaElementPlaylistProvider`.
1412
+ *
1413
+ * This component can be placed independently in consumer layouts, allowing the
1414
+ * waveform and annotation list to be positioned separately (e.g., in different
1415
+ * panels or with custom elements between them).
1416
+ */
1417
+ declare const MediaElementPlaylist: React__default.FC<MediaElementPlaylistProps>;
1418
+
1419
+ interface MediaElementAnnotationListProps {
1420
+ /** Height in pixels for the annotation text list */
1421
+ height?: number;
1422
+ /**
1423
+ * Custom render function for annotation items in the text list.
1424
+ * When provided, completely replaces the default annotation item rendering.
1425
+ */
1426
+ renderAnnotationItem?: (props: RenderAnnotationItemProps) => React__default.ReactNode;
1427
+ /**
1428
+ * Callback when annotations are updated (e.g., text edited).
1429
+ * Called with the full updated annotations array.
1430
+ */
1431
+ onAnnotationUpdate?: OnAnnotationUpdateFn;
1432
+ /** Whether annotation text can be edited. Defaults to false. */
1433
+ editable?: boolean;
1434
+ /**
1435
+ * Action controls to show on each annotation item (e.g., delete, split).
1436
+ * Only rendered when `editable` is true.
1437
+ */
1438
+ controls?: AnnotationAction[];
1439
+ /**
1440
+ * Override annotation list config. Falls back to context values
1441
+ * `{ linkEndpoints: false, continuousPlay }` if not provided.
1442
+ */
1443
+ annotationListConfig?: AnnotationActionOptions;
1444
+ /** Where to position the active annotation when auto-scrolling. Defaults to 'center'. */
1445
+ scrollActivePosition?: ScrollLogicalPosition;
1446
+ /** Which scrollable containers to scroll: 'nearest' or 'all'. Defaults to 'nearest'. */
1447
+ scrollActiveContainer?: 'nearest' | 'all';
1448
+ }
1449
+ /**
1450
+ * Standalone annotation text list component for MediaElementPlaylistProvider.
1451
+ *
1452
+ * Requires @waveform-playlist/annotations with AnnotationProvider.
1453
+ * Throws if used without `<AnnotationProvider>` wrapping the component tree.
1454
+ */
1455
+ declare const MediaElementAnnotationList: React__default.FC<MediaElementAnnotationListProps>;
1456
+
1457
+ interface PlaylistVisualizationProps {
1458
+ renderTrackControls?: (trackIndex: number) => ReactNode;
1459
+ renderTick?: (label: string, pixelPosition: number) => ReactNode;
1460
+ /** Custom playhead render function. Receives position (pixels) and color from theme. */
1461
+ renderPlayhead?: RenderPlayheadFunction;
1462
+ annotationControls?: AnnotationAction[];
1463
+ /**
1464
+ * Custom function to generate the label shown on annotation boxes in the waveform.
1465
+ * Receives the annotation data and its index, returns a string label.
1466
+ * Default: annotation.id
1467
+ */
1468
+ getAnnotationBoxLabel?: GetAnnotationBoxLabelFn;
1469
+ className?: string;
1470
+ showClipHeaders?: boolean;
1471
+ interactiveClips?: boolean;
1472
+ showFades?: boolean;
1473
+ /**
1474
+ * Enable mobile-optimized touch interactions.
1475
+ * When true, increases touch target sizes for clip boundaries.
1476
+ * Use with useDragSensors({ touchOptimized: true }) for best results.
1477
+ */
1478
+ touchOptimized?: boolean;
1479
+ /** Callback when a track's close button is clicked. Only renders close button when provided. */
1480
+ onRemoveTrack?: (trackIndex: number) => void;
1481
+ recordingState?: {
1482
+ isRecording: boolean;
1483
+ trackId: string;
1484
+ startSample: number;
1485
+ durationSamples: number;
1486
+ peaks: (Int8Array | Int16Array)[];
1487
+ bits: 8 | 16;
1488
+ };
1489
+ }
1490
+ /**
1491
+ * Standalone playlist visualization component (WebAudio version).
1492
+ *
1493
+ * Renders the waveform tracks, timescale, annotations boxes, selection,
1494
+ * playhead, loop regions, and track controls everything that lives
1495
+ * inside <Playlist> plus wrapping providers.
1496
+ *
1497
+ * Does NOT render AnnotationText (the annotation list below the waveform).
1498
+ * Pair with PlaylistAnnotationList for a full annotation editing UI.
1499
+ */
1500
+ declare const PlaylistVisualization: React__default.FC<PlaylistVisualizationProps>;
1501
+
1502
+ interface PlaylistAnnotationListProps {
1503
+ /** Height in pixels for the annotation text list */
1504
+ height?: number;
1505
+ /**
1506
+ * Custom render function for annotation items in the text list.
1507
+ * When provided, completely replaces the default annotation item rendering.
1508
+ */
1509
+ renderAnnotationItem?: (props: RenderAnnotationItemProps) => React__default.ReactNode;
1510
+ /**
1511
+ * Callback when annotations are updated (e.g., text edited).
1512
+ * Called with the full updated annotations array.
1513
+ */
1514
+ onAnnotationUpdate?: OnAnnotationUpdateFn;
1515
+ /**
1516
+ * Action controls to show on each annotation item (e.g., delete, split).
1517
+ * Only rendered when `annotationsEditable` is true in context.
1518
+ */
1519
+ controls?: AnnotationAction[];
1520
+ /**
1521
+ * Override annotation list config. Falls back to context values
1522
+ * `{ linkEndpoints, continuousPlay }` if not provided.
1523
+ */
1524
+ annotationListConfig?: AnnotationActionOptions;
1525
+ /** Where to position the active annotation when auto-scrolling. Defaults to 'center'. */
1526
+ scrollActivePosition?: ScrollLogicalPosition;
1527
+ /** Which scrollable containers to scroll: 'nearest' or 'all'. Defaults to 'nearest'. */
1528
+ scrollActiveContainer?: 'nearest' | 'all';
1529
+ }
1530
+ /**
1531
+ * Standalone annotation text list component for WaveformPlaylistProvider (WebAudio).
1532
+ *
1533
+ * Requires @waveform-playlist/annotations with AnnotationProvider.
1534
+ * Throws if used without `<AnnotationProvider>` wrapping the component tree.
1535
+ */
1536
+ declare const PlaylistAnnotationList: React__default.FC<PlaylistAnnotationListProps>;
1537
+
1538
+ interface KeyboardShortcutsProps {
1539
+ /** Enable default playback shortcuts (Space, Escape, 0). Defaults to false. */
1540
+ playback?: boolean;
1541
+ /** Enable clip splitting shortcut ('s' key). Defaults to false. */
1542
+ clipSplitting?: boolean;
1543
+ /** Enable annotation keyboard controls (arrow nav, boundary editing). Defaults to false. */
1544
+ annotations?: boolean;
1545
+ /** Additional shortcuts appended to the defaults. */
1546
+ additionalShortcuts?: KeyboardShortcut[];
1547
+ }
1548
+ /**
1549
+ * Self-closing component that sets up keyboard shortcuts for the playlist.
1550
+ * Must be rendered inside a WaveformPlaylistProvider.
1551
+ *
1552
+ * @example
1553
+ * ```tsx
1554
+ * <WaveformPlaylistProvider tracks={tracks} {...}>
1555
+ * <KeyboardShortcuts playback clipSplitting />
1556
+ * <Waveform />
1557
+ * </WaveformPlaylistProvider>
1558
+ * ```
1559
+ */
1560
+ declare const KeyboardShortcuts: React__default.FC<KeyboardShortcutsProps>;
1561
+
1562
+ /**
1563
+ * Props the browser package passes to the AnnotationText component.
1564
+ * Mirrors what PlaylistAnnotationList and MediaElementAnnotationList actually use.
1565
+ */
1566
+ interface AnnotationTextIntegrationProps {
1567
+ annotations: AnnotationData[];
1568
+ activeAnnotationId?: string;
1569
+ shouldScrollToActive?: boolean;
1570
+ scrollActivePosition?: ScrollLogicalPosition;
1571
+ scrollActiveContainer?: 'nearest' | 'all';
1572
+ editable?: boolean;
1573
+ controls?: AnnotationAction[];
1574
+ annotationListConfig?: AnnotationActionOptions;
1575
+ height?: number;
1576
+ onAnnotationUpdate?: (updatedAnnotations: AnnotationData[]) => void;
1577
+ renderAnnotationItem?: (props: RenderAnnotationItemProps) => React.ReactNode;
1578
+ }
1579
+ /**
1580
+ * Props the browser package passes to the AnnotationBox component.
1581
+ * Mirrors what PlaylistVisualization and MediaElementPlaylist actually use.
1582
+ */
1583
+ interface AnnotationBoxIntegrationProps {
1584
+ annotationId: string;
1585
+ annotationIndex: number;
1586
+ startPosition: number;
1587
+ endPosition: number;
1588
+ label?: string;
1589
+ color?: string;
1590
+ isActive?: boolean;
1591
+ onClick?: () => void;
1592
+ editable?: boolean;
1593
+ }
1594
+ /**
1595
+ * Props the browser package passes to the AnnotationBoxesWrapper component.
1596
+ * Mirrors what PlaylistVisualization and MediaElementPlaylist actually use.
1597
+ */
1598
+ interface AnnotationBoxesWrapperIntegrationProps {
1599
+ children?: React.ReactNode;
1600
+ height?: number;
1601
+ width?: number;
1602
+ }
1603
+ /**
1604
+ * Interface for annotation integration provided by @waveform-playlist/annotations.
1605
+ *
1606
+ * The browser package defines what it needs, and the optional annotations package
1607
+ * provides it via <AnnotationProvider>.
1608
+ */
1609
+ interface AnnotationIntegration {
1610
+ parseAeneas: (data: unknown) => AnnotationData;
1611
+ serializeAeneas: (annotation: AnnotationData) => unknown;
1612
+ AnnotationText: React.ComponentType<AnnotationTextIntegrationProps>;
1613
+ AnnotationBox: React.ComponentType<AnnotationBoxIntegrationProps>;
1614
+ AnnotationBoxesWrapper: React.ComponentType<AnnotationBoxesWrapperIntegrationProps>;
1615
+ ContinuousPlayCheckbox: React.ComponentType<{
1616
+ checked: boolean;
1617
+ onChange: (checked: boolean) => void;
1618
+ className?: string;
1619
+ }>;
1620
+ LinkEndpointsCheckbox: React.ComponentType<{
1621
+ checked: boolean;
1622
+ onChange: (checked: boolean) => void;
1623
+ className?: string;
1624
+ }>;
1625
+ EditableCheckbox: React.ComponentType<{
1626
+ checked: boolean;
1627
+ onChange: (checked: boolean) => void;
1628
+ className?: string;
1629
+ }>;
1630
+ DownloadAnnotationsButton: React.ComponentType<{
1631
+ annotations: AnnotationData[];
1632
+ filename?: string;
1633
+ className?: string;
1634
+ }>;
1635
+ }
1636
+ declare const AnnotationIntegrationProvider: React$1.Provider<AnnotationIntegration | null>;
1637
+ /**
1638
+ * Hook to access annotation integration provided by @waveform-playlist/annotations.
1639
+ * Throws if used without <AnnotationProvider> wrapping the component tree.
1640
+ *
1641
+ * Follows the Kent C. Dodds pattern:
1642
+ * https://kentcdodds.com/blog/how-to-use-react-context-effectively
1643
+ */
1644
+ declare function useAnnotationIntegration(): AnnotationIntegration;
1645
+
1646
+ interface SpectrogramIntegration {
1647
+ trackSpectrogramOverrides: Map<string, TrackSpectrogramOverrides>;
1648
+ spectrogramWorkerApi: SpectrogramWorkerApi | null;
1649
+ spectrogramConfig?: SpectrogramConfig;
1650
+ spectrogramColorMap?: ColorMapValue;
1651
+ setTrackRenderMode: (trackId: string, mode: RenderMode) => void;
1652
+ setTrackSpectrogramConfig: (trackId: string, config: SpectrogramConfig, colorMap?: ColorMapValue) => void;
1653
+ registerSpectrogramCanvases: (clipId: string, channelIndex: number, canvasIds: string[], canvasWidths: number[]) => void;
1654
+ unregisterSpectrogramCanvases: (clipId: string, channelIndex: number) => void;
1655
+ /** Render spectrogram menu items for a track's context menu */
1656
+ renderMenuItems?: (props: {
1657
+ renderMode: string;
1658
+ onRenderModeChange: (mode: RenderMode) => void;
1659
+ onOpenSettings: () => void;
1660
+ onClose?: () => void;
1661
+ }) => TrackMenuItem[];
1662
+ /** Settings modal component provided by the spectrogram package */
1663
+ SettingsModal?: React.ComponentType<{
1664
+ open: boolean;
1665
+ onClose: () => void;
1666
+ config: SpectrogramConfig;
1667
+ colorMap: ColorMapValue;
1668
+ onApply: (config: SpectrogramConfig, colorMap: ColorMapValue) => void;
1669
+ }>;
1670
+ /** Get color lookup table for a color map name */
1671
+ getColorMap: (name: ColorMapValue) => Uint8Array;
1672
+ /** Get frequency scale function for a scale name */
1673
+ getFrequencyScale: (name: string) => (f: number, minF: number, maxF: number) => number;
1674
+ }
1675
+ /** Minimal type for the worker API surface used by browser components */
1676
+ interface SpectrogramWorkerApi {
1677
+ registerCanvas: (canvasId: string, canvas: OffscreenCanvas) => void;
1678
+ unregisterCanvas: (canvasId: string) => void;
1679
+ }
1680
+ declare const SpectrogramIntegrationProvider: React$1.Provider<SpectrogramIntegration | null>;
1681
+ /**
1682
+ * Hook to access spectrogram integration provided by @waveform-playlist/spectrogram.
1683
+ * Throws if used without <SpectrogramProvider> wrapping the component tree.
1684
+ *
1685
+ * Follows the Kent C. Dodds pattern:
1686
+ * https://kentcdodds.com/blog/how-to-use-react-context-effectively
1687
+ */
1688
+ declare function useSpectrogramIntegration(): SpectrogramIntegration;
1689
+
1690
+ interface ClipInteractionProviderProps {
1691
+ /** Enable snap-to-grid for clip moves and boundary trims. When true,
1692
+ * auto-detects beats snapping from BeatsAndBarsProvider context
1693
+ * (if present with scaleMode="beats" and snapTo!="off"), otherwise
1694
+ * falls back to timescale-based snapping. Default: false. */
1695
+ snap?: boolean;
1696
+ touchOptimized?: boolean;
1697
+ children: React__default.ReactNode;
1698
+ }
1699
+ declare const ClipInteractionProvider: React__default.FC<ClipInteractionProviderProps>;
1700
+
1701
+ declare function useClipInteractionEnabled(): boolean;
1702
+
1703
+ interface ClipCollisionOptions {
1704
+ tracks: ClipTrack[];
1705
+ samplesPerPixel: number;
1706
+ }
1707
+ /**
1708
+ * Modifier that constrains clip drag movement to prevent overlaps.
1709
+ *
1710
+ * For clip move operations: constrains horizontal transform to valid positions
1711
+ * using the engine's collision detection.
1712
+ *
1713
+ * For boundary trim operations: returns zero transform because visual feedback
1714
+ * comes from React state updates resizing the clip, not from CSS translate.
1715
+ */
1716
+ declare class ClipCollisionModifier extends Modifier<DragDropManager<any, any>, ClipCollisionOptions> {
1717
+ apply(operation: DragOperation): {
1718
+ x: number;
1719
+ y: number;
1720
+ };
1721
+ static configure: (options: ClipCollisionOptions) => _dnd_kit_abstract.PluginDescriptor<any, any, typeof ClipCollisionModifier>;
1722
+ }
1723
+
1724
+ interface SnapToGridBeatsOptions {
1725
+ mode: 'beats';
1726
+ snapTo: SnapTo;
1727
+ bpm: number;
1728
+ timeSignature: [number, number];
1729
+ samplesPerPixel: number;
1730
+ sampleRate: number;
1731
+ }
1732
+ interface SnapToGridTimescaleOptions {
1733
+ mode: 'timescale';
1734
+ gridSamples: number;
1735
+ samplesPerPixel: number;
1736
+ }
1737
+ type SnapToGridOptions = SnapToGridBeatsOptions | SnapToGridTimescaleOptions;
1738
+ /**
1739
+ * dnd-kit modifier that quantizes clip drag movement to a grid.
1740
+ *
1741
+ * Two modes:
1742
+ * - "beats": Snaps to beat/bar grid using PPQN tick space for exact musical timing.
1743
+ * - "timescale": Snaps to a sample-based grid derived from timescale markers.
1744
+ *
1745
+ * Designed to compose with ClipCollisionModifier — snap first,
1746
+ * then collision constrains the snapped position.
1747
+ */
1748
+ declare class SnapToGridModifier extends Modifier<DragDropManager<any, any>, SnapToGridOptions> {
1749
+ apply(operation: DragOperation): {
1750
+ x: number;
1751
+ y: number;
1752
+ };
1753
+ static configure: (options: SnapToGridBeatsOptions | SnapToGridTimescaleOptions) => _dnd_kit_abstract.PluginDescriptor<any, any, typeof SnapToGridModifier>;
1754
+ }
1755
+
1756
+ /**
1757
+ * DragDropProvider plugins customizer that disables the Feedback plugin's drop animation.
1758
+ *
1759
+ * Without this, the Feedback plugin animates the dragged element back to its original
1760
+ * position on drop, causing a visual snap-back before React re-renders at the new position.
1761
+ *
1762
+ * Usage:
1763
+ * ```tsx
1764
+ * <DragDropProvider plugins={noDropAnimationPlugins} ...>
1765
+ * ```
1766
+ */
1767
+ declare const noDropAnimationPlugins: (defaults: Plugins) => Plugins;
1768
+
1769
+ /**
1770
+ * Waveform Data Loader
1771
+ *
1772
+ * Utilities for loading pre-computed waveform data in waveform-data.js format.
1773
+ * Supports both binary (.dat) and JSON formats from BBC's audiowaveform tool.
1774
+ */
1775
+
1776
+ /**
1777
+ * Load waveform data from a .dat or .json file
1778
+ *
1779
+ * @param src - URL to waveform data file (.dat or .json)
1780
+ * @returns WaveformData instance
1781
+ */
1782
+ declare function loadWaveformData(src: string): Promise<WaveformData>;
1783
+ /**
1784
+ * Convert WaveformData to our internal Peaks format
1785
+ *
1786
+ * @param waveformData - WaveformData instance from waveform-data.js
1787
+ * @param channelIndex - Channel index (0 for mono/left, 1 for right)
1788
+ * @returns Peaks data with alternating min/max values, preserving original bit depth
1789
+ */
1790
+ declare function waveformDataToPeaks(waveformData: WaveformData, channelIndex?: number): {
1791
+ data: Int8Array | Int16Array;
1792
+ bits: 8 | 16;
1793
+ length: number;
1794
+ sampleRate: number;
1795
+ };
1796
+ /**
1797
+ * Load waveform data file and convert to Peaks format in one step
1798
+ *
1799
+ * @param src - URL to waveform data file (.dat or .json)
1800
+ * @param channelIndex - Channel index (default: 0)
1801
+ * @returns Peaks data ready for rendering
1802
+ */
1803
+ declare function loadPeaksFromWaveformData(src: string, channelIndex?: number): Promise<{
1804
+ data: Int8Array | Int16Array;
1805
+ bits: 8 | 16;
1806
+ length: number;
1807
+ sampleRate: number;
1808
+ }>;
1809
+ /**
1810
+ * Get metadata from waveform data file without converting to peaks
1811
+ *
1812
+ * @param src - URL to waveform data file
1813
+ * @returns Metadata (sample rate, channels, duration, bits, etc.)
1814
+ */
1815
+ declare function getWaveformDataMetadata(src: string): Promise<{
1816
+ sampleRate: number;
1817
+ channels: number;
1818
+ duration: number;
1819
+ samplesPerPixel: number;
1820
+ length: number;
1821
+ bits: 8 | 16;
1822
+ }>;
1823
+
1824
+ 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 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, getShortcutLabel, 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 };