@waveform-playlist/browser 5.0.0-alpha.7 → 5.0.0-alpha.9

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
@@ -64,18 +64,37 @@ declare interface AnnotationData {
64
64
  * IMPORTANT: All positions/durations are stored as SAMPLE COUNTS (integers)
65
65
  * to avoid floating-point precision errors. Convert to seconds only when
66
66
  * needed for playback using: seconds = samples / sampleRate
67
+ *
68
+ * Clips can be created with just waveformData (for instant visual rendering)
69
+ * and have audioBuffer added later when audio finishes loading.
67
70
  */
68
71
  export declare interface AudioClip {
69
72
  /** Unique identifier for this clip */
70
73
  id: string;
71
- /** The audio buffer containing the audio data */
72
- audioBuffer: AudioBuffer;
74
+ /**
75
+ * The audio buffer containing the audio data.
76
+ * Optional for peaks-first rendering - can be added later.
77
+ * Required for playback and editing operations.
78
+ */
79
+ audioBuffer?: AudioBuffer;
73
80
  /** Position on timeline where this clip starts (in samples at timeline sampleRate) */
74
81
  startSample: number;
75
82
  /** Duration of this clip (in samples) - how much of the audio buffer to play */
76
83
  durationSamples: number;
77
84
  /** Offset into the audio buffer where playback starts (in samples) - the "trim start" point */
78
85
  offsetSamples: number;
86
+ /**
87
+ * Sample rate for this clip's audio.
88
+ * Required when audioBuffer is not provided (for peaks-first rendering).
89
+ * When audioBuffer is present, this should match audioBuffer.sampleRate.
90
+ */
91
+ sampleRate: number;
92
+ /**
93
+ * Total duration of the source audio in samples.
94
+ * Required when audioBuffer is not provided (for trim bounds calculation).
95
+ * When audioBuffer is present, this should equal audioBuffer.length.
96
+ */
97
+ sourceDurationSamples: number;
79
98
  /** Optional fade in effect */
80
99
  fadeIn?: Fade;
81
100
  /** Optional fade out effect */
@@ -86,6 +105,13 @@ export declare interface AudioClip {
86
105
  name?: string;
87
106
  /** Optional color for visual distinction */
88
107
  color?: string;
108
+ /**
109
+ * Pre-computed waveform data from waveform-data.js library.
110
+ * When provided, the library will use this instead of computing peaks from the audioBuffer.
111
+ * Supports resampling to different zoom levels and slicing for clip trimming.
112
+ * Load with: `const waveformData = await loadWaveformData('/path/to/peaks.dat')`
113
+ */
114
+ waveformData?: WaveformDataObject;
89
115
  }
90
116
 
91
117
  /**
@@ -99,9 +125,20 @@ export declare const AudioPosition: default_2.FC<{
99
125
 
100
126
  /**
101
127
  * Configuration for a single audio track to load
128
+ *
129
+ * Audio can be provided in three ways:
130
+ * 1. `src` - URL to fetch and decode (standard loading)
131
+ * 2. `audioBuffer` - Pre-loaded AudioBuffer (skip fetch/decode)
132
+ * 3. `waveformData` only - Peaks-first rendering (audio loads later)
133
+ *
134
+ * For peaks-first rendering, just provide `waveformData` - the sample rate
135
+ * and duration are derived from the waveform data automatically.
102
136
  */
103
137
  export declare interface AudioTrackConfig {
104
- src: string;
138
+ /** URL to audio file - used if audioBuffer not provided */
139
+ src?: string;
140
+ /** Pre-loaded AudioBuffer - skips fetch/decode if provided */
141
+ audioBuffer?: AudioBuffer;
105
142
  name?: string;
106
143
  muted?: boolean;
107
144
  soloed?: boolean;
@@ -114,6 +151,7 @@ export declare interface AudioTrackConfig {
114
151
  offset?: number;
115
152
  fadeIn?: Fade;
116
153
  fadeOut?: Fade;
154
+ waveformData?: WaveformDataObject;
117
155
  }
118
156
 
119
157
  /**
@@ -786,17 +824,6 @@ declare type TrackClipPeaks = ClipPeaks[];
786
824
 
787
825
  export declare type TrackEffectsFunction = (graphEnd: Gain, masterGainNode: ToneAudioNode, isOffline: boolean) => void | (() => void);
788
826
 
789
- /**
790
- * Clip-Based Model Types
791
- *
792
- * These types support a professional multi-track editing model where:
793
- * - Each track can contain multiple audio clips
794
- * - Clips can be positioned anywhere on the timeline
795
- * - Clips have independent trim points (offset/duration)
796
- * - Gaps between clips are silent
797
- * - Clips can overlap (for crossfades)
798
- */
799
-
800
827
  /**
801
828
  * Generic effects function type for track-level audio processing.
802
829
  *
@@ -971,7 +998,8 @@ declare interface UseAnnotationKeyboardControlsOptions {
971
998
  * with a single clip per track. Supports custom positioning for multi-clip arrangements.
972
999
  *
973
1000
  * @param configs - Array of audio track configurations
974
- * @returns Object with tracks array and loading state
1001
+ * @param options - Optional configuration for loading behavior
1002
+ * @returns Object with tracks array, loading state, and progress info
975
1003
  *
976
1004
  * @example
977
1005
  * ```typescript
@@ -981,25 +1009,48 @@ declare interface UseAnnotationKeyboardControlsOptions {
981
1009
  * { src: 'audio/drums.mp3', name: 'Drums' },
982
1010
  * ]);
983
1011
  *
984
- * // Multi-clip positioning (clips at different times with gaps)
985
- * const { tracks, loading, error } = useAudioTracks([
986
- * { src: 'audio/guitar.mp3', name: 'Guitar Clip 1', startTime: 0, duration: 3 },
987
- * { src: 'audio/guitar.mp3', name: 'Guitar Clip 2', startTime: 5, duration: 3, offset: 5 },
988
- * { src: 'audio/vocals.mp3', name: 'Vocals', startTime: 2, duration: 4 },
1012
+ * // Progressive loading (tracks appear as they load)
1013
+ * const { tracks, loading, loadedCount, totalCount } = useAudioTracks(
1014
+ * [{ src: 'audio/vocals.mp3' }, { src: 'audio/drums.mp3' }],
1015
+ * { progressive: true }
1016
+ * );
1017
+ *
1018
+ * // Pre-loaded AudioBuffer (skip fetch/decode)
1019
+ * const { tracks } = useAudioTracks([
1020
+ * { audioBuffer: myPreloadedBuffer, name: 'Pre-loaded' },
989
1021
  * ]);
990
1022
  *
991
- * if (loading) return <div>Loading...</div>;
1023
+ * // Peaks-first rendering (instant visual, audio loads later)
1024
+ * const { tracks } = useAudioTracks([
1025
+ * { waveformData: preloadedPeaks, name: 'Peaks Only' }, // Renders immediately
1026
+ * ]);
1027
+ *
1028
+ * if (loading) return <div>Loading {loadedCount}/{totalCount}...</div>;
992
1029
  * if (error) return <div>Error: {error}</div>;
993
1030
  *
994
1031
  * return <WaveformPlaylistProvider tracks={tracks}>...</WaveformPlaylistProvider>;
995
1032
  * ```
996
1033
  */
997
- export declare function useAudioTracks(configs: AudioTrackConfig[]): {
1034
+ export declare function useAudioTracks(configs: AudioTrackConfig[], options?: UseAudioTracksOptions): {
998
1035
  tracks: ClipTrack[];
999
1036
  loading: boolean;
1000
1037
  error: string | null;
1038
+ loadedCount: number;
1039
+ totalCount: number;
1001
1040
  };
1002
1041
 
1042
+ /**
1043
+ * Options for useAudioTracks hook
1044
+ */
1045
+ declare interface UseAudioTracksOptions {
1046
+ /**
1047
+ * When true, tracks are added to the playlist progressively as they load,
1048
+ * rather than waiting for all tracks to finish loading.
1049
+ * Default: false (wait for all tracks)
1050
+ */
1051
+ progressive?: boolean;
1052
+ }
1053
+
1003
1054
  /**
1004
1055
  * Custom hook for handling clip drag operations (movement and trimming)
1005
1056
  *
@@ -1373,6 +1424,56 @@ export declare const Waveform: default_2.FC<WaveformProps>;
1373
1424
  */
1374
1425
  declare type WaveformColor = string | WaveformGradient;
1375
1426
 
1427
+ /**
1428
+ * Clip-Based Model Types
1429
+ *
1430
+ * These types support a professional multi-track editing model where:
1431
+ * - Each track can contain multiple audio clips
1432
+ * - Clips can be positioned anywhere on the timeline
1433
+ * - Clips have independent trim points (offset/duration)
1434
+ * - Gaps between clips are silent
1435
+ * - Clips can overlap (for crossfades)
1436
+ */
1437
+
1438
+ /**
1439
+ * WaveformData object from waveform-data.js library.
1440
+ * Supports resample() and slice() for dynamic zoom levels.
1441
+ * See: https://github.com/bbc/waveform-data.js
1442
+ */
1443
+ declare interface WaveformDataObject {
1444
+ /** Sample rate of the original audio */
1445
+ readonly sample_rate: number;
1446
+ /** Number of audio samples per pixel */
1447
+ readonly scale: number;
1448
+ /** Length of waveform data in pixels */
1449
+ readonly length: number;
1450
+ /** Bit depth (8 or 16) */
1451
+ readonly bits: number;
1452
+ /** Duration in seconds */
1453
+ readonly duration: number;
1454
+ /** Number of channels */
1455
+ readonly channels: number;
1456
+ /** Get channel data */
1457
+ channel: (index: number) => {
1458
+ min_array: () => number[];
1459
+ max_array: () => number[];
1460
+ };
1461
+ /** Resample to different scale */
1462
+ resample: (options: {
1463
+ scale: number;
1464
+ } | {
1465
+ width: number;
1466
+ }) => WaveformDataObject;
1467
+ /** Slice a portion of the waveform */
1468
+ slice: (options: {
1469
+ startTime: number;
1470
+ endTime: number;
1471
+ } | {
1472
+ startIndex: number;
1473
+ endIndex: number;
1474
+ }) => WaveformDataObject;
1475
+ }
1476
+
1376
1477
  /**
1377
1478
  * Convert WaveformData to our internal Peaks format
1378
1479
  *