@waveform-playlist/browser 5.0.0-alpha.8 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ import { default as default_3 } from 'waveform-data';
4
4
  import { DragEndEvent } from '@dnd-kit/core';
5
5
  import { Fade as Fade_2 } from '@waveform-playlist/core';
6
6
  import { Gain } from 'tone';
7
+ import { MediaElementPlayout } from '@waveform-playlist/media-element-playout';
7
8
  import { MutableRefObject } from 'react';
8
9
  import react__default from 'react';
9
10
  import { ReactNode } from 'react';
@@ -50,7 +51,7 @@ declare interface AnnotationActionOptions {
50
51
  [key: string]: unknown;
51
52
  }
52
53
 
53
- declare interface AnnotationData {
54
+ export declare interface AnnotationData {
54
55
  id: string;
55
56
  start: number;
56
57
  end: number;
@@ -58,24 +59,56 @@ declare interface AnnotationData {
58
59
  language?: string;
59
60
  }
60
61
 
62
+ /**
63
+ * Shared annotation types used across Waveform components
64
+ */
65
+ /**
66
+ * Base annotation data structure
67
+ */
68
+ declare interface AnnotationData_2 {
69
+ id: string;
70
+ start: number;
71
+ end: number;
72
+ lines: string[];
73
+ }
74
+
61
75
  /**
62
76
  * Represents a single audio clip on the timeline
63
77
  *
64
78
  * IMPORTANT: All positions/durations are stored as SAMPLE COUNTS (integers)
65
79
  * to avoid floating-point precision errors. Convert to seconds only when
66
80
  * needed for playback using: seconds = samples / sampleRate
81
+ *
82
+ * Clips can be created with just waveformData (for instant visual rendering)
83
+ * and have audioBuffer added later when audio finishes loading.
67
84
  */
68
85
  export declare interface AudioClip {
69
86
  /** Unique identifier for this clip */
70
87
  id: string;
71
- /** The audio buffer containing the audio data */
72
- audioBuffer: AudioBuffer;
88
+ /**
89
+ * The audio buffer containing the audio data.
90
+ * Optional for peaks-first rendering - can be added later.
91
+ * Required for playback and editing operations.
92
+ */
93
+ audioBuffer?: AudioBuffer;
73
94
  /** Position on timeline where this clip starts (in samples at timeline sampleRate) */
74
95
  startSample: number;
75
96
  /** Duration of this clip (in samples) - how much of the audio buffer to play */
76
97
  durationSamples: number;
77
98
  /** Offset into the audio buffer where playback starts (in samples) - the "trim start" point */
78
99
  offsetSamples: number;
100
+ /**
101
+ * Sample rate for this clip's audio.
102
+ * Required when audioBuffer is not provided (for peaks-first rendering).
103
+ * When audioBuffer is present, this should match audioBuffer.sampleRate.
104
+ */
105
+ sampleRate: number;
106
+ /**
107
+ * Total duration of the source audio in samples.
108
+ * Required when audioBuffer is not provided (for trim bounds calculation).
109
+ * When audioBuffer is present, this should equal audioBuffer.length.
110
+ */
111
+ sourceDurationSamples: number;
79
112
  /** Optional fade in effect */
80
113
  fadeIn?: Fade;
81
114
  /** Optional fade out effect */
@@ -106,9 +139,20 @@ export declare const AudioPosition: default_2.FC<{
106
139
 
107
140
  /**
108
141
  * Configuration for a single audio track to load
142
+ *
143
+ * Audio can be provided in three ways:
144
+ * 1. `src` - URL to fetch and decode (standard loading)
145
+ * 2. `audioBuffer` - Pre-loaded AudioBuffer (skip fetch/decode)
146
+ * 3. `waveformData` only - Peaks-first rendering (audio loads later)
147
+ *
148
+ * For peaks-first rendering, just provide `waveformData` - the sample rate
149
+ * and duration are derived from the waveform data automatically.
109
150
  */
110
151
  export declare interface AudioTrackConfig {
111
- src: string;
152
+ /** URL to audio file - used if audioBuffer not provided */
153
+ src?: string;
154
+ /** Pre-loaded AudioBuffer - skips fetch/decode if provided */
155
+ audioBuffer?: AudioBuffer;
112
156
  name?: string;
113
157
  muted?: boolean;
114
158
  soloed?: boolean;
@@ -380,6 +424,21 @@ export declare const FastForwardButton: default_2.FC<{
380
424
  className?: string;
381
425
  }>;
382
426
 
427
+ /**
428
+ * Custom function to generate the label shown on annotation boxes in the waveform.
429
+ * Receives the annotation data and its index in the list, returns a string label.
430
+ * Default behavior: displays annotation.id
431
+ *
432
+ * @example
433
+ * // Show sequence numbers
434
+ * getAnnotationBoxLabel={(annotation, index) => String(index + 1)}
435
+ *
436
+ * @example
437
+ * // Show formatted time
438
+ * getAnnotationBoxLabel={(annotation) => formatTime(annotation.start)}
439
+ */
440
+ export declare type GetAnnotationBoxLabelFn = (annotation: AnnotationData_2, index: number) => string;
441
+
383
442
  export declare const getEffectDefinition: (id: string) => EffectDefinition | undefined;
384
443
 
385
444
  export declare const getEffectsByCategory: (category: EffectDefinition["category"]) => EffectDefinition[];
@@ -500,12 +559,165 @@ export declare interface MasterVolumeControls {
500
559
  setMasterVolume: (volume: number) => void;
501
560
  }
502
561
 
562
+ export declare interface MediaElementAnimationContextValue {
563
+ isPlaying: boolean;
564
+ currentTime: number;
565
+ currentTimeRef: default_2.RefObject<number>;
566
+ }
567
+
568
+ export declare interface MediaElementControlsContextValue {
569
+ play: (startTime?: number) => void;
570
+ pause: () => void;
571
+ stop: () => void;
572
+ seekTo: (time: number) => void;
573
+ setPlaybackRate: (rate: number) => void;
574
+ setContinuousPlay: (enabled: boolean) => void;
575
+ setAnnotations: (annotations: AnnotationData[]) => void;
576
+ setActiveAnnotationId: (id: string | null) => void;
577
+ setAutomaticScroll: (enabled: boolean) => void;
578
+ setScrollContainer: (element: HTMLDivElement | null) => void;
579
+ scrollContainerRef: default_2.RefObject<HTMLDivElement | null>;
580
+ }
581
+
582
+ export declare interface MediaElementDataContextValue {
583
+ duration: number;
584
+ peaksDataArray: TrackClipPeaks[];
585
+ sampleRate: number;
586
+ waveHeight: number;
587
+ timeScaleHeight: number;
588
+ samplesPerPixel: number;
589
+ playoutRef: default_2.RefObject<MediaElementPlayout | null>;
590
+ controls: {
591
+ show: boolean;
592
+ width: number;
593
+ };
594
+ barWidth: number;
595
+ barGap: number;
596
+ progressBarWidth: number;
597
+ }
598
+
599
+ /**
600
+ * MediaElementPlaylistProvider
601
+ *
602
+ * A simplified playlist provider for single-track playback using HTMLAudioElement.
603
+ * Key features:
604
+ * - Pitch-preserving playback rate (0.5x - 2.0x)
605
+ * - Pre-computed peaks visualization (no AudioBuffer needed)
606
+ * - Simpler API than full WaveformPlaylistProvider
607
+ *
608
+ * Use this for:
609
+ * - Language learning apps (speed control)
610
+ * - Podcast players
611
+ * - Single-track audio viewers
612
+ *
613
+ * For multi-track editing, use WaveformPlaylistProvider instead.
614
+ */
615
+ export declare const MediaElementPlaylistProvider: default_2.FC<MediaElementPlaylistProviderProps>;
616
+
617
+ declare interface MediaElementPlaylistProviderProps {
618
+ /** Single track configuration with source URL and waveform data */
619
+ track: MediaElementTrackConfig;
620
+ /** Initial samples per pixel (zoom level) */
621
+ samplesPerPixel?: number;
622
+ /** Height of each waveform track */
623
+ waveHeight?: number;
624
+ /** Show timescale */
625
+ timescale?: boolean;
626
+ /** Initial playback rate (0.5 to 2.0) */
627
+ playbackRate?: number;
628
+ /** Enable automatic scroll to keep playhead centered */
629
+ automaticScroll?: boolean;
630
+ /** Theme configuration */
631
+ theme?: Partial<WaveformPlaylistTheme>;
632
+ /** Track controls configuration */
633
+ controls?: {
634
+ show: boolean;
635
+ width: number;
636
+ };
637
+ /** Annotations */
638
+ annotationList?: {
639
+ annotations?: any[];
640
+ isContinuousPlay?: boolean;
641
+ };
642
+ /** Width of waveform bars */
643
+ barWidth?: number;
644
+ /** Gap between waveform bars */
645
+ barGap?: number;
646
+ /** Width of progress bars */
647
+ progressBarWidth?: number;
648
+ /** Callback when audio is ready */
649
+ onReady?: () => void;
650
+ children: ReactNode;
651
+ }
652
+
653
+ export declare interface MediaElementStateContextValue {
654
+ continuousPlay: boolean;
655
+ annotations: AnnotationData[];
656
+ activeAnnotationId: string | null;
657
+ playbackRate: number;
658
+ isAutomaticScroll: boolean;
659
+ }
660
+
661
+ export declare interface MediaElementTrackConfig {
662
+ /** Audio source URL or Blob URL */
663
+ source: string;
664
+ /** Pre-computed waveform data (required for visualization) */
665
+ waveformData: WaveformDataObject;
666
+ /** Track name for display */
667
+ name?: string;
668
+ }
669
+
670
+ /**
671
+ * Simplified Waveform component for MediaElementPlaylistProvider
672
+ *
673
+ * This is a stripped-down version of Waveform that works with the
674
+ * MediaElement context. It supports:
675
+ * - Single track visualization
676
+ * - Click to seek
677
+ * - Annotation display and click-to-play
678
+ * - Playhead animation
679
+ *
680
+ * For multi-track editing, use the full Waveform with WaveformPlaylistProvider.
681
+ */
682
+ export declare const MediaElementWaveform: default_2.FC<MediaElementWaveformProps>;
683
+
684
+ export declare interface MediaElementWaveformProps {
685
+ /** Height in pixels for the annotation text list */
686
+ annotationTextHeight?: number;
687
+ /** Custom function to generate the label shown on annotation boxes */
688
+ getAnnotationBoxLabel?: GetAnnotationBoxLabelFn;
689
+ /**
690
+ * Custom render function for annotation items in the text list.
691
+ * When provided, completely replaces the default annotation item rendering.
692
+ * Use this to customize the appearance of each annotation (e.g., add furigana).
693
+ */
694
+ renderAnnotationItem?: (props: RenderAnnotationItemProps) => default_2.ReactNode;
695
+ /** Whether annotation boundaries can be edited by dragging. Defaults to false. */
696
+ editable?: boolean;
697
+ /**
698
+ * Callback when annotations are updated (e.g., boundaries dragged).
699
+ * Called with the full updated annotations array.
700
+ */
701
+ onAnnotationUpdate?: OnAnnotationUpdateFn;
702
+ /** Where to position the active annotation when auto-scrolling: 'center', 'start', 'end', or 'nearest'. Defaults to 'center'. */
703
+ scrollActivePosition?: ScrollLogicalPosition;
704
+ /** Which scrollable containers to scroll: 'nearest' (only the annotation list) or 'all' (including viewport). Defaults to 'nearest'. */
705
+ scrollActiveContainer?: 'nearest' | 'all';
706
+ className?: string;
707
+ }
708
+
503
709
  declare interface MicrophoneDevice {
504
710
  deviceId: string;
505
711
  label: string;
506
712
  groupId: string;
507
713
  }
508
714
 
715
+ /**
716
+ * Callback when annotations are updated (e.g., boundaries dragged).
717
+ * Called with the full updated annotations array.
718
+ */
719
+ export declare type OnAnnotationUpdateFn = (annotations: AnnotationData_2[]) => void;
720
+
509
721
  /**
510
722
  * Effect definitions for all available Tone.js effects
511
723
  * Each effect has parameters with min/max/default values for UI controls
@@ -643,6 +855,17 @@ declare interface PlaylistStateContextValue {
643
855
  loopEnd: number;
644
856
  }
645
857
 
858
+ /**
859
+ * Props passed to the renderAnnotationItem function for custom rendering
860
+ */
861
+ export declare interface RenderAnnotationItemProps {
862
+ annotation: AnnotationData;
863
+ index: number;
864
+ isActive: boolean;
865
+ onClick: () => void;
866
+ formatTime: (seconds: number) => string;
867
+ }
868
+
646
869
  /**
647
870
  * Type for custom playhead render functions.
648
871
  * Receives position, color, and animation refs for smooth 60fps animation.
@@ -968,7 +1191,8 @@ declare interface UseAnnotationKeyboardControlsOptions {
968
1191
  * with a single clip per track. Supports custom positioning for multi-clip arrangements.
969
1192
  *
970
1193
  * @param configs - Array of audio track configurations
971
- * @returns Object with tracks array and loading state
1194
+ * @param options - Optional configuration for loading behavior
1195
+ * @returns Object with tracks array, loading state, and progress info
972
1196
  *
973
1197
  * @example
974
1198
  * ```typescript
@@ -978,25 +1202,48 @@ declare interface UseAnnotationKeyboardControlsOptions {
978
1202
  * { src: 'audio/drums.mp3', name: 'Drums' },
979
1203
  * ]);
980
1204
  *
981
- * // Multi-clip positioning (clips at different times with gaps)
982
- * const { tracks, loading, error } = useAudioTracks([
983
- * { src: 'audio/guitar.mp3', name: 'Guitar Clip 1', startTime: 0, duration: 3 },
984
- * { src: 'audio/guitar.mp3', name: 'Guitar Clip 2', startTime: 5, duration: 3, offset: 5 },
985
- * { src: 'audio/vocals.mp3', name: 'Vocals', startTime: 2, duration: 4 },
1205
+ * // Progressive loading (tracks appear as they load)
1206
+ * const { tracks, loading, loadedCount, totalCount } = useAudioTracks(
1207
+ * [{ src: 'audio/vocals.mp3' }, { src: 'audio/drums.mp3' }],
1208
+ * { progressive: true }
1209
+ * );
1210
+ *
1211
+ * // Pre-loaded AudioBuffer (skip fetch/decode)
1212
+ * const { tracks } = useAudioTracks([
1213
+ * { audioBuffer: myPreloadedBuffer, name: 'Pre-loaded' },
986
1214
  * ]);
987
1215
  *
988
- * if (loading) return <div>Loading...</div>;
1216
+ * // Peaks-first rendering (instant visual, audio loads later)
1217
+ * const { tracks } = useAudioTracks([
1218
+ * { waveformData: preloadedPeaks, name: 'Peaks Only' }, // Renders immediately
1219
+ * ]);
1220
+ *
1221
+ * if (loading) return <div>Loading {loadedCount}/{totalCount}...</div>;
989
1222
  * if (error) return <div>Error: {error}</div>;
990
1223
  *
991
1224
  * return <WaveformPlaylistProvider tracks={tracks}>...</WaveformPlaylistProvider>;
992
1225
  * ```
993
1226
  */
994
- export declare function useAudioTracks(configs: AudioTrackConfig[]): {
1227
+ export declare function useAudioTracks(configs: AudioTrackConfig[], options?: UseAudioTracksOptions): {
995
1228
  tracks: ClipTrack[];
996
1229
  loading: boolean;
997
1230
  error: string | null;
1231
+ loadedCount: number;
1232
+ totalCount: number;
998
1233
  };
999
1234
 
1235
+ /**
1236
+ * Options for useAudioTracks hook
1237
+ */
1238
+ declare interface UseAudioTracksOptions {
1239
+ /**
1240
+ * When true, tracks are added to the playlist progressively as they load,
1241
+ * rather than waiting for all tracks to finish loading.
1242
+ * Default: false (wait for all tracks)
1243
+ */
1244
+ progressive?: boolean;
1245
+ }
1246
+
1000
1247
  /**
1001
1248
  * Custom hook for handling clip drag operations (movement and trimming)
1002
1249
  *
@@ -1249,6 +1496,14 @@ declare interface UseMasterVolumeProps {
1249
1496
  onVolumeChange?: (volume: number) => void;
1250
1497
  }
1251
1498
 
1499
+ export declare const useMediaElementAnimation: () => MediaElementAnimationContextValue;
1500
+
1501
+ export declare const useMediaElementControls: () => MediaElementControlsContextValue;
1502
+
1503
+ export declare const useMediaElementData: () => MediaElementDataContextValue;
1504
+
1505
+ export declare const useMediaElementState: () => MediaElementStateContextValue;
1506
+
1252
1507
  export declare const usePlaybackAnimation: () => PlaybackAnimationContextValue;
1253
1508
 
1254
1509
  /**
@@ -1599,6 +1854,21 @@ export declare interface WaveformProps {
1599
1854
  annotationControls?: AnnotationAction[];
1600
1855
  annotationListConfig?: AnnotationActionOptions;
1601
1856
  annotationTextHeight?: number;
1857
+ /**
1858
+ * Custom render function for annotation items in the text list.
1859
+ * Use this to completely customize how each annotation is displayed.
1860
+ */
1861
+ renderAnnotationItem?: (props: RenderAnnotationItemProps) => ReactNode;
1862
+ /**
1863
+ * Custom function to generate the label shown on annotation boxes in the waveform.
1864
+ * Receives the annotation data and its index, returns a string label.
1865
+ * Default: annotation.id
1866
+ */
1867
+ getAnnotationBoxLabel?: GetAnnotationBoxLabelFn;
1868
+ /** Where to position the active annotation when auto-scrolling: 'center', 'start', 'end', or 'nearest'. Defaults to 'center'. */
1869
+ scrollActivePosition?: ScrollLogicalPosition;
1870
+ /** Which scrollable containers to scroll: 'nearest' (only the annotation list) or 'all' (including viewport). Defaults to 'nearest'. */
1871
+ scrollActiveContainer?: 'nearest' | 'all';
1602
1872
  className?: string;
1603
1873
  showClipHeaders?: boolean;
1604
1874
  interactiveClips?: boolean;