@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.mts +1824 -0
- package/dist/index.d.ts +1824 -2464
- package/dist/index.js +7124 -924
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5718 -14795
- package/dist/index.mjs.map +1 -1
- package/package.json +13 -15
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,1824 @@
|
|
|
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 };
|