@waveform-playlist/browser 13.1.3 → 14.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +34 -433
- package/dist/index.d.ts +34 -433
- package/dist/index.js +610 -2371
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +507 -2291
- package/dist/index.mjs.map +1 -1
- package/dist/tone.d.mts +429 -0
- package/dist/tone.d.ts +429 -0
- package/dist/tone.js +1963 -0
- package/dist/tone.js.map +1 -0
- package/dist/tone.mjs +1958 -0
- package/dist/tone.mjs.map +1 -0
- package/package.json +23 -8
package/dist/index.mjs
CHANGED
|
@@ -50,30 +50,52 @@ var __async = (__this, __arguments, generator) => {
|
|
|
50
50
|
});
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
-
// src/index.tsx
|
|
54
|
-
import * as Tone2 from "tone";
|
|
55
|
-
|
|
56
53
|
// src/WaveformPlaylistContext.tsx
|
|
57
54
|
import {
|
|
58
55
|
createContext,
|
|
59
56
|
useContext,
|
|
60
|
-
useState as
|
|
61
|
-
useEffect as
|
|
62
|
-
useRef as
|
|
63
|
-
useCallback as
|
|
64
|
-
useMemo as
|
|
57
|
+
useState as useState9,
|
|
58
|
+
useEffect as useEffect5,
|
|
59
|
+
useRef as useRef9,
|
|
60
|
+
useCallback as useCallback13,
|
|
61
|
+
useMemo as useMemo3
|
|
65
62
|
} from "react";
|
|
66
63
|
import { ThemeProvider } from "styled-components";
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
|
|
65
|
+
// src/playout/resolvePlayoutAdapter.ts
|
|
66
|
+
var INSTALL_HINT = "@waveform-playlist/playout (and its peer `tone`) is required for the default WebAudio engine. Install with: npm install @waveform-playlist/playout tone \u2014 or pass a custom `createAdapter`.";
|
|
67
|
+
function resolvePlayoutAdapter(opts) {
|
|
68
|
+
return __async(this, null, function* () {
|
|
69
|
+
if (opts.createAdapter) {
|
|
70
|
+
return opts.createAdapter();
|
|
71
|
+
}
|
|
72
|
+
let mod;
|
|
73
|
+
try {
|
|
74
|
+
mod = yield import("@waveform-playlist/playout");
|
|
75
|
+
} catch (originalErr) {
|
|
76
|
+
console.warn(
|
|
77
|
+
"[waveform-playlist] @waveform-playlist/playout dynamic import failed: " + String(originalErr)
|
|
78
|
+
);
|
|
79
|
+
throw new Error(INSTALL_HINT);
|
|
80
|
+
}
|
|
81
|
+
if (opts.sampleRate !== void 0) {
|
|
82
|
+
try {
|
|
83
|
+
mod.configureGlobalContext({ sampleRate: opts.sampleRate });
|
|
84
|
+
} catch (ctxErr) {
|
|
85
|
+
console.warn(
|
|
86
|
+
"[waveform-playlist] configureGlobalContext failed (continuing with default rate): " + String(ctxErr)
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return mod.createToneAdapter({ effects: opts.effects, soundFontCache: opts.soundFontCache });
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/WaveformPlaylistContext.tsx
|
|
72
95
|
import { PlaylistEngine } from "@waveform-playlist/engine";
|
|
73
96
|
import {
|
|
74
97
|
defaultTheme
|
|
75
98
|
} from "@waveform-playlist/ui-components";
|
|
76
|
-
import { getContext as getContext2 } from "tone";
|
|
77
99
|
|
|
78
100
|
// src/waveformDataLoader.ts
|
|
79
101
|
import WaveformData from "waveform-data";
|
|
@@ -239,9 +261,11 @@ function extractPeaksFromWaveformDataFull(waveformData, samplesPerPixel, isMono,
|
|
|
239
261
|
}
|
|
240
262
|
|
|
241
263
|
// src/soundFontSync.ts
|
|
242
|
-
|
|
264
|
+
function supportsSoundFont(adapter) {
|
|
265
|
+
return adapter != null && typeof adapter.setSoundFontCache === "function";
|
|
266
|
+
}
|
|
243
267
|
function syncSoundFontCacheToAdapter(adapter, cache) {
|
|
244
|
-
if (!
|
|
268
|
+
if (!supportsSoundFont(adapter)) return;
|
|
245
269
|
adapter.setSoundFontCache(cache);
|
|
246
270
|
}
|
|
247
271
|
|
|
@@ -501,224 +525,6 @@ function useUndoState({ engineRef }) {
|
|
|
501
525
|
};
|
|
502
526
|
}
|
|
503
527
|
|
|
504
|
-
// src/hooks/useAudioEffects.ts
|
|
505
|
-
import { useRef as useRef7, useCallback as useCallback7 } from "react";
|
|
506
|
-
import { Analyser } from "tone";
|
|
507
|
-
var useMasterAnalyser = (fftSize = 256) => {
|
|
508
|
-
const analyserRef = useRef7(null);
|
|
509
|
-
const masterEffects = useCallback7(
|
|
510
|
-
(masterGainNode, destination, _isOffline) => {
|
|
511
|
-
const analyserNode = new Analyser("fft", fftSize);
|
|
512
|
-
masterGainNode.connect(analyserNode);
|
|
513
|
-
masterGainNode.connect(destination);
|
|
514
|
-
analyserRef.current = analyserNode;
|
|
515
|
-
return function cleanup() {
|
|
516
|
-
analyserNode.dispose();
|
|
517
|
-
analyserRef.current = null;
|
|
518
|
-
};
|
|
519
|
-
},
|
|
520
|
-
[fftSize]
|
|
521
|
-
);
|
|
522
|
-
return { analyserRef, masterEffects };
|
|
523
|
-
};
|
|
524
|
-
|
|
525
|
-
// src/hooks/useAudioTracks.ts
|
|
526
|
-
import { useState as useState8, useEffect, useRef as useRef8, useMemo } from "react";
|
|
527
|
-
import {
|
|
528
|
-
createTrack,
|
|
529
|
-
createClipFromSeconds
|
|
530
|
-
} from "@waveform-playlist/core";
|
|
531
|
-
import * as Tone from "tone";
|
|
532
|
-
function buildTrackFromConfig(config, index, audioBuffer, stableIds, contextSampleRate = 48e3) {
|
|
533
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
|
|
534
|
-
const buffer = audioBuffer != null ? audioBuffer : config.audioBuffer;
|
|
535
|
-
const sampleRate = (_c = (_b = buffer == null ? void 0 : buffer.sampleRate) != null ? _b : (_a = config.waveformData) == null ? void 0 : _a.sample_rate) != null ? _c : contextSampleRate;
|
|
536
|
-
const sourceDuration = (_g = (_e = buffer == null ? void 0 : buffer.duration) != null ? _e : (_d = config.waveformData) == null ? void 0 : _d.duration) != null ? _g : config.duration != null ? config.duration + ((_f = config.offset) != null ? _f : 0) : void 0;
|
|
537
|
-
if (sourceDuration === void 0) {
|
|
538
|
-
console.warn(
|
|
539
|
-
`[waveform-playlist] Track ${index + 1} ("${(_h = config.name) != null ? _h : "unnamed"}"): Cannot create track \u2014 provide duration, audioBuffer, or waveformData with duration.`
|
|
540
|
-
);
|
|
541
|
-
return null;
|
|
542
|
-
}
|
|
543
|
-
const clip = createClipFromSeconds({
|
|
544
|
-
audioBuffer: buffer,
|
|
545
|
-
sampleRate,
|
|
546
|
-
sourceDuration,
|
|
547
|
-
startTime: (_i = config.startTime) != null ? _i : 0,
|
|
548
|
-
duration: (_j = config.duration) != null ? _j : sourceDuration,
|
|
549
|
-
offset: (_k = config.offset) != null ? _k : 0,
|
|
550
|
-
name: config.name || `Track ${index + 1}`,
|
|
551
|
-
fadeIn: config.fadeIn,
|
|
552
|
-
fadeOut: config.fadeOut,
|
|
553
|
-
waveformData: config.waveformData
|
|
554
|
-
});
|
|
555
|
-
if (isNaN(clip.startSample) || isNaN(clip.durationSamples) || isNaN(clip.offsetSamples)) {
|
|
556
|
-
console.error(
|
|
557
|
-
`[waveform-playlist] Invalid clip values for track ${index + 1} ("${(_l = config.name) != null ? _l : "unnamed"}"): startSample=${clip.startSample}, durationSamples=${clip.durationSamples}, offsetSamples=${clip.offsetSamples}`
|
|
558
|
-
);
|
|
559
|
-
return null;
|
|
560
|
-
}
|
|
561
|
-
const track = __spreadProps(__spreadValues({}, createTrack({
|
|
562
|
-
name: config.name || `Track ${index + 1}`,
|
|
563
|
-
clips: [clip],
|
|
564
|
-
muted: (_m = config.muted) != null ? _m : false,
|
|
565
|
-
soloed: (_n = config.soloed) != null ? _n : false,
|
|
566
|
-
volume: (_o = config.volume) != null ? _o : 1,
|
|
567
|
-
pan: (_p = config.pan) != null ? _p : 0,
|
|
568
|
-
color: config.color
|
|
569
|
-
})), {
|
|
570
|
-
effects: config.effects,
|
|
571
|
-
renderMode: config.renderMode,
|
|
572
|
-
spectrogramConfig: config.spectrogramConfig,
|
|
573
|
-
spectrogramColorMap: config.spectrogramColorMap
|
|
574
|
-
});
|
|
575
|
-
const existingIds = stableIds.get(index);
|
|
576
|
-
if (existingIds) {
|
|
577
|
-
track.id = existingIds.trackId;
|
|
578
|
-
track.clips[0] = __spreadProps(__spreadValues({}, track.clips[0]), { id: existingIds.clipId });
|
|
579
|
-
} else {
|
|
580
|
-
stableIds.set(index, { trackId: track.id, clipId: track.clips[0].id });
|
|
581
|
-
}
|
|
582
|
-
return track;
|
|
583
|
-
}
|
|
584
|
-
function useAudioTracks(configs, options = {}) {
|
|
585
|
-
const { immediate = false, progressive = false } = options;
|
|
586
|
-
const isImmediate = immediate || progressive;
|
|
587
|
-
const [loading, setLoading] = useState8(true);
|
|
588
|
-
const [error, setError] = useState8(null);
|
|
589
|
-
const [loadedCount, setLoadedCount] = useState8(0);
|
|
590
|
-
const totalCount = configs.length;
|
|
591
|
-
const [loadedBuffers, setLoadedBuffers] = useState8(/* @__PURE__ */ new Map());
|
|
592
|
-
const stableIdsRef = useRef8(/* @__PURE__ */ new Map());
|
|
593
|
-
const contextSampleRateRef = useRef8(48e3);
|
|
594
|
-
const derivedTracks = useMemo(() => {
|
|
595
|
-
if (!isImmediate) return null;
|
|
596
|
-
const result = [];
|
|
597
|
-
for (let i = 0; i < configs.length; i++) {
|
|
598
|
-
const track = buildTrackFromConfig(
|
|
599
|
-
configs[i],
|
|
600
|
-
i,
|
|
601
|
-
loadedBuffers.get(i),
|
|
602
|
-
stableIdsRef.current,
|
|
603
|
-
contextSampleRateRef.current
|
|
604
|
-
);
|
|
605
|
-
if (track) result.push(track);
|
|
606
|
-
}
|
|
607
|
-
return result;
|
|
608
|
-
}, [isImmediate, configs, loadedBuffers]);
|
|
609
|
-
const [tracks, setTracks] = useState8(derivedTracks != null ? derivedTracks : []);
|
|
610
|
-
const prevDerivedRef = useRef8(derivedTracks);
|
|
611
|
-
if (derivedTracks !== prevDerivedRef.current) {
|
|
612
|
-
prevDerivedRef.current = derivedTracks;
|
|
613
|
-
if (derivedTracks) setTracks(derivedTracks);
|
|
614
|
-
}
|
|
615
|
-
useEffect(() => {
|
|
616
|
-
if (configs.length === 0) {
|
|
617
|
-
setTracks([]);
|
|
618
|
-
setLoading(false);
|
|
619
|
-
setLoadedCount(0);
|
|
620
|
-
return;
|
|
621
|
-
}
|
|
622
|
-
let cancelled = false;
|
|
623
|
-
const abortController = new AbortController();
|
|
624
|
-
const loadTracks = () => __async(null, null, function* () {
|
|
625
|
-
try {
|
|
626
|
-
setLoading(true);
|
|
627
|
-
setError(null);
|
|
628
|
-
setLoadedCount(0);
|
|
629
|
-
if (isImmediate) {
|
|
630
|
-
setLoadedBuffers(/* @__PURE__ */ new Map());
|
|
631
|
-
}
|
|
632
|
-
const audioContext = Tone.getContext().rawContext;
|
|
633
|
-
contextSampleRateRef.current = audioContext.sampleRate;
|
|
634
|
-
const loadPromises = configs.map((config, index) => __async(null, null, function* () {
|
|
635
|
-
if (config.audioBuffer) {
|
|
636
|
-
if (isImmediate && !cancelled) {
|
|
637
|
-
setLoadedBuffers((prev) => {
|
|
638
|
-
const next = new Map(prev);
|
|
639
|
-
next.set(index, config.audioBuffer);
|
|
640
|
-
return next;
|
|
641
|
-
});
|
|
642
|
-
setLoadedCount((prev) => prev + 1);
|
|
643
|
-
return;
|
|
644
|
-
}
|
|
645
|
-
return buildTrackFromConfig(
|
|
646
|
-
config,
|
|
647
|
-
index,
|
|
648
|
-
config.audioBuffer,
|
|
649
|
-
stableIdsRef.current,
|
|
650
|
-
audioContext.sampleRate
|
|
651
|
-
);
|
|
652
|
-
}
|
|
653
|
-
if (!config.src && config.waveformData) {
|
|
654
|
-
if (isImmediate && !cancelled) {
|
|
655
|
-
setLoadedCount((prev) => prev + 1);
|
|
656
|
-
return;
|
|
657
|
-
}
|
|
658
|
-
return buildTrackFromConfig(
|
|
659
|
-
config,
|
|
660
|
-
index,
|
|
661
|
-
void 0,
|
|
662
|
-
stableIdsRef.current,
|
|
663
|
-
audioContext.sampleRate
|
|
664
|
-
);
|
|
665
|
-
}
|
|
666
|
-
if (!config.src) {
|
|
667
|
-
throw new Error(`Track ${index + 1}: Must provide src, audioBuffer, or waveformData`);
|
|
668
|
-
}
|
|
669
|
-
const response = yield fetch(config.src, { signal: abortController.signal });
|
|
670
|
-
if (!response.ok) {
|
|
671
|
-
throw new Error(`Failed to fetch ${config.src}: ${response.statusText}`);
|
|
672
|
-
}
|
|
673
|
-
const arrayBuffer = yield response.arrayBuffer();
|
|
674
|
-
const audioBuffer = yield audioContext.decodeAudioData(arrayBuffer);
|
|
675
|
-
if (!audioBuffer || !audioBuffer.sampleRate || !audioBuffer.duration) {
|
|
676
|
-
throw new Error(`Invalid audio buffer for ${config.src}`);
|
|
677
|
-
}
|
|
678
|
-
if (isImmediate && !cancelled) {
|
|
679
|
-
setLoadedBuffers((prev) => {
|
|
680
|
-
const next = new Map(prev);
|
|
681
|
-
next.set(index, audioBuffer);
|
|
682
|
-
return next;
|
|
683
|
-
});
|
|
684
|
-
setLoadedCount((prev) => prev + 1);
|
|
685
|
-
return;
|
|
686
|
-
}
|
|
687
|
-
return buildTrackFromConfig(
|
|
688
|
-
config,
|
|
689
|
-
index,
|
|
690
|
-
audioBuffer,
|
|
691
|
-
stableIdsRef.current,
|
|
692
|
-
audioContext.sampleRate
|
|
693
|
-
);
|
|
694
|
-
}));
|
|
695
|
-
const loadedTracks = yield Promise.all(loadPromises);
|
|
696
|
-
if (!cancelled) {
|
|
697
|
-
if (!isImmediate) {
|
|
698
|
-
const validTracks = loadedTracks.filter((t) => t != null);
|
|
699
|
-
setTracks(validTracks);
|
|
700
|
-
setLoadedCount(validTracks.length);
|
|
701
|
-
}
|
|
702
|
-
setLoading(false);
|
|
703
|
-
}
|
|
704
|
-
} catch (err) {
|
|
705
|
-
if (!cancelled) {
|
|
706
|
-
const errorMessage = err instanceof Error ? err.message : "Unknown error loading audio";
|
|
707
|
-
setError(errorMessage);
|
|
708
|
-
setLoading(false);
|
|
709
|
-
console.error(`[waveform-playlist] Error loading audio tracks: ${errorMessage}`);
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
});
|
|
713
|
-
loadTracks();
|
|
714
|
-
return () => {
|
|
715
|
-
cancelled = true;
|
|
716
|
-
abortController.abort();
|
|
717
|
-
};
|
|
718
|
-
}, [configs, isImmediate]);
|
|
719
|
-
return { tracks, loading, error, loadedCount, totalCount };
|
|
720
|
-
}
|
|
721
|
-
|
|
722
528
|
// src/hooks/useClipDragHandlers.ts
|
|
723
529
|
import React from "react";
|
|
724
530
|
|
|
@@ -955,13 +761,13 @@ function useClipDragHandlers({
|
|
|
955
761
|
|
|
956
762
|
// src/hooks/useAnnotationDragHandlers.ts
|
|
957
763
|
import React2 from "react";
|
|
958
|
-
import { getGlobalAudioContext } from "@waveform-playlist/playout";
|
|
959
764
|
var LINK_THRESHOLD = 0.01;
|
|
960
765
|
function useAnnotationDragHandlers({
|
|
961
766
|
annotations,
|
|
962
767
|
onAnnotationsChange,
|
|
963
768
|
samplesPerPixel,
|
|
964
|
-
|
|
769
|
+
// Default mirrors the engine default; the providers always pass the real rate from context (#510).
|
|
770
|
+
sampleRate = 48e3,
|
|
965
771
|
duration,
|
|
966
772
|
linkEndpoints
|
|
967
773
|
}) {
|
|
@@ -1119,7 +925,7 @@ function updateAnnotationBoundaries({
|
|
|
1119
925
|
}
|
|
1120
926
|
|
|
1121
927
|
// src/hooks/useDragSensors.ts
|
|
1122
|
-
import { useMemo
|
|
928
|
+
import { useMemo } from "react";
|
|
1123
929
|
import { PointerSensor, PointerActivationConstraints } from "@dnd-kit/dom";
|
|
1124
930
|
function useDragSensors(options = {}) {
|
|
1125
931
|
const {
|
|
@@ -1128,7 +934,7 @@ function useDragSensors(options = {}) {
|
|
|
1128
934
|
touchTolerance = 5,
|
|
1129
935
|
mouseDistance = 1
|
|
1130
936
|
} = options;
|
|
1131
|
-
return
|
|
937
|
+
return useMemo(() => {
|
|
1132
938
|
if (touchOptimized) {
|
|
1133
939
|
return [
|
|
1134
940
|
PointerSensor.configure({
|
|
@@ -1157,14 +963,14 @@ function useDragSensors(options = {}) {
|
|
|
1157
963
|
}
|
|
1158
964
|
|
|
1159
965
|
// src/hooks/useClipSplitting.ts
|
|
1160
|
-
import { useCallback as
|
|
966
|
+
import { useCallback as useCallback7 } from "react";
|
|
1161
967
|
import { calculateSplitPoint, canSplitAt } from "@waveform-playlist/engine";
|
|
1162
968
|
var useClipSplitting = (options) => {
|
|
1163
969
|
const { tracks, engineRef } = options;
|
|
1164
970
|
const { sampleRate } = usePlaylistData();
|
|
1165
971
|
const { currentTimeRef } = usePlaybackAnimation();
|
|
1166
972
|
const { selectedTrackId } = usePlaylistState();
|
|
1167
|
-
const splitClipAt =
|
|
973
|
+
const splitClipAt = useCallback7(
|
|
1168
974
|
(trackIndex, clipIndex, splitTime) => {
|
|
1169
975
|
const { samplesPerPixel } = options;
|
|
1170
976
|
const track = tracks[trackIndex];
|
|
@@ -1188,7 +994,7 @@ var useClipSplitting = (options) => {
|
|
|
1188
994
|
},
|
|
1189
995
|
[tracks, options, engineRef, sampleRate]
|
|
1190
996
|
);
|
|
1191
|
-
const splitClipAtPlayhead =
|
|
997
|
+
const splitClipAtPlayhead = useCallback7(() => {
|
|
1192
998
|
var _a;
|
|
1193
999
|
if (!selectedTrackId) {
|
|
1194
1000
|
console.warn("[waveform-playlist] No track selected \u2014 click a clip to select a track first");
|
|
@@ -1219,16 +1025,16 @@ var useClipSplitting = (options) => {
|
|
|
1219
1025
|
};
|
|
1220
1026
|
|
|
1221
1027
|
// src/hooks/useKeyboardShortcuts.ts
|
|
1222
|
-
import { useEffect
|
|
1028
|
+
import { useEffect, useCallback as useCallback8 } from "react";
|
|
1223
1029
|
import { handleKeyboardEvent } from "@waveform-playlist/core";
|
|
1224
1030
|
import { handleKeyboardEvent as handleKeyboardEvent2, getShortcutLabel } from "@waveform-playlist/core";
|
|
1225
1031
|
var useKeyboardShortcuts = (options) => {
|
|
1226
1032
|
const { shortcuts, enabled = true } = options;
|
|
1227
|
-
const handleKeyDown =
|
|
1033
|
+
const handleKeyDown = useCallback8(
|
|
1228
1034
|
(event) => handleKeyboardEvent(event, shortcuts, enabled),
|
|
1229
1035
|
[shortcuts, enabled]
|
|
1230
1036
|
);
|
|
1231
|
-
|
|
1037
|
+
useEffect(() => {
|
|
1232
1038
|
if (!enabled) return;
|
|
1233
1039
|
window.addEventListener("keydown", handleKeyDown);
|
|
1234
1040
|
return () => {
|
|
@@ -1238,22 +1044,22 @@ var useKeyboardShortcuts = (options) => {
|
|
|
1238
1044
|
};
|
|
1239
1045
|
|
|
1240
1046
|
// src/hooks/usePlaybackShortcuts.ts
|
|
1241
|
-
import { useCallback as
|
|
1047
|
+
import { useCallback as useCallback9 } from "react";
|
|
1242
1048
|
var usePlaybackShortcuts = (options = {}) => {
|
|
1243
1049
|
const { enabled = true, additionalShortcuts = [], shortcuts: overrideShortcuts } = options;
|
|
1244
1050
|
const { isPlaying } = usePlaybackAnimation();
|
|
1245
1051
|
const { setCurrentTime, play, pause, stop } = usePlaylistControls();
|
|
1246
|
-
const togglePlayPause =
|
|
1052
|
+
const togglePlayPause = useCallback9(() => {
|
|
1247
1053
|
if (isPlaying) {
|
|
1248
1054
|
pause();
|
|
1249
1055
|
} else {
|
|
1250
1056
|
play();
|
|
1251
1057
|
}
|
|
1252
1058
|
}, [isPlaying, play, pause]);
|
|
1253
|
-
const stopPlayback =
|
|
1059
|
+
const stopPlayback = useCallback9(() => {
|
|
1254
1060
|
stop();
|
|
1255
1061
|
}, [stop]);
|
|
1256
|
-
const rewindToStart =
|
|
1062
|
+
const rewindToStart = useCallback9(() => {
|
|
1257
1063
|
setCurrentTime(0);
|
|
1258
1064
|
if (isPlaying) {
|
|
1259
1065
|
play(0);
|
|
@@ -1293,7 +1099,7 @@ var usePlaybackShortcuts = (options = {}) => {
|
|
|
1293
1099
|
};
|
|
1294
1100
|
|
|
1295
1101
|
// src/hooks/useAnnotationKeyboardControls.ts
|
|
1296
|
-
import { useCallback as
|
|
1102
|
+
import { useCallback as useCallback10, useMemo as useMemo2, useEffect as useEffect2 } from "react";
|
|
1297
1103
|
var LINK_THRESHOLD2 = 0.01;
|
|
1298
1104
|
var TIME_DELTA = 0.01;
|
|
1299
1105
|
function useAnnotationKeyboardControls({
|
|
@@ -1313,11 +1119,11 @@ function useAnnotationKeyboardControls({
|
|
|
1313
1119
|
const playlistData = usePlaylistDataOptional();
|
|
1314
1120
|
const samplesPerPixel = samplesPerPixelProp != null ? samplesPerPixelProp : playlistData == null ? void 0 : playlistData.samplesPerPixel;
|
|
1315
1121
|
const sampleRate = sampleRateProp != null ? sampleRateProp : playlistData == null ? void 0 : playlistData.sampleRate;
|
|
1316
|
-
const activeIndex =
|
|
1122
|
+
const activeIndex = useMemo2(() => {
|
|
1317
1123
|
if (!activeAnnotationId) return -1;
|
|
1318
1124
|
return annotations.findIndex((a) => a.id === activeAnnotationId);
|
|
1319
1125
|
}, [annotations, activeAnnotationId]);
|
|
1320
|
-
const scrollToAnnotation =
|
|
1126
|
+
const scrollToAnnotation = useCallback10(
|
|
1321
1127
|
(annotationId) => {
|
|
1322
1128
|
if (!(scrollContainerRef == null ? void 0 : scrollContainerRef.current) || !samplesPerPixel || !sampleRate) return;
|
|
1323
1129
|
const annotation = annotations.find((a) => a.id === annotationId);
|
|
@@ -1340,12 +1146,12 @@ function useAnnotationKeyboardControls({
|
|
|
1340
1146
|
},
|
|
1341
1147
|
[annotations, scrollContainerRef, samplesPerPixel, sampleRate]
|
|
1342
1148
|
);
|
|
1343
|
-
|
|
1149
|
+
useEffect2(() => {
|
|
1344
1150
|
if (activeAnnotationId && (scrollContainerRef == null ? void 0 : scrollContainerRef.current) && samplesPerPixel && sampleRate) {
|
|
1345
1151
|
scrollToAnnotation(activeAnnotationId);
|
|
1346
1152
|
}
|
|
1347
1153
|
}, [activeAnnotationId, scrollToAnnotation, scrollContainerRef, samplesPerPixel, sampleRate]);
|
|
1348
|
-
const moveStartBoundary =
|
|
1154
|
+
const moveStartBoundary = useCallback10(
|
|
1349
1155
|
(delta) => {
|
|
1350
1156
|
if (activeIndex < 0) return;
|
|
1351
1157
|
const annotation = annotations[activeIndex];
|
|
@@ -1374,7 +1180,7 @@ function useAnnotationKeyboardControls({
|
|
|
1374
1180
|
},
|
|
1375
1181
|
[annotations, activeIndex, linkEndpoints, onAnnotationsChange]
|
|
1376
1182
|
);
|
|
1377
|
-
const moveEndBoundary =
|
|
1183
|
+
const moveEndBoundary = useCallback10(
|
|
1378
1184
|
(delta) => {
|
|
1379
1185
|
if (activeIndex < 0) return;
|
|
1380
1186
|
const annotation = annotations[activeIndex];
|
|
@@ -1434,7 +1240,7 @@ function useAnnotationKeyboardControls({
|
|
|
1434
1240
|
},
|
|
1435
1241
|
[annotations, activeIndex, duration, linkEndpoints, onAnnotationsChange]
|
|
1436
1242
|
);
|
|
1437
|
-
const selectPrevious =
|
|
1243
|
+
const selectPrevious = useCallback10(() => {
|
|
1438
1244
|
if (!onActiveAnnotationChange || annotations.length === 0) return;
|
|
1439
1245
|
if (activeIndex <= 0) {
|
|
1440
1246
|
onActiveAnnotationChange(annotations[annotations.length - 1].id);
|
|
@@ -1442,7 +1248,7 @@ function useAnnotationKeyboardControls({
|
|
|
1442
1248
|
onActiveAnnotationChange(annotations[activeIndex - 1].id);
|
|
1443
1249
|
}
|
|
1444
1250
|
}, [annotations, activeIndex, onActiveAnnotationChange]);
|
|
1445
|
-
const selectNext =
|
|
1251
|
+
const selectNext = useCallback10(() => {
|
|
1446
1252
|
if (!onActiveAnnotationChange || annotations.length === 0) return;
|
|
1447
1253
|
if (activeIndex < 0 || activeIndex >= annotations.length - 1) {
|
|
1448
1254
|
onActiveAnnotationChange(annotations[0].id);
|
|
@@ -1450,25 +1256,25 @@ function useAnnotationKeyboardControls({
|
|
|
1450
1256
|
onActiveAnnotationChange(annotations[activeIndex + 1].id);
|
|
1451
1257
|
}
|
|
1452
1258
|
}, [annotations, activeIndex, onActiveAnnotationChange]);
|
|
1453
|
-
const selectFirst =
|
|
1259
|
+
const selectFirst = useCallback10(() => {
|
|
1454
1260
|
if (!onActiveAnnotationChange || annotations.length === 0) return;
|
|
1455
1261
|
onActiveAnnotationChange(annotations[0].id);
|
|
1456
1262
|
}, [annotations, onActiveAnnotationChange]);
|
|
1457
|
-
const selectLast =
|
|
1263
|
+
const selectLast = useCallback10(() => {
|
|
1458
1264
|
if (!onActiveAnnotationChange || annotations.length === 0) return;
|
|
1459
1265
|
onActiveAnnotationChange(annotations[annotations.length - 1].id);
|
|
1460
1266
|
}, [annotations, onActiveAnnotationChange]);
|
|
1461
|
-
const clearSelection =
|
|
1267
|
+
const clearSelection = useCallback10(() => {
|
|
1462
1268
|
if (!onActiveAnnotationChange) return;
|
|
1463
1269
|
onActiveAnnotationChange(null);
|
|
1464
1270
|
}, [onActiveAnnotationChange]);
|
|
1465
|
-
const playActiveAnnotation =
|
|
1271
|
+
const playActiveAnnotation = useCallback10(() => {
|
|
1466
1272
|
if (activeIndex < 0 || !onPlay) return;
|
|
1467
1273
|
const annotation = annotations[activeIndex];
|
|
1468
1274
|
const playDuration = !continuousPlay ? annotation.end - annotation.start : void 0;
|
|
1469
1275
|
onPlay(annotation.start, playDuration);
|
|
1470
1276
|
}, [annotations, activeIndex, continuousPlay, onPlay]);
|
|
1471
|
-
const activeAnnotationShortcuts =
|
|
1277
|
+
const activeAnnotationShortcuts = useMemo2(
|
|
1472
1278
|
() => [
|
|
1473
1279
|
{
|
|
1474
1280
|
key: "[",
|
|
@@ -1505,7 +1311,7 @@ function useAnnotationKeyboardControls({
|
|
|
1505
1311
|
],
|
|
1506
1312
|
[moveStartBoundary, moveEndBoundary, playActiveAnnotation]
|
|
1507
1313
|
);
|
|
1508
|
-
const navigationShortcuts =
|
|
1314
|
+
const navigationShortcuts = useMemo2(
|
|
1509
1315
|
() => [
|
|
1510
1316
|
{
|
|
1511
1317
|
key: "ArrowUp",
|
|
@@ -1532,1452 +1338,65 @@ function useAnnotationKeyboardControls({
|
|
|
1532
1338
|
preventDefault: true
|
|
1533
1339
|
},
|
|
1534
1340
|
{
|
|
1535
|
-
key: "Home",
|
|
1536
|
-
action: selectFirst,
|
|
1537
|
-
description: "Select first annotation",
|
|
1538
|
-
preventDefault: true
|
|
1539
|
-
},
|
|
1540
|
-
{
|
|
1541
|
-
key: "End",
|
|
1542
|
-
action: selectLast,
|
|
1543
|
-
description: "Select last annotation",
|
|
1544
|
-
preventDefault: true
|
|
1545
|
-
},
|
|
1546
|
-
{
|
|
1547
|
-
key: "Escape",
|
|
1548
|
-
action: clearSelection,
|
|
1549
|
-
description: "Deselect annotation",
|
|
1550
|
-
preventDefault: true
|
|
1551
|
-
}
|
|
1552
|
-
],
|
|
1553
|
-
[selectPrevious, selectNext, selectFirst, selectLast, clearSelection]
|
|
1554
|
-
);
|
|
1555
|
-
useKeyboardShortcuts({
|
|
1556
|
-
shortcuts: activeAnnotationShortcuts,
|
|
1557
|
-
enabled: enabled && activeIndex >= 0
|
|
1558
|
-
});
|
|
1559
|
-
useKeyboardShortcuts({
|
|
1560
|
-
shortcuts: navigationShortcuts,
|
|
1561
|
-
enabled: enabled && annotations.length > 0 && !!onActiveAnnotationChange
|
|
1562
|
-
});
|
|
1563
|
-
return {
|
|
1564
|
-
moveStartBoundary,
|
|
1565
|
-
moveEndBoundary,
|
|
1566
|
-
selectPrevious,
|
|
1567
|
-
selectNext,
|
|
1568
|
-
selectFirst,
|
|
1569
|
-
selectLast,
|
|
1570
|
-
clearSelection,
|
|
1571
|
-
scrollToAnnotation,
|
|
1572
|
-
playActiveAnnotation
|
|
1573
|
-
};
|
|
1574
|
-
}
|
|
1575
|
-
|
|
1576
|
-
// src/hooks/useDynamicEffects.ts
|
|
1577
|
-
import { useState as useState9, useCallback as useCallback12, useRef as useRef9, useEffect as useEffect4 } from "react";
|
|
1578
|
-
|
|
1579
|
-
// src/effects/effectDefinitions.ts
|
|
1580
|
-
var effectDefinitions = [
|
|
1581
|
-
// === REVERB EFFECTS ===
|
|
1582
|
-
{
|
|
1583
|
-
id: "reverb",
|
|
1584
|
-
name: "Reverb",
|
|
1585
|
-
category: "reverb",
|
|
1586
|
-
description: "Simple convolution reverb with adjustable decay time",
|
|
1587
|
-
parameters: [
|
|
1588
|
-
{
|
|
1589
|
-
name: "decay",
|
|
1590
|
-
label: "Decay",
|
|
1591
|
-
type: "number",
|
|
1592
|
-
min: 0.1,
|
|
1593
|
-
max: 10,
|
|
1594
|
-
step: 0.1,
|
|
1595
|
-
default: 1.5,
|
|
1596
|
-
unit: "s"
|
|
1597
|
-
},
|
|
1598
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1599
|
-
]
|
|
1600
|
-
},
|
|
1601
|
-
{
|
|
1602
|
-
id: "freeverb",
|
|
1603
|
-
name: "Freeverb",
|
|
1604
|
-
category: "reverb",
|
|
1605
|
-
description: "Classic Schroeder/Moorer reverb with room size and dampening",
|
|
1606
|
-
parameters: [
|
|
1607
|
-
{
|
|
1608
|
-
name: "roomSize",
|
|
1609
|
-
label: "Room Size",
|
|
1610
|
-
type: "number",
|
|
1611
|
-
min: 0,
|
|
1612
|
-
max: 1,
|
|
1613
|
-
step: 0.01,
|
|
1614
|
-
default: 0.7
|
|
1615
|
-
},
|
|
1616
|
-
{
|
|
1617
|
-
name: "dampening",
|
|
1618
|
-
label: "Dampening",
|
|
1619
|
-
type: "number",
|
|
1620
|
-
min: 0,
|
|
1621
|
-
max: 1e4,
|
|
1622
|
-
step: 100,
|
|
1623
|
-
default: 3e3,
|
|
1624
|
-
unit: "Hz"
|
|
1625
|
-
},
|
|
1626
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1627
|
-
]
|
|
1628
|
-
},
|
|
1629
|
-
{
|
|
1630
|
-
id: "jcReverb",
|
|
1631
|
-
name: "JC Reverb",
|
|
1632
|
-
category: "reverb",
|
|
1633
|
-
description: "Attempt at Roland JC-120 chorus reverb emulation",
|
|
1634
|
-
parameters: [
|
|
1635
|
-
{
|
|
1636
|
-
name: "roomSize",
|
|
1637
|
-
label: "Room Size",
|
|
1638
|
-
type: "number",
|
|
1639
|
-
min: 0,
|
|
1640
|
-
max: 1,
|
|
1641
|
-
step: 0.01,
|
|
1642
|
-
default: 0.5
|
|
1643
|
-
},
|
|
1644
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1645
|
-
]
|
|
1646
|
-
},
|
|
1647
|
-
// === DELAY EFFECTS ===
|
|
1648
|
-
{
|
|
1649
|
-
id: "feedbackDelay",
|
|
1650
|
-
name: "Feedback Delay",
|
|
1651
|
-
category: "delay",
|
|
1652
|
-
description: "Delay line with feedback for echo effects",
|
|
1653
|
-
parameters: [
|
|
1654
|
-
{
|
|
1655
|
-
name: "delayTime",
|
|
1656
|
-
label: "Delay Time",
|
|
1657
|
-
type: "number",
|
|
1658
|
-
min: 0,
|
|
1659
|
-
max: 1,
|
|
1660
|
-
step: 0.01,
|
|
1661
|
-
default: 0.25,
|
|
1662
|
-
unit: "s"
|
|
1663
|
-
},
|
|
1664
|
-
{
|
|
1665
|
-
name: "feedback",
|
|
1666
|
-
label: "Feedback",
|
|
1667
|
-
type: "number",
|
|
1668
|
-
min: 0,
|
|
1669
|
-
max: 0.95,
|
|
1670
|
-
step: 0.01,
|
|
1671
|
-
default: 0.5
|
|
1672
|
-
},
|
|
1673
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1674
|
-
]
|
|
1675
|
-
},
|
|
1676
|
-
{
|
|
1677
|
-
id: "pingPongDelay",
|
|
1678
|
-
name: "Ping Pong Delay",
|
|
1679
|
-
category: "delay",
|
|
1680
|
-
description: "Stereo delay bouncing between left and right channels",
|
|
1681
|
-
parameters: [
|
|
1682
|
-
{
|
|
1683
|
-
name: "delayTime",
|
|
1684
|
-
label: "Delay Time",
|
|
1685
|
-
type: "number",
|
|
1686
|
-
min: 0,
|
|
1687
|
-
max: 1,
|
|
1688
|
-
step: 0.01,
|
|
1689
|
-
default: 0.25,
|
|
1690
|
-
unit: "s"
|
|
1691
|
-
},
|
|
1692
|
-
{
|
|
1693
|
-
name: "feedback",
|
|
1694
|
-
label: "Feedback",
|
|
1695
|
-
type: "number",
|
|
1696
|
-
min: 0,
|
|
1697
|
-
max: 0.95,
|
|
1698
|
-
step: 0.01,
|
|
1699
|
-
default: 0.5
|
|
1700
|
-
},
|
|
1701
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1702
|
-
]
|
|
1703
|
-
},
|
|
1704
|
-
// === MODULATION EFFECTS ===
|
|
1705
|
-
{
|
|
1706
|
-
id: "chorus",
|
|
1707
|
-
name: "Chorus",
|
|
1708
|
-
category: "modulation",
|
|
1709
|
-
description: "Creates thickness by layering detuned copies of the signal",
|
|
1710
|
-
parameters: [
|
|
1711
|
-
{
|
|
1712
|
-
name: "frequency",
|
|
1713
|
-
label: "Rate",
|
|
1714
|
-
type: "number",
|
|
1715
|
-
min: 0.1,
|
|
1716
|
-
max: 10,
|
|
1717
|
-
step: 0.1,
|
|
1718
|
-
default: 1.5,
|
|
1719
|
-
unit: "Hz"
|
|
1720
|
-
},
|
|
1721
|
-
{
|
|
1722
|
-
name: "delayTime",
|
|
1723
|
-
label: "Delay",
|
|
1724
|
-
type: "number",
|
|
1725
|
-
min: 0,
|
|
1726
|
-
max: 20,
|
|
1727
|
-
step: 0.5,
|
|
1728
|
-
default: 3.5,
|
|
1729
|
-
unit: "ms"
|
|
1730
|
-
},
|
|
1731
|
-
{ name: "depth", label: "Depth", type: "number", min: 0, max: 1, step: 0.01, default: 0.7 },
|
|
1732
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1733
|
-
]
|
|
1734
|
-
},
|
|
1735
|
-
{
|
|
1736
|
-
id: "phaser",
|
|
1737
|
-
name: "Phaser",
|
|
1738
|
-
category: "modulation",
|
|
1739
|
-
description: "Classic phaser effect using allpass filters",
|
|
1740
|
-
parameters: [
|
|
1741
|
-
{
|
|
1742
|
-
name: "frequency",
|
|
1743
|
-
label: "Rate",
|
|
1744
|
-
type: "number",
|
|
1745
|
-
min: 0.1,
|
|
1746
|
-
max: 10,
|
|
1747
|
-
step: 0.1,
|
|
1748
|
-
default: 0.5,
|
|
1749
|
-
unit: "Hz"
|
|
1750
|
-
},
|
|
1751
|
-
{ name: "octaves", label: "Octaves", type: "number", min: 1, max: 6, step: 1, default: 3 },
|
|
1752
|
-
{
|
|
1753
|
-
name: "baseFrequency",
|
|
1754
|
-
label: "Base Freq",
|
|
1755
|
-
type: "number",
|
|
1756
|
-
min: 100,
|
|
1757
|
-
max: 2e3,
|
|
1758
|
-
step: 10,
|
|
1759
|
-
default: 350,
|
|
1760
|
-
unit: "Hz"
|
|
1761
|
-
},
|
|
1762
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1763
|
-
]
|
|
1764
|
-
},
|
|
1765
|
-
{
|
|
1766
|
-
id: "tremolo",
|
|
1767
|
-
name: "Tremolo",
|
|
1768
|
-
category: "modulation",
|
|
1769
|
-
description: "Rhythmic volume modulation",
|
|
1770
|
-
parameters: [
|
|
1771
|
-
{
|
|
1772
|
-
name: "frequency",
|
|
1773
|
-
label: "Rate",
|
|
1774
|
-
type: "number",
|
|
1775
|
-
min: 0.1,
|
|
1776
|
-
max: 20,
|
|
1777
|
-
step: 0.1,
|
|
1778
|
-
default: 4,
|
|
1779
|
-
unit: "Hz"
|
|
1780
|
-
},
|
|
1781
|
-
{ name: "depth", label: "Depth", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 },
|
|
1782
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1783
|
-
]
|
|
1784
|
-
},
|
|
1785
|
-
{
|
|
1786
|
-
id: "vibrato",
|
|
1787
|
-
name: "Vibrato",
|
|
1788
|
-
category: "modulation",
|
|
1789
|
-
description: "Pitch modulation effect",
|
|
1790
|
-
parameters: [
|
|
1791
|
-
{
|
|
1792
|
-
name: "frequency",
|
|
1793
|
-
label: "Rate",
|
|
1794
|
-
type: "number",
|
|
1795
|
-
min: 0.1,
|
|
1796
|
-
max: 20,
|
|
1797
|
-
step: 0.1,
|
|
1798
|
-
default: 5,
|
|
1799
|
-
unit: "Hz"
|
|
1800
|
-
},
|
|
1801
|
-
{ name: "depth", label: "Depth", type: "number", min: 0, max: 1, step: 0.01, default: 0.1 },
|
|
1802
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1803
|
-
]
|
|
1804
|
-
},
|
|
1805
|
-
{
|
|
1806
|
-
id: "autoPanner",
|
|
1807
|
-
name: "Auto Panner",
|
|
1808
|
-
category: "modulation",
|
|
1809
|
-
description: "Automatic left-right panning",
|
|
1810
|
-
parameters: [
|
|
1811
|
-
{
|
|
1812
|
-
name: "frequency",
|
|
1813
|
-
label: "Rate",
|
|
1814
|
-
type: "number",
|
|
1815
|
-
min: 0.1,
|
|
1816
|
-
max: 10,
|
|
1817
|
-
step: 0.1,
|
|
1818
|
-
default: 1,
|
|
1819
|
-
unit: "Hz"
|
|
1820
|
-
},
|
|
1821
|
-
{ name: "depth", label: "Depth", type: "number", min: 0, max: 1, step: 0.01, default: 1 },
|
|
1822
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1823
|
-
]
|
|
1824
|
-
},
|
|
1825
|
-
// === FILTER EFFECTS ===
|
|
1826
|
-
{
|
|
1827
|
-
id: "autoFilter",
|
|
1828
|
-
name: "Auto Filter",
|
|
1829
|
-
category: "filter",
|
|
1830
|
-
description: "Automated filter sweep with LFO",
|
|
1831
|
-
parameters: [
|
|
1832
|
-
{
|
|
1833
|
-
name: "frequency",
|
|
1834
|
-
label: "Rate",
|
|
1835
|
-
type: "number",
|
|
1836
|
-
min: 0.1,
|
|
1837
|
-
max: 10,
|
|
1838
|
-
step: 0.1,
|
|
1839
|
-
default: 1,
|
|
1840
|
-
unit: "Hz"
|
|
1841
|
-
},
|
|
1842
|
-
{
|
|
1843
|
-
name: "baseFrequency",
|
|
1844
|
-
label: "Base Freq",
|
|
1845
|
-
type: "number",
|
|
1846
|
-
min: 20,
|
|
1847
|
-
max: 2e3,
|
|
1848
|
-
step: 10,
|
|
1849
|
-
default: 200,
|
|
1850
|
-
unit: "Hz"
|
|
1851
|
-
},
|
|
1852
|
-
{
|
|
1853
|
-
name: "octaves",
|
|
1854
|
-
label: "Octaves",
|
|
1855
|
-
type: "number",
|
|
1856
|
-
min: 0.5,
|
|
1857
|
-
max: 8,
|
|
1858
|
-
step: 0.5,
|
|
1859
|
-
default: 2.6
|
|
1860
|
-
},
|
|
1861
|
-
{ name: "depth", label: "Depth", type: "number", min: 0, max: 1, step: 0.01, default: 1 },
|
|
1862
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1863
|
-
]
|
|
1864
|
-
},
|
|
1865
|
-
{
|
|
1866
|
-
id: "autoWah",
|
|
1867
|
-
name: "Auto Wah",
|
|
1868
|
-
category: "filter",
|
|
1869
|
-
description: "Envelope follower filter effect",
|
|
1870
|
-
parameters: [
|
|
1871
|
-
{
|
|
1872
|
-
name: "baseFrequency",
|
|
1873
|
-
label: "Base Freq",
|
|
1874
|
-
type: "number",
|
|
1875
|
-
min: 20,
|
|
1876
|
-
max: 500,
|
|
1877
|
-
step: 10,
|
|
1878
|
-
default: 100,
|
|
1879
|
-
unit: "Hz"
|
|
1880
|
-
},
|
|
1881
|
-
{ name: "octaves", label: "Octaves", type: "number", min: 1, max: 8, step: 1, default: 6 },
|
|
1882
|
-
{
|
|
1883
|
-
name: "sensitivity",
|
|
1884
|
-
label: "Sensitivity",
|
|
1885
|
-
type: "number",
|
|
1886
|
-
min: -40,
|
|
1887
|
-
max: 0,
|
|
1888
|
-
step: 1,
|
|
1889
|
-
default: 0,
|
|
1890
|
-
unit: "dB"
|
|
1891
|
-
},
|
|
1892
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1893
|
-
]
|
|
1894
|
-
},
|
|
1895
|
-
{
|
|
1896
|
-
id: "eq3",
|
|
1897
|
-
name: "3-Band EQ",
|
|
1898
|
-
category: "filter",
|
|
1899
|
-
description: "Three band equalizer with low, mid, and high controls",
|
|
1900
|
-
parameters: [
|
|
1901
|
-
{
|
|
1902
|
-
name: "low",
|
|
1903
|
-
label: "Low",
|
|
1904
|
-
type: "number",
|
|
1905
|
-
min: -24,
|
|
1906
|
-
max: 24,
|
|
1907
|
-
step: 0.5,
|
|
1908
|
-
default: 0,
|
|
1909
|
-
unit: "dB"
|
|
1910
|
-
},
|
|
1911
|
-
{
|
|
1912
|
-
name: "mid",
|
|
1913
|
-
label: "Mid",
|
|
1914
|
-
type: "number",
|
|
1915
|
-
min: -24,
|
|
1916
|
-
max: 24,
|
|
1917
|
-
step: 0.5,
|
|
1918
|
-
default: 0,
|
|
1919
|
-
unit: "dB"
|
|
1920
|
-
},
|
|
1921
|
-
{
|
|
1922
|
-
name: "high",
|
|
1923
|
-
label: "High",
|
|
1924
|
-
type: "number",
|
|
1925
|
-
min: -24,
|
|
1926
|
-
max: 24,
|
|
1927
|
-
step: 0.5,
|
|
1928
|
-
default: 0,
|
|
1929
|
-
unit: "dB"
|
|
1930
|
-
},
|
|
1931
|
-
{
|
|
1932
|
-
name: "lowFrequency",
|
|
1933
|
-
label: "Low Freq",
|
|
1934
|
-
type: "number",
|
|
1935
|
-
min: 20,
|
|
1936
|
-
max: 500,
|
|
1937
|
-
step: 10,
|
|
1938
|
-
default: 400,
|
|
1939
|
-
unit: "Hz"
|
|
1940
|
-
},
|
|
1941
|
-
{
|
|
1942
|
-
name: "highFrequency",
|
|
1943
|
-
label: "High Freq",
|
|
1944
|
-
type: "number",
|
|
1945
|
-
min: 1e3,
|
|
1946
|
-
max: 1e4,
|
|
1947
|
-
step: 100,
|
|
1948
|
-
default: 2500,
|
|
1949
|
-
unit: "Hz"
|
|
1950
|
-
}
|
|
1951
|
-
]
|
|
1952
|
-
},
|
|
1953
|
-
// === DISTORTION EFFECTS ===
|
|
1954
|
-
{
|
|
1955
|
-
id: "distortion",
|
|
1956
|
-
name: "Distortion",
|
|
1957
|
-
category: "distortion",
|
|
1958
|
-
description: "Wave shaping distortion effect",
|
|
1959
|
-
parameters: [
|
|
1960
|
-
{
|
|
1961
|
-
name: "distortion",
|
|
1962
|
-
label: "Drive",
|
|
1963
|
-
type: "number",
|
|
1964
|
-
min: 0,
|
|
1965
|
-
max: 1,
|
|
1966
|
-
step: 0.01,
|
|
1967
|
-
default: 0.4
|
|
1968
|
-
},
|
|
1969
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1970
|
-
]
|
|
1971
|
-
},
|
|
1972
|
-
{
|
|
1973
|
-
id: "bitCrusher",
|
|
1974
|
-
name: "Bit Crusher",
|
|
1975
|
-
category: "distortion",
|
|
1976
|
-
description: "Reduces bit depth for lo-fi digital texture",
|
|
1977
|
-
parameters: [
|
|
1978
|
-
{ name: "bits", label: "Bits", type: "number", min: 1, max: 16, step: 1, default: 4 },
|
|
1979
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1980
|
-
]
|
|
1981
|
-
},
|
|
1982
|
-
{
|
|
1983
|
-
id: "chebyshev",
|
|
1984
|
-
name: "Chebyshev",
|
|
1985
|
-
category: "distortion",
|
|
1986
|
-
description: "Waveshaping distortion using Chebyshev polynomials",
|
|
1987
|
-
parameters: [
|
|
1988
|
-
{ name: "order", label: "Order", type: "number", min: 1, max: 100, step: 1, default: 50 },
|
|
1989
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1990
|
-
]
|
|
1991
|
-
},
|
|
1992
|
-
// === DYNAMICS EFFECTS ===
|
|
1993
|
-
{
|
|
1994
|
-
id: "compressor",
|
|
1995
|
-
name: "Compressor",
|
|
1996
|
-
category: "dynamics",
|
|
1997
|
-
description: "Dynamic range compressor",
|
|
1998
|
-
parameters: [
|
|
1999
|
-
{
|
|
2000
|
-
name: "threshold",
|
|
2001
|
-
label: "Threshold",
|
|
2002
|
-
type: "number",
|
|
2003
|
-
min: -60,
|
|
2004
|
-
max: 0,
|
|
2005
|
-
step: 1,
|
|
2006
|
-
default: -24,
|
|
2007
|
-
unit: "dB"
|
|
2008
|
-
},
|
|
2009
|
-
{ name: "ratio", label: "Ratio", type: "number", min: 1, max: 20, step: 0.5, default: 4 },
|
|
2010
|
-
{
|
|
2011
|
-
name: "attack",
|
|
2012
|
-
label: "Attack",
|
|
2013
|
-
type: "number",
|
|
2014
|
-
min: 0,
|
|
2015
|
-
max: 1,
|
|
2016
|
-
step: 1e-3,
|
|
2017
|
-
default: 3e-3,
|
|
2018
|
-
unit: "s"
|
|
2019
|
-
},
|
|
2020
|
-
{
|
|
2021
|
-
name: "release",
|
|
2022
|
-
label: "Release",
|
|
2023
|
-
type: "number",
|
|
2024
|
-
min: 0,
|
|
2025
|
-
max: 1,
|
|
2026
|
-
step: 0.01,
|
|
2027
|
-
default: 0.25,
|
|
2028
|
-
unit: "s"
|
|
2029
|
-
},
|
|
2030
|
-
{
|
|
2031
|
-
name: "knee",
|
|
2032
|
-
label: "Knee",
|
|
2033
|
-
type: "number",
|
|
2034
|
-
min: 0,
|
|
2035
|
-
max: 40,
|
|
2036
|
-
step: 1,
|
|
2037
|
-
default: 30,
|
|
2038
|
-
unit: "dB"
|
|
2039
|
-
}
|
|
2040
|
-
]
|
|
2041
|
-
},
|
|
2042
|
-
{
|
|
2043
|
-
id: "limiter",
|
|
2044
|
-
name: "Limiter",
|
|
2045
|
-
category: "dynamics",
|
|
2046
|
-
description: "Hard limiter to prevent clipping",
|
|
2047
|
-
parameters: [
|
|
2048
|
-
{
|
|
2049
|
-
name: "threshold",
|
|
2050
|
-
label: "Threshold",
|
|
2051
|
-
type: "number",
|
|
2052
|
-
min: -12,
|
|
2053
|
-
max: 0,
|
|
2054
|
-
step: 0.5,
|
|
2055
|
-
default: -6,
|
|
2056
|
-
unit: "dB"
|
|
2057
|
-
}
|
|
2058
|
-
]
|
|
2059
|
-
},
|
|
2060
|
-
{
|
|
2061
|
-
id: "gate",
|
|
2062
|
-
name: "Gate",
|
|
2063
|
-
category: "dynamics",
|
|
2064
|
-
description: "Noise gate to silence signal below threshold",
|
|
2065
|
-
parameters: [
|
|
2066
|
-
{
|
|
2067
|
-
name: "threshold",
|
|
2068
|
-
label: "Threshold",
|
|
2069
|
-
type: "number",
|
|
2070
|
-
min: -100,
|
|
2071
|
-
max: 0,
|
|
2072
|
-
step: 1,
|
|
2073
|
-
default: -40,
|
|
2074
|
-
unit: "dB"
|
|
2075
|
-
},
|
|
2076
|
-
{
|
|
2077
|
-
name: "attack",
|
|
2078
|
-
label: "Attack",
|
|
2079
|
-
type: "number",
|
|
2080
|
-
min: 0,
|
|
2081
|
-
max: 0.3,
|
|
2082
|
-
step: 1e-3,
|
|
2083
|
-
default: 1e-3,
|
|
2084
|
-
unit: "s"
|
|
2085
|
-
},
|
|
2086
|
-
{
|
|
2087
|
-
name: "release",
|
|
2088
|
-
label: "Release",
|
|
2089
|
-
type: "number",
|
|
2090
|
-
min: 0,
|
|
2091
|
-
max: 0.5,
|
|
2092
|
-
step: 0.01,
|
|
2093
|
-
default: 0.1,
|
|
2094
|
-
unit: "s"
|
|
2095
|
-
}
|
|
2096
|
-
]
|
|
2097
|
-
},
|
|
2098
|
-
// === SPATIAL EFFECTS ===
|
|
2099
|
-
{
|
|
2100
|
-
id: "stereoWidener",
|
|
2101
|
-
name: "Stereo Widener",
|
|
2102
|
-
category: "spatial",
|
|
2103
|
-
description: "Expands or narrows the stereo image",
|
|
2104
|
-
parameters: [
|
|
2105
|
-
{ name: "width", label: "Width", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
2106
|
-
]
|
|
2107
|
-
}
|
|
2108
|
-
];
|
|
2109
|
-
var getEffectDefinition = (id) => {
|
|
2110
|
-
return effectDefinitions.find((def) => def.id === id);
|
|
2111
|
-
};
|
|
2112
|
-
var getEffectsByCategory = (category) => {
|
|
2113
|
-
return effectDefinitions.filter((def) => def.category === category);
|
|
2114
|
-
};
|
|
2115
|
-
var effectCategories = [
|
|
2116
|
-
{ id: "reverb", name: "Reverb" },
|
|
2117
|
-
{ id: "delay", name: "Delay" },
|
|
2118
|
-
{ id: "modulation", name: "Modulation" },
|
|
2119
|
-
{ id: "filter", name: "Filter" },
|
|
2120
|
-
{ id: "distortion", name: "Distortion" },
|
|
2121
|
-
{ id: "dynamics", name: "Dynamics" },
|
|
2122
|
-
{ id: "spatial", name: "Spatial" }
|
|
2123
|
-
];
|
|
2124
|
-
|
|
2125
|
-
// src/effects/effectFactory.ts
|
|
2126
|
-
import {
|
|
2127
|
-
Reverb,
|
|
2128
|
-
Freeverb,
|
|
2129
|
-
JCReverb,
|
|
2130
|
-
FeedbackDelay,
|
|
2131
|
-
PingPongDelay,
|
|
2132
|
-
Chorus,
|
|
2133
|
-
Phaser,
|
|
2134
|
-
Tremolo,
|
|
2135
|
-
Vibrato,
|
|
2136
|
-
AutoPanner,
|
|
2137
|
-
AutoFilter,
|
|
2138
|
-
AutoWah,
|
|
2139
|
-
EQ3,
|
|
2140
|
-
Distortion,
|
|
2141
|
-
BitCrusher,
|
|
2142
|
-
Chebyshev,
|
|
2143
|
-
Compressor,
|
|
2144
|
-
Limiter,
|
|
2145
|
-
Gate,
|
|
2146
|
-
StereoWidener
|
|
2147
|
-
} from "tone";
|
|
2148
|
-
function asEffectConstructor(ctor) {
|
|
2149
|
-
return ctor;
|
|
2150
|
-
}
|
|
2151
|
-
var effectConstructors = {
|
|
2152
|
-
reverb: asEffectConstructor(Reverb),
|
|
2153
|
-
freeverb: asEffectConstructor(Freeverb),
|
|
2154
|
-
jcReverb: asEffectConstructor(JCReverb),
|
|
2155
|
-
feedbackDelay: asEffectConstructor(FeedbackDelay),
|
|
2156
|
-
pingPongDelay: asEffectConstructor(PingPongDelay),
|
|
2157
|
-
chorus: asEffectConstructor(Chorus),
|
|
2158
|
-
phaser: asEffectConstructor(Phaser),
|
|
2159
|
-
tremolo: asEffectConstructor(Tremolo),
|
|
2160
|
-
vibrato: asEffectConstructor(Vibrato),
|
|
2161
|
-
autoPanner: asEffectConstructor(AutoPanner),
|
|
2162
|
-
autoFilter: asEffectConstructor(AutoFilter),
|
|
2163
|
-
autoWah: asEffectConstructor(AutoWah),
|
|
2164
|
-
eq3: asEffectConstructor(EQ3),
|
|
2165
|
-
distortion: asEffectConstructor(Distortion),
|
|
2166
|
-
bitCrusher: asEffectConstructor(BitCrusher),
|
|
2167
|
-
chebyshev: asEffectConstructor(Chebyshev),
|
|
2168
|
-
compressor: asEffectConstructor(Compressor),
|
|
2169
|
-
limiter: asEffectConstructor(Limiter),
|
|
2170
|
-
gate: asEffectConstructor(Gate),
|
|
2171
|
-
stereoWidener: asEffectConstructor(StereoWidener)
|
|
2172
|
-
};
|
|
2173
|
-
var instanceCounter = 0;
|
|
2174
|
-
var generateInstanceId = () => {
|
|
2175
|
-
return `effect_${Date.now()}_${++instanceCounter}`;
|
|
2176
|
-
};
|
|
2177
|
-
function createEffectInstance(definition, initialParams) {
|
|
2178
|
-
const Constructor = effectConstructors[definition.id];
|
|
2179
|
-
if (!Constructor) {
|
|
2180
|
-
throw new Error(`Unknown effect type: ${definition.id}`);
|
|
2181
|
-
}
|
|
2182
|
-
const options = {};
|
|
2183
|
-
definition.parameters.forEach((param) => {
|
|
2184
|
-
var _a;
|
|
2185
|
-
const value = (_a = initialParams == null ? void 0 : initialParams[param.name]) != null ? _a : param.default;
|
|
2186
|
-
options[param.name] = value;
|
|
2187
|
-
});
|
|
2188
|
-
const effect = new Constructor(options);
|
|
2189
|
-
const instanceId = generateInstanceId();
|
|
2190
|
-
const effectRecord = effect;
|
|
2191
|
-
return {
|
|
2192
|
-
effect,
|
|
2193
|
-
id: definition.id,
|
|
2194
|
-
instanceId,
|
|
2195
|
-
dispose() {
|
|
2196
|
-
try {
|
|
2197
|
-
effect.disconnect();
|
|
2198
|
-
effect.dispose();
|
|
2199
|
-
} catch (e) {
|
|
2200
|
-
console.warn(
|
|
2201
|
-
`[waveform-playlist] Error disposing effect "${definition.id}" (${instanceId}):`,
|
|
2202
|
-
e
|
|
2203
|
-
);
|
|
2204
|
-
}
|
|
2205
|
-
},
|
|
2206
|
-
setParameter(name, value) {
|
|
2207
|
-
const prop = effectRecord[name];
|
|
2208
|
-
if (name === "wet") {
|
|
2209
|
-
const wetProp = effectRecord["wet"];
|
|
2210
|
-
if (wetProp && typeof wetProp === "object" && "value" in wetProp) {
|
|
2211
|
-
wetProp.value = value;
|
|
2212
|
-
return;
|
|
2213
|
-
}
|
|
2214
|
-
}
|
|
2215
|
-
if (prop !== void 0) {
|
|
2216
|
-
if (prop && typeof prop === "object" && "value" in prop) {
|
|
2217
|
-
prop.value = value;
|
|
2218
|
-
} else {
|
|
2219
|
-
effectRecord[name] = value;
|
|
2220
|
-
}
|
|
2221
|
-
}
|
|
2222
|
-
},
|
|
2223
|
-
getParameter(name) {
|
|
2224
|
-
if (name === "wet") {
|
|
2225
|
-
const wetProp = effectRecord["wet"];
|
|
2226
|
-
if (wetProp && typeof wetProp === "object" && "value" in wetProp) {
|
|
2227
|
-
return wetProp.value;
|
|
2228
|
-
}
|
|
2229
|
-
}
|
|
2230
|
-
const prop = effectRecord[name];
|
|
2231
|
-
if (prop !== void 0) {
|
|
2232
|
-
if (prop && typeof prop === "object" && "value" in prop) {
|
|
2233
|
-
return prop.value;
|
|
2234
|
-
}
|
|
2235
|
-
return prop;
|
|
2236
|
-
}
|
|
2237
|
-
return void 0;
|
|
2238
|
-
},
|
|
2239
|
-
connect(destination) {
|
|
2240
|
-
effect.connect(destination);
|
|
2241
|
-
},
|
|
2242
|
-
disconnect() {
|
|
2243
|
-
try {
|
|
2244
|
-
effect.disconnect();
|
|
2245
|
-
} catch (e) {
|
|
2246
|
-
console.warn(
|
|
2247
|
-
`[waveform-playlist] Error disconnecting effect "${definition.id}" (${instanceId}):`,
|
|
2248
|
-
e
|
|
2249
|
-
);
|
|
2250
|
-
}
|
|
2251
|
-
}
|
|
2252
|
-
};
|
|
2253
|
-
}
|
|
2254
|
-
function createEffectChain(effects) {
|
|
2255
|
-
if (effects.length === 0) {
|
|
2256
|
-
throw new Error("Cannot create effect chain with no effects");
|
|
2257
|
-
}
|
|
2258
|
-
for (let i = 0; i < effects.length - 1; i++) {
|
|
2259
|
-
effects[i].effect.connect(effects[i + 1].effect);
|
|
2260
|
-
}
|
|
2261
|
-
return {
|
|
2262
|
-
input: effects[0].effect,
|
|
2263
|
-
output: effects[effects.length - 1].effect,
|
|
2264
|
-
dispose() {
|
|
2265
|
-
effects.forEach((e) => e.dispose());
|
|
2266
|
-
}
|
|
2267
|
-
};
|
|
2268
|
-
}
|
|
2269
|
-
|
|
2270
|
-
// src/hooks/useDynamicEffects.ts
|
|
2271
|
-
import { Analyser as Analyser2 } from "tone";
|
|
2272
|
-
function useDynamicEffects(fftSize = 256) {
|
|
2273
|
-
const [activeEffects, setActiveEffects] = useState9([]);
|
|
2274
|
-
const activeEffectsRef = useRef9(activeEffects);
|
|
2275
|
-
activeEffectsRef.current = activeEffects;
|
|
2276
|
-
const effectInstancesRef = useRef9(/* @__PURE__ */ new Map());
|
|
2277
|
-
const analyserRef = useRef9(null);
|
|
2278
|
-
const graphNodesRef = useRef9(null);
|
|
2279
|
-
const rebuildChain = useCallback12((effects) => {
|
|
2280
|
-
const nodes = graphNodesRef.current;
|
|
2281
|
-
if (!nodes) return;
|
|
2282
|
-
const { masterGainNode, destination, analyserNode } = nodes;
|
|
2283
|
-
try {
|
|
2284
|
-
masterGainNode.disconnect();
|
|
2285
|
-
} catch (e) {
|
|
2286
|
-
console.warn("[waveform-playlist] Error disconnecting master effects chain:", e);
|
|
2287
|
-
}
|
|
2288
|
-
const instances = effects.map((ae) => effectInstancesRef.current.get(ae.instanceId)).filter((inst) => inst !== void 0);
|
|
2289
|
-
if (instances.length === 0) {
|
|
2290
|
-
masterGainNode.connect(analyserNode);
|
|
2291
|
-
analyserNode.connect(destination);
|
|
2292
|
-
} else {
|
|
2293
|
-
let currentNode = masterGainNode;
|
|
2294
|
-
instances.forEach((inst) => {
|
|
2295
|
-
try {
|
|
2296
|
-
inst.disconnect();
|
|
2297
|
-
} catch (e) {
|
|
2298
|
-
console.warn(`[waveform-playlist] Error disconnecting effect "${inst.id}":`, e);
|
|
2299
|
-
}
|
|
2300
|
-
currentNode.connect(inst.effect);
|
|
2301
|
-
currentNode = inst.effect;
|
|
2302
|
-
});
|
|
2303
|
-
currentNode.connect(analyserNode);
|
|
2304
|
-
analyserNode.connect(destination);
|
|
2305
|
-
}
|
|
2306
|
-
}, []);
|
|
2307
|
-
const addEffect = useCallback12((effectId) => {
|
|
2308
|
-
const definition = getEffectDefinition(effectId);
|
|
2309
|
-
if (!definition) {
|
|
2310
|
-
console.error(`Unknown effect: ${effectId}`);
|
|
2311
|
-
return;
|
|
2312
|
-
}
|
|
2313
|
-
const params = {};
|
|
2314
|
-
definition.parameters.forEach((p) => {
|
|
2315
|
-
params[p.name] = p.default;
|
|
2316
|
-
});
|
|
2317
|
-
const instance = createEffectInstance(definition, params);
|
|
2318
|
-
effectInstancesRef.current.set(instance.instanceId, instance);
|
|
2319
|
-
const newActiveEffect = {
|
|
2320
|
-
instanceId: instance.instanceId,
|
|
2321
|
-
effectId: definition.id,
|
|
2322
|
-
definition,
|
|
2323
|
-
params,
|
|
2324
|
-
bypassed: false
|
|
2325
|
-
};
|
|
2326
|
-
setActiveEffects((prev) => [...prev, newActiveEffect]);
|
|
2327
|
-
}, []);
|
|
2328
|
-
const removeEffect = useCallback12((instanceId) => {
|
|
2329
|
-
const instance = effectInstancesRef.current.get(instanceId);
|
|
2330
|
-
if (instance) {
|
|
2331
|
-
instance.dispose();
|
|
2332
|
-
effectInstancesRef.current.delete(instanceId);
|
|
2333
|
-
}
|
|
2334
|
-
setActiveEffects((prev) => prev.filter((e) => e.instanceId !== instanceId));
|
|
2335
|
-
}, []);
|
|
2336
|
-
const updateParameter = useCallback12(
|
|
2337
|
-
(instanceId, paramName, value) => {
|
|
2338
|
-
const instance = effectInstancesRef.current.get(instanceId);
|
|
2339
|
-
if (instance) {
|
|
2340
|
-
instance.setParameter(paramName, value);
|
|
2341
|
-
}
|
|
2342
|
-
setActiveEffects(
|
|
2343
|
-
(prev) => prev.map(
|
|
2344
|
-
(e) => e.instanceId === instanceId ? __spreadProps(__spreadValues({}, e), { params: __spreadProps(__spreadValues({}, e.params), { [paramName]: value }) }) : e
|
|
2345
|
-
)
|
|
2346
|
-
);
|
|
2347
|
-
},
|
|
2348
|
-
[]
|
|
2349
|
-
);
|
|
2350
|
-
const toggleBypass = useCallback12((instanceId) => {
|
|
2351
|
-
var _a;
|
|
2352
|
-
const effect = activeEffectsRef.current.find((e) => e.instanceId === instanceId);
|
|
2353
|
-
if (!effect) return;
|
|
2354
|
-
const newBypassed = !effect.bypassed;
|
|
2355
|
-
const instance = effectInstancesRef.current.get(instanceId);
|
|
2356
|
-
if (instance) {
|
|
2357
|
-
const originalWet = (_a = effect.params.wet) != null ? _a : 1;
|
|
2358
|
-
instance.setParameter("wet", newBypassed ? 0 : originalWet);
|
|
2359
|
-
}
|
|
2360
|
-
setActiveEffects(
|
|
2361
|
-
(prev) => prev.map((e) => e.instanceId === instanceId ? __spreadProps(__spreadValues({}, e), { bypassed: newBypassed }) : e)
|
|
2362
|
-
);
|
|
2363
|
-
}, []);
|
|
2364
|
-
const reorderEffects = useCallback12((fromIndex, toIndex) => {
|
|
2365
|
-
setActiveEffects((prev) => {
|
|
2366
|
-
const newEffects = [...prev];
|
|
2367
|
-
const [removed] = newEffects.splice(fromIndex, 1);
|
|
2368
|
-
newEffects.splice(toIndex, 0, removed);
|
|
2369
|
-
return newEffects;
|
|
2370
|
-
});
|
|
2371
|
-
}, []);
|
|
2372
|
-
const clearAllEffects = useCallback12(() => {
|
|
2373
|
-
effectInstancesRef.current.forEach((inst) => inst.dispose());
|
|
2374
|
-
effectInstancesRef.current.clear();
|
|
2375
|
-
setActiveEffects([]);
|
|
2376
|
-
}, []);
|
|
2377
|
-
useEffect4(() => {
|
|
2378
|
-
rebuildChain(activeEffects);
|
|
2379
|
-
}, [activeEffects, rebuildChain]);
|
|
2380
|
-
const masterEffects = useCallback12(
|
|
2381
|
-
(masterGainNode, destination, _isOffline) => {
|
|
2382
|
-
const analyserNode = new Analyser2("fft", fftSize);
|
|
2383
|
-
analyserRef.current = analyserNode;
|
|
2384
|
-
graphNodesRef.current = {
|
|
2385
|
-
masterGainNode,
|
|
2386
|
-
destination,
|
|
2387
|
-
analyserNode
|
|
2388
|
-
};
|
|
2389
|
-
const effects = activeEffectsRef.current;
|
|
2390
|
-
const instances = effects.map((ae) => effectInstancesRef.current.get(ae.instanceId)).filter((inst) => inst !== void 0);
|
|
2391
|
-
if (instances.length === 0) {
|
|
2392
|
-
masterGainNode.connect(analyserNode);
|
|
2393
|
-
analyserNode.connect(destination);
|
|
2394
|
-
} else {
|
|
2395
|
-
let currentNode = masterGainNode;
|
|
2396
|
-
instances.forEach((inst) => {
|
|
2397
|
-
currentNode.connect(inst.effect);
|
|
2398
|
-
currentNode = inst.effect;
|
|
2399
|
-
});
|
|
2400
|
-
currentNode.connect(analyserNode);
|
|
2401
|
-
analyserNode.connect(destination);
|
|
2402
|
-
}
|
|
2403
|
-
return function cleanup() {
|
|
2404
|
-
analyserNode.dispose();
|
|
2405
|
-
analyserRef.current = null;
|
|
2406
|
-
graphNodesRef.current = null;
|
|
2407
|
-
};
|
|
2408
|
-
},
|
|
2409
|
-
[fftSize]
|
|
2410
|
-
// Only fftSize - reads effects from ref
|
|
2411
|
-
);
|
|
2412
|
-
useEffect4(() => {
|
|
2413
|
-
const effectInstances = effectInstancesRef.current;
|
|
2414
|
-
return () => {
|
|
2415
|
-
effectInstances.forEach((inst) => inst.dispose());
|
|
2416
|
-
effectInstances.clear();
|
|
2417
|
-
};
|
|
2418
|
-
}, []);
|
|
2419
|
-
const createOfflineEffectsFunction = useCallback12(() => {
|
|
2420
|
-
const nonBypassedEffects = activeEffects.filter((e) => !e.bypassed);
|
|
2421
|
-
if (nonBypassedEffects.length === 0) {
|
|
2422
|
-
return void 0;
|
|
2423
|
-
}
|
|
2424
|
-
return (masterGainNode, destination, _isOffline) => {
|
|
2425
|
-
const offlineInstances = [];
|
|
2426
|
-
for (const activeEffect of nonBypassedEffects) {
|
|
2427
|
-
const instance = createEffectInstance(activeEffect.definition, activeEffect.params);
|
|
2428
|
-
offlineInstances.push(instance);
|
|
2429
|
-
}
|
|
2430
|
-
if (offlineInstances.length === 0) {
|
|
2431
|
-
masterGainNode.connect(destination);
|
|
2432
|
-
} else {
|
|
2433
|
-
let currentNode = masterGainNode;
|
|
2434
|
-
offlineInstances.forEach((inst) => {
|
|
2435
|
-
currentNode.connect(inst.effect);
|
|
2436
|
-
currentNode = inst.effect;
|
|
2437
|
-
});
|
|
2438
|
-
currentNode.connect(destination);
|
|
2439
|
-
}
|
|
2440
|
-
return function cleanup() {
|
|
2441
|
-
offlineInstances.forEach((inst) => inst.dispose());
|
|
2442
|
-
};
|
|
2443
|
-
};
|
|
2444
|
-
}, [activeEffects]);
|
|
2445
|
-
return {
|
|
2446
|
-
activeEffects,
|
|
2447
|
-
availableEffects: effectDefinitions,
|
|
2448
|
-
addEffect,
|
|
2449
|
-
removeEffect,
|
|
2450
|
-
updateParameter,
|
|
2451
|
-
toggleBypass,
|
|
2452
|
-
reorderEffects,
|
|
2453
|
-
clearAllEffects,
|
|
2454
|
-
masterEffects,
|
|
2455
|
-
createOfflineEffectsFunction,
|
|
2456
|
-
analyserRef
|
|
2457
|
-
};
|
|
2458
|
-
}
|
|
2459
|
-
|
|
2460
|
-
// src/hooks/useTrackDynamicEffects.ts
|
|
2461
|
-
import { useState as useState10, useCallback as useCallback13, useRef as useRef10, useEffect as useEffect5 } from "react";
|
|
2462
|
-
function useTrackDynamicEffects() {
|
|
2463
|
-
const [trackEffectsState, setTrackEffectsState] = useState10(
|
|
2464
|
-
/* @__PURE__ */ new Map()
|
|
2465
|
-
);
|
|
2466
|
-
const trackEffectInstancesRef = useRef10(/* @__PURE__ */ new Map());
|
|
2467
|
-
const trackGraphNodesRef = useRef10(/* @__PURE__ */ new Map());
|
|
2468
|
-
const rebuildTrackChain = useCallback13((trackId, trackEffects) => {
|
|
2469
|
-
const nodes = trackGraphNodesRef.current.get(trackId);
|
|
2470
|
-
if (!nodes) return;
|
|
2471
|
-
const { graphEnd, masterGainNode } = nodes;
|
|
2472
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2473
|
-
try {
|
|
2474
|
-
graphEnd.disconnect();
|
|
2475
|
-
} catch (e) {
|
|
2476
|
-
console.warn(`[waveform-playlist] Error disconnecting track "${trackId}" effect chain:`, e);
|
|
2477
|
-
}
|
|
2478
|
-
const instances = trackEffects.map((ae) => instancesMap == null ? void 0 : instancesMap.get(ae.instanceId)).filter((inst) => inst !== void 0);
|
|
2479
|
-
if (instances.length === 0) {
|
|
2480
|
-
graphEnd.connect(masterGainNode);
|
|
2481
|
-
} else {
|
|
2482
|
-
let currentNode = graphEnd;
|
|
2483
|
-
instances.forEach((inst) => {
|
|
2484
|
-
try {
|
|
2485
|
-
inst.disconnect();
|
|
2486
|
-
} catch (e) {
|
|
2487
|
-
console.warn(
|
|
2488
|
-
`[waveform-playlist] Error disconnecting effect "${inst.id}" on track "${trackId}":`,
|
|
2489
|
-
e
|
|
2490
|
-
);
|
|
2491
|
-
}
|
|
2492
|
-
currentNode.connect(inst.effect);
|
|
2493
|
-
currentNode = inst.effect;
|
|
2494
|
-
});
|
|
2495
|
-
currentNode.connect(masterGainNode);
|
|
2496
|
-
}
|
|
2497
|
-
}, []);
|
|
2498
|
-
const addEffectToTrack = useCallback13((trackId, effectId) => {
|
|
2499
|
-
const definition = getEffectDefinition(effectId);
|
|
2500
|
-
if (!definition) {
|
|
2501
|
-
console.error(`Unknown effect: ${effectId}`);
|
|
2502
|
-
return;
|
|
2503
|
-
}
|
|
2504
|
-
const params = {};
|
|
2505
|
-
definition.parameters.forEach((p) => {
|
|
2506
|
-
params[p.name] = p.default;
|
|
2507
|
-
});
|
|
2508
|
-
const instance = createEffectInstance(definition, params);
|
|
2509
|
-
if (!trackEffectInstancesRef.current.has(trackId)) {
|
|
2510
|
-
trackEffectInstancesRef.current.set(trackId, /* @__PURE__ */ new Map());
|
|
2511
|
-
}
|
|
2512
|
-
trackEffectInstancesRef.current.get(trackId).set(instance.instanceId, instance);
|
|
2513
|
-
const newActiveEffect = {
|
|
2514
|
-
instanceId: instance.instanceId,
|
|
2515
|
-
effectId: definition.id,
|
|
2516
|
-
definition,
|
|
2517
|
-
params,
|
|
2518
|
-
bypassed: false
|
|
2519
|
-
};
|
|
2520
|
-
setTrackEffectsState((prev) => {
|
|
2521
|
-
const newState = new Map(prev);
|
|
2522
|
-
const existing = newState.get(trackId) || [];
|
|
2523
|
-
newState.set(trackId, [...existing, newActiveEffect]);
|
|
2524
|
-
return newState;
|
|
2525
|
-
});
|
|
2526
|
-
}, []);
|
|
2527
|
-
const removeEffectFromTrack = useCallback13((trackId, instanceId) => {
|
|
2528
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2529
|
-
const instance = instancesMap == null ? void 0 : instancesMap.get(instanceId);
|
|
2530
|
-
if (instance) {
|
|
2531
|
-
instance.dispose();
|
|
2532
|
-
instancesMap == null ? void 0 : instancesMap.delete(instanceId);
|
|
2533
|
-
}
|
|
2534
|
-
setTrackEffectsState((prev) => {
|
|
2535
|
-
const newState = new Map(prev);
|
|
2536
|
-
const existing = newState.get(trackId) || [];
|
|
2537
|
-
newState.set(
|
|
2538
|
-
trackId,
|
|
2539
|
-
existing.filter((e) => e.instanceId !== instanceId)
|
|
2540
|
-
);
|
|
2541
|
-
return newState;
|
|
2542
|
-
});
|
|
2543
|
-
}, []);
|
|
2544
|
-
const updateTrackEffectParameter = useCallback13(
|
|
2545
|
-
(trackId, instanceId, paramName, value) => {
|
|
2546
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2547
|
-
const instance = instancesMap == null ? void 0 : instancesMap.get(instanceId);
|
|
2548
|
-
if (instance) {
|
|
2549
|
-
instance.setParameter(paramName, value);
|
|
2550
|
-
}
|
|
2551
|
-
setTrackEffectsState((prev) => {
|
|
2552
|
-
const newState = new Map(prev);
|
|
2553
|
-
const existing = newState.get(trackId) || [];
|
|
2554
|
-
newState.set(
|
|
2555
|
-
trackId,
|
|
2556
|
-
existing.map(
|
|
2557
|
-
(e) => e.instanceId === instanceId ? __spreadProps(__spreadValues({}, e), { params: __spreadProps(__spreadValues({}, e.params), { [paramName]: value }) }) : e
|
|
2558
|
-
)
|
|
2559
|
-
);
|
|
2560
|
-
return newState;
|
|
2561
|
-
});
|
|
2562
|
-
},
|
|
2563
|
-
[]
|
|
2564
|
-
);
|
|
2565
|
-
const toggleBypass = useCallback13((trackId, instanceId) => {
|
|
2566
|
-
var _a;
|
|
2567
|
-
const trackEffects = trackEffectsStateRef.current.get(trackId) || [];
|
|
2568
|
-
const effect = trackEffects.find((e) => e.instanceId === instanceId);
|
|
2569
|
-
if (!effect) return;
|
|
2570
|
-
const newBypassed = !effect.bypassed;
|
|
2571
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2572
|
-
const instance = instancesMap == null ? void 0 : instancesMap.get(instanceId);
|
|
2573
|
-
if (instance) {
|
|
2574
|
-
const originalWet = (_a = effect.params.wet) != null ? _a : 1;
|
|
2575
|
-
instance.setParameter("wet", newBypassed ? 0 : originalWet);
|
|
2576
|
-
}
|
|
2577
|
-
setTrackEffectsState((prev) => {
|
|
2578
|
-
const newState = new Map(prev);
|
|
2579
|
-
const existing = newState.get(trackId) || [];
|
|
2580
|
-
newState.set(
|
|
2581
|
-
trackId,
|
|
2582
|
-
existing.map((e) => e.instanceId === instanceId ? __spreadProps(__spreadValues({}, e), { bypassed: newBypassed }) : e)
|
|
2583
|
-
);
|
|
2584
|
-
return newState;
|
|
2585
|
-
});
|
|
2586
|
-
}, []);
|
|
2587
|
-
const clearTrackEffects = useCallback13((trackId) => {
|
|
2588
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2589
|
-
if (instancesMap) {
|
|
2590
|
-
instancesMap.forEach((inst) => inst.dispose());
|
|
2591
|
-
instancesMap.clear();
|
|
2592
|
-
}
|
|
2593
|
-
setTrackEffectsState((prev) => {
|
|
2594
|
-
const newState = new Map(prev);
|
|
2595
|
-
newState.set(trackId, []);
|
|
2596
|
-
return newState;
|
|
2597
|
-
});
|
|
2598
|
-
}, []);
|
|
2599
|
-
const trackEffectsStateRef = useRef10(trackEffectsState);
|
|
2600
|
-
trackEffectsStateRef.current = trackEffectsState;
|
|
2601
|
-
const getTrackEffectsFunction = useCallback13(
|
|
2602
|
-
(trackId) => {
|
|
2603
|
-
return (graphEnd, masterGainNode, _isOffline) => {
|
|
2604
|
-
trackGraphNodesRef.current.set(trackId, {
|
|
2605
|
-
graphEnd,
|
|
2606
|
-
masterGainNode
|
|
2607
|
-
});
|
|
2608
|
-
const trackEffects = trackEffectsStateRef.current.get(trackId) || [];
|
|
2609
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2610
|
-
const instances = trackEffects.map((ae) => instancesMap == null ? void 0 : instancesMap.get(ae.instanceId)).filter((inst) => inst !== void 0);
|
|
2611
|
-
if (instances.length === 0) {
|
|
2612
|
-
graphEnd.connect(masterGainNode);
|
|
2613
|
-
} else {
|
|
2614
|
-
let currentNode = graphEnd;
|
|
2615
|
-
instances.forEach((inst) => {
|
|
2616
|
-
currentNode.connect(inst.effect);
|
|
2617
|
-
currentNode = inst.effect;
|
|
2618
|
-
});
|
|
2619
|
-
currentNode.connect(masterGainNode);
|
|
2620
|
-
}
|
|
2621
|
-
return function cleanup() {
|
|
2622
|
-
trackGraphNodesRef.current.delete(trackId);
|
|
2623
|
-
};
|
|
2624
|
-
};
|
|
2625
|
-
},
|
|
2626
|
-
[]
|
|
2627
|
-
// No dependencies - stable function that reads from refs
|
|
2628
|
-
);
|
|
2629
|
-
useEffect5(() => {
|
|
2630
|
-
trackEffectsState.forEach((effects, trackId) => {
|
|
2631
|
-
rebuildTrackChain(trackId, effects);
|
|
2632
|
-
});
|
|
2633
|
-
}, [trackEffectsState, rebuildTrackChain]);
|
|
2634
|
-
useEffect5(() => {
|
|
2635
|
-
const trackEffectInstances = trackEffectInstancesRef.current;
|
|
2636
|
-
return () => {
|
|
2637
|
-
trackEffectInstances.forEach((instancesMap) => {
|
|
2638
|
-
instancesMap.forEach((inst) => inst.dispose());
|
|
2639
|
-
instancesMap.clear();
|
|
2640
|
-
});
|
|
2641
|
-
trackEffectInstances.clear();
|
|
2642
|
-
};
|
|
2643
|
-
}, []);
|
|
2644
|
-
const createOfflineTrackEffectsFunction = useCallback13(
|
|
2645
|
-
(trackId) => {
|
|
2646
|
-
const trackEffects = trackEffectsState.get(trackId) || [];
|
|
2647
|
-
const nonBypassedEffects = trackEffects.filter((e) => !e.bypassed);
|
|
2648
|
-
if (nonBypassedEffects.length === 0) {
|
|
2649
|
-
return void 0;
|
|
2650
|
-
}
|
|
2651
|
-
return (graphEnd, masterGainNode, _isOffline) => {
|
|
2652
|
-
const offlineInstances = [];
|
|
2653
|
-
for (const activeEffect of nonBypassedEffects) {
|
|
2654
|
-
const instance = createEffectInstance(activeEffect.definition, activeEffect.params);
|
|
2655
|
-
offlineInstances.push(instance);
|
|
2656
|
-
}
|
|
2657
|
-
if (offlineInstances.length === 0) {
|
|
2658
|
-
graphEnd.connect(masterGainNode);
|
|
2659
|
-
} else {
|
|
2660
|
-
let currentNode = graphEnd;
|
|
2661
|
-
offlineInstances.forEach((inst) => {
|
|
2662
|
-
currentNode.connect(inst.effect);
|
|
2663
|
-
currentNode = inst.effect;
|
|
2664
|
-
});
|
|
2665
|
-
currentNode.connect(masterGainNode);
|
|
2666
|
-
}
|
|
2667
|
-
return function cleanup() {
|
|
2668
|
-
offlineInstances.forEach((inst) => inst.dispose());
|
|
2669
|
-
};
|
|
2670
|
-
};
|
|
2671
|
-
},
|
|
2672
|
-
[trackEffectsState]
|
|
2673
|
-
);
|
|
2674
|
-
return {
|
|
2675
|
-
trackEffectsState,
|
|
2676
|
-
addEffectToTrack,
|
|
2677
|
-
removeEffectFromTrack,
|
|
2678
|
-
updateTrackEffectParameter,
|
|
2679
|
-
toggleBypass,
|
|
2680
|
-
clearTrackEffects,
|
|
2681
|
-
getTrackEffectsFunction,
|
|
2682
|
-
createOfflineTrackEffectsFunction,
|
|
2683
|
-
availableEffects: effectDefinitions
|
|
2684
|
-
};
|
|
2685
|
-
}
|
|
2686
|
-
|
|
2687
|
-
// src/hooks/useExportWav.ts
|
|
2688
|
-
import { useState as useState11, useCallback as useCallback14 } from "react";
|
|
2689
|
-
import {
|
|
2690
|
-
gainToDb,
|
|
2691
|
-
trackChannelCount,
|
|
2692
|
-
applyFadeIn,
|
|
2693
|
-
applyFadeOut
|
|
2694
|
-
} from "@waveform-playlist/core";
|
|
2695
|
-
import {
|
|
2696
|
-
getUnderlyingAudioParam,
|
|
2697
|
-
getGlobalAudioContext as getGlobalAudioContext2
|
|
2698
|
-
} from "@waveform-playlist/playout";
|
|
2699
|
-
|
|
2700
|
-
// src/utils/wavEncoder.ts
|
|
2701
|
-
function encodeWav(audioBuffer, options = {}) {
|
|
2702
|
-
const { bitDepth = 16 } = options;
|
|
2703
|
-
const numChannels = audioBuffer.numberOfChannels;
|
|
2704
|
-
const sampleRate = audioBuffer.sampleRate;
|
|
2705
|
-
const numSamples = audioBuffer.length;
|
|
2706
|
-
const bytesPerSample = bitDepth / 8;
|
|
2707
|
-
const blockAlign = numChannels * bytesPerSample;
|
|
2708
|
-
const byteRate = sampleRate * blockAlign;
|
|
2709
|
-
const dataSize = numSamples * blockAlign;
|
|
2710
|
-
const headerSize = 44;
|
|
2711
|
-
const totalSize = headerSize + dataSize;
|
|
2712
|
-
const buffer = new ArrayBuffer(totalSize);
|
|
2713
|
-
const view = new DataView(buffer);
|
|
2714
|
-
writeString(view, 0, "RIFF");
|
|
2715
|
-
view.setUint32(4, totalSize - 8, true);
|
|
2716
|
-
writeString(view, 8, "WAVE");
|
|
2717
|
-
writeString(view, 12, "fmt ");
|
|
2718
|
-
view.setUint32(16, 16, true);
|
|
2719
|
-
view.setUint16(20, bitDepth === 32 ? 3 : 1, true);
|
|
2720
|
-
view.setUint16(22, numChannels, true);
|
|
2721
|
-
view.setUint32(24, sampleRate, true);
|
|
2722
|
-
view.setUint32(28, byteRate, true);
|
|
2723
|
-
view.setUint16(32, blockAlign, true);
|
|
2724
|
-
view.setUint16(34, bitDepth, true);
|
|
2725
|
-
writeString(view, 36, "data");
|
|
2726
|
-
view.setUint32(40, dataSize, true);
|
|
2727
|
-
const channelData = [];
|
|
2728
|
-
for (let ch = 0; ch < numChannels; ch++) {
|
|
2729
|
-
channelData.push(audioBuffer.getChannelData(ch));
|
|
2730
|
-
}
|
|
2731
|
-
let offset = headerSize;
|
|
2732
|
-
if (bitDepth === 16) {
|
|
2733
|
-
for (let i = 0; i < numSamples; i++) {
|
|
2734
|
-
for (let ch = 0; ch < numChannels; ch++) {
|
|
2735
|
-
const sample = channelData[ch][i];
|
|
2736
|
-
const clampedSample = Math.max(-1, Math.min(1, sample));
|
|
2737
|
-
const intSample = clampedSample < 0 ? clampedSample * 32768 : clampedSample * 32767;
|
|
2738
|
-
view.setInt16(offset, intSample, true);
|
|
2739
|
-
offset += 2;
|
|
2740
|
-
}
|
|
2741
|
-
}
|
|
2742
|
-
} else {
|
|
2743
|
-
for (let i = 0; i < numSamples; i++) {
|
|
2744
|
-
for (let ch = 0; ch < numChannels; ch++) {
|
|
2745
|
-
view.setFloat32(offset, channelData[ch][i], true);
|
|
2746
|
-
offset += 4;
|
|
2747
|
-
}
|
|
2748
|
-
}
|
|
2749
|
-
}
|
|
2750
|
-
return new Blob([buffer], { type: "audio/wav" });
|
|
2751
|
-
}
|
|
2752
|
-
function writeString(view, offset, str) {
|
|
2753
|
-
for (let i = 0; i < str.length; i++) {
|
|
2754
|
-
view.setUint8(offset + i, str.charCodeAt(i));
|
|
2755
|
-
}
|
|
2756
|
-
}
|
|
2757
|
-
function downloadBlob(blob, filename) {
|
|
2758
|
-
const url = URL.createObjectURL(blob);
|
|
2759
|
-
const a = document.createElement("a");
|
|
2760
|
-
a.href = url;
|
|
2761
|
-
a.download = filename;
|
|
2762
|
-
a.style.display = "none";
|
|
2763
|
-
document.body.appendChild(a);
|
|
2764
|
-
a.click();
|
|
2765
|
-
document.body.removeChild(a);
|
|
2766
|
-
URL.revokeObjectURL(url);
|
|
2767
|
-
}
|
|
2768
|
-
|
|
2769
|
-
// src/hooks/useExportWav.ts
|
|
2770
|
-
function useExportWav() {
|
|
2771
|
-
const [isExporting, setIsExporting] = useState11(false);
|
|
2772
|
-
const [progress, setProgress] = useState11(0);
|
|
2773
|
-
const [error, setError] = useState11(null);
|
|
2774
|
-
const exportWav = useCallback14(
|
|
2775
|
-
(_0, _1, ..._2) => __async(null, [_0, _1, ..._2], function* (tracks, trackStates, options = {}) {
|
|
2776
|
-
const {
|
|
2777
|
-
filename = "export",
|
|
2778
|
-
mode = "master",
|
|
2779
|
-
trackIndex,
|
|
2780
|
-
autoDownload = true,
|
|
2781
|
-
applyEffects = true,
|
|
2782
|
-
effectsFunction,
|
|
2783
|
-
createOfflineTrackEffects,
|
|
2784
|
-
bitDepth = 16,
|
|
2785
|
-
onProgress
|
|
2786
|
-
} = options;
|
|
2787
|
-
setIsExporting(true);
|
|
2788
|
-
setProgress(0);
|
|
2789
|
-
setError(null);
|
|
2790
|
-
try {
|
|
2791
|
-
if (tracks.length === 0) {
|
|
2792
|
-
throw new Error("No tracks to export");
|
|
2793
|
-
}
|
|
2794
|
-
if (mode === "individual" && (trackIndex === void 0 || trackIndex < 0 || trackIndex >= tracks.length)) {
|
|
2795
|
-
throw new Error("Invalid track index for individual export");
|
|
2796
|
-
}
|
|
2797
|
-
const sampleRate = getGlobalAudioContext2().sampleRate;
|
|
2798
|
-
let totalDurationSamples = 0;
|
|
2799
|
-
for (const track of tracks) {
|
|
2800
|
-
for (const clip of track.clips) {
|
|
2801
|
-
const clipEndSample = clip.startSample + clip.durationSamples;
|
|
2802
|
-
totalDurationSamples = Math.max(totalDurationSamples, clipEndSample);
|
|
2803
|
-
}
|
|
2804
|
-
}
|
|
2805
|
-
totalDurationSamples += Math.round(sampleRate * 0.1);
|
|
2806
|
-
const duration = totalDurationSamples / sampleRate;
|
|
2807
|
-
const tracksToRender = mode === "individual" ? [{ track: tracks[trackIndex], state: trackStates[trackIndex], index: trackIndex }] : tracks.map((track, index) => ({ track, state: trackStates[index], index }));
|
|
2808
|
-
const hasSolo = mode === "master" && trackStates.some((state) => state.soloed);
|
|
2809
|
-
const reportProgress = (p) => {
|
|
2810
|
-
setProgress(p);
|
|
2811
|
-
onProgress == null ? void 0 : onProgress(p);
|
|
2812
|
-
};
|
|
2813
|
-
const renderedBuffer = yield renderOffline(
|
|
2814
|
-
tracksToRender,
|
|
2815
|
-
hasSolo,
|
|
2816
|
-
duration,
|
|
2817
|
-
sampleRate,
|
|
2818
|
-
applyEffects,
|
|
2819
|
-
effectsFunction,
|
|
2820
|
-
createOfflineTrackEffects,
|
|
2821
|
-
reportProgress
|
|
2822
|
-
);
|
|
2823
|
-
reportProgress(0.9);
|
|
2824
|
-
const blob = encodeWav(renderedBuffer, { bitDepth });
|
|
2825
|
-
reportProgress(1);
|
|
2826
|
-
if (autoDownload) {
|
|
2827
|
-
const exportFilename = mode === "individual" ? `${filename}_${tracks[trackIndex].name}` : filename;
|
|
2828
|
-
downloadBlob(blob, `${exportFilename}.wav`);
|
|
2829
|
-
}
|
|
2830
|
-
return {
|
|
2831
|
-
audioBuffer: renderedBuffer,
|
|
2832
|
-
blob,
|
|
2833
|
-
duration
|
|
2834
|
-
};
|
|
2835
|
-
} catch (err) {
|
|
2836
|
-
const message = err instanceof Error ? err.message : "Export failed";
|
|
2837
|
-
setError(message);
|
|
2838
|
-
throw err;
|
|
2839
|
-
} finally {
|
|
2840
|
-
setIsExporting(false);
|
|
1341
|
+
key: "Home",
|
|
1342
|
+
action: selectFirst,
|
|
1343
|
+
description: "Select first annotation",
|
|
1344
|
+
preventDefault: true
|
|
1345
|
+
},
|
|
1346
|
+
{
|
|
1347
|
+
key: "End",
|
|
1348
|
+
action: selectLast,
|
|
1349
|
+
description: "Select last annotation",
|
|
1350
|
+
preventDefault: true
|
|
1351
|
+
},
|
|
1352
|
+
{
|
|
1353
|
+
key: "Escape",
|
|
1354
|
+
action: clearSelection,
|
|
1355
|
+
description: "Deselect annotation",
|
|
1356
|
+
preventDefault: true
|
|
2841
1357
|
}
|
|
2842
|
-
|
|
2843
|
-
[]
|
|
1358
|
+
],
|
|
1359
|
+
[selectPrevious, selectNext, selectFirst, selectLast, clearSelection]
|
|
2844
1360
|
);
|
|
1361
|
+
useKeyboardShortcuts({
|
|
1362
|
+
shortcuts: activeAnnotationShortcuts,
|
|
1363
|
+
enabled: enabled && activeIndex >= 0
|
|
1364
|
+
});
|
|
1365
|
+
useKeyboardShortcuts({
|
|
1366
|
+
shortcuts: navigationShortcuts,
|
|
1367
|
+
enabled: enabled && annotations.length > 0 && !!onActiveAnnotationChange
|
|
1368
|
+
});
|
|
2845
1369
|
return {
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
1370
|
+
moveStartBoundary,
|
|
1371
|
+
moveEndBoundary,
|
|
1372
|
+
selectPrevious,
|
|
1373
|
+
selectNext,
|
|
1374
|
+
selectFirst,
|
|
1375
|
+
selectLast,
|
|
1376
|
+
clearSelection,
|
|
1377
|
+
scrollToAnnotation,
|
|
1378
|
+
playActiveAnnotation
|
|
2850
1379
|
};
|
|
2851
1380
|
}
|
|
2852
|
-
function renderOffline(tracksToRender, hasSolo, duration, sampleRate, applyEffects, effectsFunction, createOfflineTrackEffects, onProgress) {
|
|
2853
|
-
return __async(this, null, function* () {
|
|
2854
|
-
const { Offline, Volume: Volume2, Gain, Panner, Player, ToneAudioBuffer } = yield import("tone");
|
|
2855
|
-
onProgress(0.1);
|
|
2856
|
-
const audibleTracks = tracksToRender.filter(({ state }) => {
|
|
2857
|
-
if (state.muted && !state.soloed) return false;
|
|
2858
|
-
if (hasSolo && !state.soloed) return false;
|
|
2859
|
-
return true;
|
|
2860
|
-
});
|
|
2861
|
-
const outputChannels = audibleTracks.reduce(
|
|
2862
|
-
(max, { track }) => Math.max(max, trackChannelCount(track)),
|
|
2863
|
-
1
|
|
2864
|
-
);
|
|
2865
|
-
let buffer;
|
|
2866
|
-
try {
|
|
2867
|
-
buffer = yield Offline(
|
|
2868
|
-
(_0) => __async(null, [_0], function* ({ transport, destination }) {
|
|
2869
|
-
const masterVolume = new Volume2(0);
|
|
2870
|
-
if (effectsFunction && applyEffects) {
|
|
2871
|
-
effectsFunction(masterVolume, destination, true);
|
|
2872
|
-
} else {
|
|
2873
|
-
masterVolume.connect(destination);
|
|
2874
|
-
}
|
|
2875
|
-
for (const { track, state } of audibleTracks) {
|
|
2876
|
-
const trackVolume = new Volume2(gainToDb(state.volume));
|
|
2877
|
-
const trackPan = new Panner({ pan: state.pan, channelCount: trackChannelCount(track) });
|
|
2878
|
-
const trackMute = new Gain(state.muted ? 0 : 1);
|
|
2879
|
-
const trackEffects = createOfflineTrackEffects == null ? void 0 : createOfflineTrackEffects(track.id);
|
|
2880
|
-
if (trackEffects && applyEffects) {
|
|
2881
|
-
trackEffects(trackMute, masterVolume, true);
|
|
2882
|
-
} else {
|
|
2883
|
-
trackMute.connect(masterVolume);
|
|
2884
|
-
}
|
|
2885
|
-
trackPan.connect(trackMute);
|
|
2886
|
-
trackVolume.connect(trackPan);
|
|
2887
|
-
for (const clip of track.clips) {
|
|
2888
|
-
const {
|
|
2889
|
-
audioBuffer,
|
|
2890
|
-
startSample,
|
|
2891
|
-
durationSamples,
|
|
2892
|
-
offsetSamples,
|
|
2893
|
-
gain: clipGain,
|
|
2894
|
-
fadeIn,
|
|
2895
|
-
fadeOut
|
|
2896
|
-
} = clip;
|
|
2897
|
-
if (!audioBuffer) {
|
|
2898
|
-
console.warn(
|
|
2899
|
-
'[waveform-playlist] Skipping clip "' + (clip.name || clip.id) + '" - no audioBuffer for export'
|
|
2900
|
-
);
|
|
2901
|
-
continue;
|
|
2902
|
-
}
|
|
2903
|
-
const startTime = startSample / sampleRate;
|
|
2904
|
-
const clipDuration = durationSamples / sampleRate;
|
|
2905
|
-
const offset = offsetSamples / sampleRate;
|
|
2906
|
-
const toneBuffer = new ToneAudioBuffer(audioBuffer);
|
|
2907
|
-
const player = new Player(toneBuffer);
|
|
2908
|
-
const fadeGain = new Gain(clipGain);
|
|
2909
|
-
player.connect(fadeGain);
|
|
2910
|
-
fadeGain.connect(trackVolume);
|
|
2911
|
-
if (applyEffects) {
|
|
2912
|
-
const audioParam = getUnderlyingAudioParam(fadeGain.gain);
|
|
2913
|
-
if (audioParam) {
|
|
2914
|
-
applyClipFades(audioParam, clipGain, startTime, clipDuration, fadeIn, fadeOut);
|
|
2915
|
-
} else if (fadeIn || fadeOut) {
|
|
2916
|
-
console.warn(
|
|
2917
|
-
'[waveform-playlist] Cannot apply fades for clip "' + (clip.name || clip.id) + '" - AudioParam not accessible'
|
|
2918
|
-
);
|
|
2919
|
-
}
|
|
2920
|
-
}
|
|
2921
|
-
player.start(startTime, offset, clipDuration);
|
|
2922
|
-
}
|
|
2923
|
-
}
|
|
2924
|
-
transport.start(0);
|
|
2925
|
-
}),
|
|
2926
|
-
duration,
|
|
2927
|
-
outputChannels,
|
|
2928
|
-
sampleRate
|
|
2929
|
-
);
|
|
2930
|
-
} catch (err) {
|
|
2931
|
-
if (err instanceof Error) {
|
|
2932
|
-
throw err;
|
|
2933
|
-
} else {
|
|
2934
|
-
throw new Error("Tone.Offline rendering failed: " + String(err));
|
|
2935
|
-
}
|
|
2936
|
-
}
|
|
2937
|
-
onProgress(0.9);
|
|
2938
|
-
const result = buffer.get();
|
|
2939
|
-
if (!result) {
|
|
2940
|
-
throw new Error("Offline rendering produced no audio buffer");
|
|
2941
|
-
}
|
|
2942
|
-
return result;
|
|
2943
|
-
});
|
|
2944
|
-
}
|
|
2945
|
-
function applyClipFades(gainParam, clipGain, startTime, clipDuration, fadeIn, fadeOut) {
|
|
2946
|
-
if (fadeIn) {
|
|
2947
|
-
gainParam.setValueAtTime(0, startTime);
|
|
2948
|
-
} else {
|
|
2949
|
-
gainParam.setValueAtTime(clipGain, startTime);
|
|
2950
|
-
}
|
|
2951
|
-
if (fadeIn) {
|
|
2952
|
-
applyFadeIn(gainParam, startTime, fadeIn.duration, fadeIn.type || "linear", 0, clipGain);
|
|
2953
|
-
}
|
|
2954
|
-
if (fadeOut) {
|
|
2955
|
-
const fadeOutStart = startTime + clipDuration - fadeOut.duration;
|
|
2956
|
-
if (!fadeIn || fadeIn.duration < clipDuration - fadeOut.duration) {
|
|
2957
|
-
gainParam.setValueAtTime(clipGain, fadeOutStart);
|
|
2958
|
-
}
|
|
2959
|
-
applyFadeOut(gainParam, fadeOutStart, fadeOut.duration, fadeOut.type || "linear", clipGain, 0);
|
|
2960
|
-
}
|
|
2961
|
-
}
|
|
2962
1381
|
|
|
2963
1382
|
// src/hooks/useAnimationFrameLoop.ts
|
|
2964
|
-
import { useCallback as
|
|
1383
|
+
import { useCallback as useCallback11, useEffect as useEffect3, useRef as useRef7 } from "react";
|
|
2965
1384
|
var useAnimationFrameLoop = () => {
|
|
2966
|
-
const animationFrameRef =
|
|
2967
|
-
const stopAnimationFrameLoop =
|
|
1385
|
+
const animationFrameRef = useRef7(null);
|
|
1386
|
+
const stopAnimationFrameLoop = useCallback11(() => {
|
|
2968
1387
|
if (animationFrameRef.current !== null) {
|
|
2969
1388
|
cancelAnimationFrame(animationFrameRef.current);
|
|
2970
1389
|
animationFrameRef.current = null;
|
|
2971
1390
|
}
|
|
2972
1391
|
}, []);
|
|
2973
|
-
const startAnimationFrameLoop =
|
|
1392
|
+
const startAnimationFrameLoop = useCallback11(
|
|
2974
1393
|
(callback) => {
|
|
2975
1394
|
stopAnimationFrameLoop();
|
|
2976
1395
|
animationFrameRef.current = requestAnimationFrame(callback);
|
|
2977
1396
|
},
|
|
2978
1397
|
[stopAnimationFrameLoop]
|
|
2979
1398
|
);
|
|
2980
|
-
|
|
1399
|
+
useEffect3(() => {
|
|
2981
1400
|
return () => {
|
|
2982
1401
|
stopAnimationFrameLoop();
|
|
2983
1402
|
};
|
|
@@ -2990,7 +1409,7 @@ var useAnimationFrameLoop = () => {
|
|
|
2990
1409
|
};
|
|
2991
1410
|
|
|
2992
1411
|
// src/hooks/useWaveformDataCache.ts
|
|
2993
|
-
import { useState as
|
|
1412
|
+
import { useState as useState8, useEffect as useEffect4, useRef as useRef8, useCallback as useCallback12 } from "react";
|
|
2994
1413
|
|
|
2995
1414
|
// src/workers/peaksWorker.ts
|
|
2996
1415
|
import WaveformData2 from "waveform-data";
|
|
@@ -3222,20 +1641,20 @@ function createPeaksWorker() {
|
|
|
3222
1641
|
|
|
3223
1642
|
// src/hooks/useWaveformDataCache.ts
|
|
3224
1643
|
function useWaveformDataCache(tracks, baseScale) {
|
|
3225
|
-
const [cache, setCache] =
|
|
3226
|
-
const [isGenerating, setIsGenerating] =
|
|
3227
|
-
const workerRef =
|
|
3228
|
-
const generatedByBufferRef =
|
|
3229
|
-
const inflightByBufferRef =
|
|
3230
|
-
const subscribersByBufferRef =
|
|
3231
|
-
const pendingCountRef =
|
|
3232
|
-
const getWorker =
|
|
1644
|
+
const [cache, setCache] = useState8(() => /* @__PURE__ */ new Map());
|
|
1645
|
+
const [isGenerating, setIsGenerating] = useState8(false);
|
|
1646
|
+
const workerRef = useRef8(null);
|
|
1647
|
+
const generatedByBufferRef = useRef8(/* @__PURE__ */ new WeakMap());
|
|
1648
|
+
const inflightByBufferRef = useRef8(/* @__PURE__ */ new WeakMap());
|
|
1649
|
+
const subscribersByBufferRef = useRef8(/* @__PURE__ */ new WeakMap());
|
|
1650
|
+
const pendingCountRef = useRef8(0);
|
|
1651
|
+
const getWorker = useCallback12(() => {
|
|
3233
1652
|
if (!workerRef.current) {
|
|
3234
1653
|
workerRef.current = createPeaksWorker();
|
|
3235
1654
|
}
|
|
3236
1655
|
return workerRef.current;
|
|
3237
1656
|
}, []);
|
|
3238
|
-
|
|
1657
|
+
useEffect4(() => {
|
|
3239
1658
|
let cancelled = false;
|
|
3240
1659
|
const generatedByBuffer = generatedByBufferRef.current;
|
|
3241
1660
|
const inflightByBuffer = inflightByBufferRef.current;
|
|
@@ -3340,7 +1759,7 @@ function useWaveformDataCache(tracks, baseScale) {
|
|
|
3340
1759
|
setIsGenerating(false);
|
|
3341
1760
|
};
|
|
3342
1761
|
}, [tracks, baseScale, getWorker]);
|
|
3343
|
-
|
|
1762
|
+
useEffect4(() => {
|
|
3344
1763
|
return () => {
|
|
3345
1764
|
var _a;
|
|
3346
1765
|
(_a = workerRef.current) == null ? void 0 : _a.terminate();
|
|
@@ -3350,226 +1769,6 @@ function useWaveformDataCache(tracks, baseScale) {
|
|
|
3350
1769
|
return { cache, isGenerating };
|
|
3351
1770
|
}
|
|
3352
1771
|
|
|
3353
|
-
// src/hooks/useDynamicTracks.ts
|
|
3354
|
-
import { useState as useState13, useCallback as useCallback17, useRef as useRef13, useEffect as useEffect8 } from "react";
|
|
3355
|
-
import { createTrack as createTrack2, createClipFromSeconds as createClipFromSeconds2 } from "@waveform-playlist/core";
|
|
3356
|
-
import { getGlobalAudioContext as getGlobalAudioContext3 } from "@waveform-playlist/playout";
|
|
3357
|
-
function getSourceName(source) {
|
|
3358
|
-
var _a, _b, _c, _d, _e;
|
|
3359
|
-
if (source instanceof File) {
|
|
3360
|
-
return source.name.replace(/\.[^/.]+$/, "");
|
|
3361
|
-
}
|
|
3362
|
-
if (source instanceof Blob) {
|
|
3363
|
-
return "Untitled";
|
|
3364
|
-
}
|
|
3365
|
-
if (typeof source === "string") {
|
|
3366
|
-
return (_b = (_a = source.split("/").pop()) == null ? void 0 : _a.replace(/\.[^/.]+$/, "")) != null ? _b : "Untitled";
|
|
3367
|
-
}
|
|
3368
|
-
return (_e = (_d = source.name) != null ? _d : (_c = source.src.split("/").pop()) == null ? void 0 : _c.replace(/\.[^/.]+$/, "")) != null ? _e : "Untitled";
|
|
3369
|
-
}
|
|
3370
|
-
function decodeSource(source, audioContext, signal) {
|
|
3371
|
-
return __async(this, null, function* () {
|
|
3372
|
-
const name = getSourceName(source);
|
|
3373
|
-
if (source instanceof Blob) {
|
|
3374
|
-
const arrayBuffer2 = yield source.arrayBuffer();
|
|
3375
|
-
signal == null ? void 0 : signal.throwIfAborted();
|
|
3376
|
-
const audioBuffer2 = yield audioContext.decodeAudioData(arrayBuffer2);
|
|
3377
|
-
return { audioBuffer: audioBuffer2, name };
|
|
3378
|
-
}
|
|
3379
|
-
const url = typeof source === "string" ? source : source.src;
|
|
3380
|
-
const response = yield fetch(url, { signal });
|
|
3381
|
-
if (!response.ok) throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
|
|
3382
|
-
const arrayBuffer = yield response.arrayBuffer();
|
|
3383
|
-
signal == null ? void 0 : signal.throwIfAborted();
|
|
3384
|
-
const audioBuffer = yield audioContext.decodeAudioData(arrayBuffer);
|
|
3385
|
-
return { audioBuffer, name };
|
|
3386
|
-
});
|
|
3387
|
-
}
|
|
3388
|
-
function useDynamicTracks() {
|
|
3389
|
-
const [tracks, setTracks] = useState13([]);
|
|
3390
|
-
const [loadingCount, setLoadingCount] = useState13(0);
|
|
3391
|
-
const [errors, setErrors] = useState13([]);
|
|
3392
|
-
const cancelledRef = useRef13(false);
|
|
3393
|
-
const loadingIdsRef = useRef13(/* @__PURE__ */ new Set());
|
|
3394
|
-
const abortControllersRef = useRef13(/* @__PURE__ */ new Map());
|
|
3395
|
-
useEffect8(() => {
|
|
3396
|
-
const controllers = abortControllersRef.current;
|
|
3397
|
-
return () => {
|
|
3398
|
-
cancelledRef.current = true;
|
|
3399
|
-
for (const controller of controllers.values()) {
|
|
3400
|
-
controller.abort();
|
|
3401
|
-
}
|
|
3402
|
-
controllers.clear();
|
|
3403
|
-
};
|
|
3404
|
-
}, []);
|
|
3405
|
-
const addTracks = useCallback17((sources) => {
|
|
3406
|
-
if (sources.length === 0) return;
|
|
3407
|
-
const audioContext = getGlobalAudioContext3();
|
|
3408
|
-
const placeholders = sources.map((source) => ({
|
|
3409
|
-
track: createTrack2({ name: `${getSourceName(source)} (loading...)`, clips: [] }),
|
|
3410
|
-
source
|
|
3411
|
-
}));
|
|
3412
|
-
setTracks((prev) => [...prev, ...placeholders.map((p) => p.track)]);
|
|
3413
|
-
setLoadingCount((prev) => prev + sources.length);
|
|
3414
|
-
for (const { track, source } of placeholders) {
|
|
3415
|
-
loadingIdsRef.current.add(track.id);
|
|
3416
|
-
const controller = new AbortController();
|
|
3417
|
-
abortControllersRef.current.set(track.id, controller);
|
|
3418
|
-
(() => __async(null, null, function* () {
|
|
3419
|
-
try {
|
|
3420
|
-
const { audioBuffer, name } = yield decodeSource(source, audioContext, controller.signal);
|
|
3421
|
-
const clip = createClipFromSeconds2({
|
|
3422
|
-
audioBuffer,
|
|
3423
|
-
startTime: 0,
|
|
3424
|
-
duration: audioBuffer.duration,
|
|
3425
|
-
offset: 0,
|
|
3426
|
-
name
|
|
3427
|
-
});
|
|
3428
|
-
if (!cancelledRef.current && loadingIdsRef.current.has(track.id)) {
|
|
3429
|
-
setTracks(
|
|
3430
|
-
(prev) => prev.map((t) => t.id === track.id ? __spreadProps(__spreadValues({}, t), { name, clips: [clip] }) : t)
|
|
3431
|
-
);
|
|
3432
|
-
}
|
|
3433
|
-
} catch (error) {
|
|
3434
|
-
if (error instanceof DOMException && error.name === "AbortError") return;
|
|
3435
|
-
console.warn("[waveform-playlist] Error loading audio:", error);
|
|
3436
|
-
if (!cancelledRef.current && loadingIdsRef.current.has(track.id)) {
|
|
3437
|
-
setTracks((prev) => prev.filter((t) => t.id !== track.id));
|
|
3438
|
-
setErrors((prev) => [
|
|
3439
|
-
...prev,
|
|
3440
|
-
{
|
|
3441
|
-
name: getSourceName(source),
|
|
3442
|
-
error: error instanceof Error ? error : new Error(String(error))
|
|
3443
|
-
}
|
|
3444
|
-
]);
|
|
3445
|
-
}
|
|
3446
|
-
} finally {
|
|
3447
|
-
abortControllersRef.current.delete(track.id);
|
|
3448
|
-
if (!cancelledRef.current && loadingIdsRef.current.delete(track.id)) {
|
|
3449
|
-
setLoadingCount((prev) => prev - 1);
|
|
3450
|
-
}
|
|
3451
|
-
}
|
|
3452
|
-
}))();
|
|
3453
|
-
}
|
|
3454
|
-
}, []);
|
|
3455
|
-
const removeTrack = useCallback17((trackId) => {
|
|
3456
|
-
setTracks((prev) => prev.filter((t) => t.id !== trackId));
|
|
3457
|
-
const controller = abortControllersRef.current.get(trackId);
|
|
3458
|
-
if (controller) {
|
|
3459
|
-
controller.abort();
|
|
3460
|
-
abortControllersRef.current.delete(trackId);
|
|
3461
|
-
}
|
|
3462
|
-
if (loadingIdsRef.current.delete(trackId)) {
|
|
3463
|
-
setLoadingCount((prev) => prev - 1);
|
|
3464
|
-
}
|
|
3465
|
-
}, []);
|
|
3466
|
-
return {
|
|
3467
|
-
tracks,
|
|
3468
|
-
addTracks,
|
|
3469
|
-
removeTrack,
|
|
3470
|
-
loadingCount,
|
|
3471
|
-
isLoading: loadingCount > 0,
|
|
3472
|
-
errors
|
|
3473
|
-
};
|
|
3474
|
-
}
|
|
3475
|
-
|
|
3476
|
-
// src/hooks/useOutputMeter.ts
|
|
3477
|
-
import { useEffect as useEffect9, useState as useState14, useRef as useRef14, useCallback as useCallback18 } from "react";
|
|
3478
|
-
import { getGlobalContext } from "@waveform-playlist/playout";
|
|
3479
|
-
import { gainToNormalized } from "@waveform-playlist/core";
|
|
3480
|
-
import { meterProcessorUrl } from "@waveform-playlist/worklets";
|
|
3481
|
-
var PEAK_DECAY = 0.98;
|
|
3482
|
-
function useOutputMeter(options = {}) {
|
|
3483
|
-
const { channelCount = 2, updateRate = 60, isPlaying = false } = options;
|
|
3484
|
-
const [levels, setLevels] = useState14(() => new Array(channelCount).fill(0));
|
|
3485
|
-
const [peakLevels, setPeakLevels] = useState14(() => new Array(channelCount).fill(0));
|
|
3486
|
-
const [rmsLevels, setRmsLevels] = useState14(() => new Array(channelCount).fill(0));
|
|
3487
|
-
const workletNodeRef = useRef14(null);
|
|
3488
|
-
const smoothedPeakRef = useRef14(new Array(channelCount).fill(0));
|
|
3489
|
-
const [meterError, setMeterError] = useState14(null);
|
|
3490
|
-
const resetPeak = useCallback18(
|
|
3491
|
-
() => setPeakLevels(new Array(channelCount).fill(0)),
|
|
3492
|
-
[channelCount]
|
|
3493
|
-
);
|
|
3494
|
-
useEffect9(() => {
|
|
3495
|
-
if (!isPlaying) {
|
|
3496
|
-
const zeros = new Array(channelCount).fill(0);
|
|
3497
|
-
smoothedPeakRef.current = new Array(channelCount).fill(0);
|
|
3498
|
-
setLevels(zeros);
|
|
3499
|
-
setRmsLevels(zeros);
|
|
3500
|
-
setPeakLevels(zeros);
|
|
3501
|
-
}
|
|
3502
|
-
}, [isPlaying, channelCount]);
|
|
3503
|
-
useEffect9(() => {
|
|
3504
|
-
let isMounted = true;
|
|
3505
|
-
const setup = () => __async(null, null, function* () {
|
|
3506
|
-
const context = getGlobalContext();
|
|
3507
|
-
const rawCtx = context.rawContext;
|
|
3508
|
-
yield rawCtx.audioWorklet.addModule(meterProcessorUrl);
|
|
3509
|
-
if (!isMounted) return;
|
|
3510
|
-
const workletNode = context.createAudioWorkletNode("meter-processor", {
|
|
3511
|
-
channelCount,
|
|
3512
|
-
channelCountMode: "explicit",
|
|
3513
|
-
processorOptions: {
|
|
3514
|
-
numberOfChannels: channelCount,
|
|
3515
|
-
updateRate
|
|
3516
|
-
}
|
|
3517
|
-
});
|
|
3518
|
-
workletNodeRef.current = workletNode;
|
|
3519
|
-
workletNode.onprocessorerror = (event) => {
|
|
3520
|
-
console.warn("[waveform-playlist] Output meter worklet processor error:", String(event));
|
|
3521
|
-
};
|
|
3522
|
-
const destination = context.destination;
|
|
3523
|
-
destination.chain(workletNode);
|
|
3524
|
-
smoothedPeakRef.current = new Array(channelCount).fill(0);
|
|
3525
|
-
workletNode.port.onmessage = (event) => {
|
|
3526
|
-
var _a;
|
|
3527
|
-
if (!isMounted) return;
|
|
3528
|
-
const { peak, rms } = event.data;
|
|
3529
|
-
const smoothed = smoothedPeakRef.current;
|
|
3530
|
-
const peakValues = [];
|
|
3531
|
-
const rmsValues = [];
|
|
3532
|
-
for (let ch = 0; ch < peak.length; ch++) {
|
|
3533
|
-
smoothed[ch] = Math.max(peak[ch], ((_a = smoothed[ch]) != null ? _a : 0) * PEAK_DECAY);
|
|
3534
|
-
peakValues.push(gainToNormalized(smoothed[ch]));
|
|
3535
|
-
rmsValues.push(gainToNormalized(rms[ch]));
|
|
3536
|
-
}
|
|
3537
|
-
setLevels(peakValues);
|
|
3538
|
-
setRmsLevels(rmsValues);
|
|
3539
|
-
setPeakLevels((prev) => peakValues.map((val, i) => {
|
|
3540
|
-
var _a2;
|
|
3541
|
-
return Math.max((_a2 = prev[i]) != null ? _a2 : 0, val);
|
|
3542
|
-
}));
|
|
3543
|
-
};
|
|
3544
|
-
});
|
|
3545
|
-
setup().catch((err) => {
|
|
3546
|
-
console.warn("[waveform-playlist] Failed to set up output meter:", String(err));
|
|
3547
|
-
if (isMounted) {
|
|
3548
|
-
setMeterError(err instanceof Error ? err : new Error(String(err)));
|
|
3549
|
-
}
|
|
3550
|
-
});
|
|
3551
|
-
return () => {
|
|
3552
|
-
isMounted = false;
|
|
3553
|
-
if (workletNodeRef.current) {
|
|
3554
|
-
try {
|
|
3555
|
-
const context = getGlobalContext();
|
|
3556
|
-
context.destination.chain();
|
|
3557
|
-
} catch (err) {
|
|
3558
|
-
console.warn("[waveform-playlist] Failed to restore destination chain:", String(err));
|
|
3559
|
-
}
|
|
3560
|
-
try {
|
|
3561
|
-
workletNodeRef.current.disconnect();
|
|
3562
|
-
workletNodeRef.current.port.close();
|
|
3563
|
-
} catch (err) {
|
|
3564
|
-
console.warn("[waveform-playlist] Output meter disconnect during cleanup:", String(err));
|
|
3565
|
-
}
|
|
3566
|
-
workletNodeRef.current = null;
|
|
3567
|
-
}
|
|
3568
|
-
};
|
|
3569
|
-
}, [channelCount, updateRate]);
|
|
3570
|
-
return { levels, peakLevels, rmsLevels, resetPeak, error: meterError };
|
|
3571
|
-
}
|
|
3572
|
-
|
|
3573
1772
|
// src/WaveformPlaylistContext.tsx
|
|
3574
1773
|
import { jsx } from "react/jsx-runtime";
|
|
3575
1774
|
var PlaybackAnimationContext = createContext(null);
|
|
@@ -3589,6 +1788,7 @@ var WaveformPlaylistProvider = ({
|
|
|
3589
1788
|
annotationList,
|
|
3590
1789
|
effects,
|
|
3591
1790
|
onReady,
|
|
1791
|
+
onError,
|
|
3592
1792
|
onAnnotationUpdate: _onAnnotationUpdate,
|
|
3593
1793
|
onAnnotationsChange,
|
|
3594
1794
|
barWidth = 1,
|
|
@@ -3599,18 +1799,19 @@ var WaveformPlaylistProvider = ({
|
|
|
3599
1799
|
deferEngineRebuild = false,
|
|
3600
1800
|
indefinitePlayback = false,
|
|
3601
1801
|
sampleRate: sampleRateProp,
|
|
1802
|
+
createAdapter,
|
|
3602
1803
|
children
|
|
3603
1804
|
}) => {
|
|
3604
1805
|
var _a, _b, _c, _d;
|
|
3605
1806
|
const progressBarWidth = progressBarWidthProp != null ? progressBarWidthProp : barWidth + barGap;
|
|
3606
|
-
const indefinitePlaybackRef =
|
|
1807
|
+
const indefinitePlaybackRef = useRef9(indefinitePlayback);
|
|
3607
1808
|
indefinitePlaybackRef.current = indefinitePlayback;
|
|
3608
|
-
const stableZoomLevels =
|
|
1809
|
+
const stableZoomLevels = useMemo3(
|
|
3609
1810
|
() => zoomLevels,
|
|
3610
1811
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3611
1812
|
[zoomLevels == null ? void 0 : zoomLevels.join(",")]
|
|
3612
1813
|
);
|
|
3613
|
-
const annotations =
|
|
1814
|
+
const annotations = useMemo3(() => {
|
|
3614
1815
|
if (!(annotationList == null ? void 0 : annotationList.annotations)) return [];
|
|
3615
1816
|
if (process.env.NODE_ENV !== "production" && annotationList.annotations.length > 0) {
|
|
3616
1817
|
const first = annotationList.annotations[0];
|
|
@@ -3623,63 +1824,50 @@ var WaveformPlaylistProvider = ({
|
|
|
3623
1824
|
}
|
|
3624
1825
|
return annotationList.annotations;
|
|
3625
1826
|
}, [annotationList == null ? void 0 : annotationList.annotations]);
|
|
3626
|
-
const annotationsRef =
|
|
1827
|
+
const annotationsRef = useRef9(annotations);
|
|
3627
1828
|
annotationsRef.current = annotations;
|
|
3628
|
-
const [activeAnnotationId, setActiveAnnotationIdState] =
|
|
3629
|
-
const [isPlaying, setIsPlaying] =
|
|
3630
|
-
const [currentTime, setCurrentTime] =
|
|
3631
|
-
const [duration, setDuration] =
|
|
3632
|
-
const [audioBuffers, setAudioBuffers] =
|
|
3633
|
-
const [peaksDataArray, setPeaksDataArray] =
|
|
3634
|
-
const [trackStates, setTrackStates] =
|
|
3635
|
-
const [isAutomaticScroll, setIsAutomaticScroll] =
|
|
3636
|
-
const [continuousPlay, setContinuousPlayState] =
|
|
1829
|
+
const [activeAnnotationId, setActiveAnnotationIdState] = useState9(null);
|
|
1830
|
+
const [isPlaying, setIsPlaying] = useState9(false);
|
|
1831
|
+
const [currentTime, setCurrentTime] = useState9(0);
|
|
1832
|
+
const [duration, setDuration] = useState9(0);
|
|
1833
|
+
const [audioBuffers, setAudioBuffers] = useState9([]);
|
|
1834
|
+
const [peaksDataArray, setPeaksDataArray] = useState9([]);
|
|
1835
|
+
const [trackStates, setTrackStates] = useState9([]);
|
|
1836
|
+
const [isAutomaticScroll, setIsAutomaticScroll] = useState9(automaticScroll);
|
|
1837
|
+
const [continuousPlay, setContinuousPlayState] = useState9(
|
|
3637
1838
|
(_a = annotationList == null ? void 0 : annotationList.isContinuousPlay) != null ? _a : false
|
|
3638
1839
|
);
|
|
3639
|
-
const [linkEndpoints, setLinkEndpoints] =
|
|
3640
|
-
const [annotationsEditable, setAnnotationsEditable] =
|
|
3641
|
-
const [isReady, setIsReady] =
|
|
3642
|
-
const engineRef =
|
|
3643
|
-
const adapterRef =
|
|
3644
|
-
const audioInitializedRef =
|
|
3645
|
-
const isPlayingRef =
|
|
1840
|
+
const [linkEndpoints, setLinkEndpoints] = useState9((_b = annotationList == null ? void 0 : annotationList.linkEndpoints) != null ? _b : false);
|
|
1841
|
+
const [annotationsEditable, setAnnotationsEditable] = useState9((_c = annotationList == null ? void 0 : annotationList.editable) != null ? _c : false);
|
|
1842
|
+
const [isReady, setIsReady] = useState9(false);
|
|
1843
|
+
const engineRef = useRef9(null);
|
|
1844
|
+
const adapterRef = useRef9(null);
|
|
1845
|
+
const audioInitializedRef = useRef9(false);
|
|
1846
|
+
const isPlayingRef = useRef9(false);
|
|
3646
1847
|
isPlayingRef.current = isPlaying;
|
|
3647
|
-
const playStartPositionRef =
|
|
3648
|
-
const currentTimeRef =
|
|
3649
|
-
const visualTimeRef =
|
|
3650
|
-
const tracksRef =
|
|
3651
|
-
const soundFontCacheRef =
|
|
1848
|
+
const playStartPositionRef = useRef9(0);
|
|
1849
|
+
const currentTimeRef = useRef9(0);
|
|
1850
|
+
const visualTimeRef = useRef9(0);
|
|
1851
|
+
const tracksRef = useRef9(tracks);
|
|
1852
|
+
const soundFontCacheRef = useRef9(soundFontCache);
|
|
3652
1853
|
soundFontCacheRef.current = soundFontCache;
|
|
3653
|
-
const trackStatesRef =
|
|
3654
|
-
const playbackStartTimeRef =
|
|
3655
|
-
const audioStartPositionRef =
|
|
3656
|
-
const playbackEndTimeRef =
|
|
3657
|
-
const scrollContainerRef =
|
|
3658
|
-
const isAutomaticScrollRef =
|
|
3659
|
-
const frameCallbacksRef =
|
|
3660
|
-
const continuousPlayRef =
|
|
3661
|
-
const activeAnnotationIdRef =
|
|
3662
|
-
const engineTracksRef =
|
|
3663
|
-
const lastTracksVersionRef =
|
|
3664
|
-
const skipEngineDisposeRef =
|
|
3665
|
-
const isDraggingRef =
|
|
3666
|
-
const prevTracksRef =
|
|
3667
|
-
const samplesPerPixelRef =
|
|
3668
|
-
const [initialSampleRate] =
|
|
3669
|
-
|
|
3670
|
-
try {
|
|
3671
|
-
if (sampleRateProp !== void 0) {
|
|
3672
|
-
return configureGlobalContext({ sampleRate: sampleRateProp });
|
|
3673
|
-
}
|
|
3674
|
-
return getGlobalAudioContext4().sampleRate;
|
|
3675
|
-
} catch (err) {
|
|
3676
|
-
console.warn(
|
|
3677
|
-
"[waveform-playlist] Failed to configure AudioContext: " + String(err) + " \u2014 falling back to " + (sampleRateProp != null ? sampleRateProp : 48e3) + " Hz"
|
|
3678
|
-
);
|
|
3679
|
-
return sampleRateProp != null ? sampleRateProp : 48e3;
|
|
3680
|
-
}
|
|
3681
|
-
});
|
|
3682
|
-
const sampleRateRef = useRef15(initialSampleRate);
|
|
1854
|
+
const trackStatesRef = useRef9(trackStates);
|
|
1855
|
+
const playbackStartTimeRef = useRef9(0);
|
|
1856
|
+
const audioStartPositionRef = useRef9(0);
|
|
1857
|
+
const playbackEndTimeRef = useRef9(null);
|
|
1858
|
+
const scrollContainerRef = useRef9(null);
|
|
1859
|
+
const isAutomaticScrollRef = useRef9(false);
|
|
1860
|
+
const frameCallbacksRef = useRef9(/* @__PURE__ */ new Map());
|
|
1861
|
+
const continuousPlayRef = useRef9((_d = annotationList == null ? void 0 : annotationList.isContinuousPlay) != null ? _d : false);
|
|
1862
|
+
const activeAnnotationIdRef = useRef9(null);
|
|
1863
|
+
const engineTracksRef = useRef9(null);
|
|
1864
|
+
const lastTracksVersionRef = useRef9(0);
|
|
1865
|
+
const skipEngineDisposeRef = useRef9(false);
|
|
1866
|
+
const isDraggingRef = useRef9(false);
|
|
1867
|
+
const prevTracksRef = useRef9([]);
|
|
1868
|
+
const samplesPerPixelRef = useRef9(initialSamplesPerPixel);
|
|
1869
|
+
const [initialSampleRate] = useState9(() => sampleRateProp != null ? sampleRateProp : 48e3);
|
|
1870
|
+
const sampleRateRef = useRef9(initialSampleRate);
|
|
3683
1871
|
const { timeFormat, setTimeFormat, formatTime: formatTime2 } = useTimeFormat();
|
|
3684
1872
|
const zoom = useZoomControls({ engineRef, initialSamplesPerPixel });
|
|
3685
1873
|
const { samplesPerPixel, onEngineState: onZoomEngineState } = zoom;
|
|
@@ -3724,20 +1912,20 @@ var WaveformPlaylistProvider = ({
|
|
|
3724
1912
|
onEngineState: onUndoEngineState
|
|
3725
1913
|
} = useUndoState({ engineRef });
|
|
3726
1914
|
const { animationFrameRef, startAnimationFrameLoop, stopAnimationFrameLoop } = useAnimationFrameLoop();
|
|
3727
|
-
const baseScale =
|
|
1915
|
+
const baseScale = useMemo3(
|
|
3728
1916
|
() => Math.min(...stableZoomLevels != null ? stableZoomLevels : [256, 512, 1024, 2048, 4096, 8192]),
|
|
3729
1917
|
[stableZoomLevels]
|
|
3730
1918
|
);
|
|
3731
1919
|
const { cache: waveformDataCache } = useWaveformDataCache(tracks, baseScale);
|
|
3732
|
-
const setContinuousPlay =
|
|
1920
|
+
const setContinuousPlay = useCallback13((value) => {
|
|
3733
1921
|
continuousPlayRef.current = value;
|
|
3734
1922
|
setContinuousPlayState(value);
|
|
3735
1923
|
}, []);
|
|
3736
|
-
const setActiveAnnotationId =
|
|
1924
|
+
const setActiveAnnotationId = useCallback13((value) => {
|
|
3737
1925
|
activeAnnotationIdRef.current = value;
|
|
3738
1926
|
setActiveAnnotationIdState(value);
|
|
3739
1927
|
}, []);
|
|
3740
|
-
const setLoopRegionFromSelection =
|
|
1928
|
+
const setLoopRegionFromSelection = useCallback13(() => {
|
|
3741
1929
|
var _a2, _b2;
|
|
3742
1930
|
const start = (_a2 = selectionStartRef.current) != null ? _a2 : 0;
|
|
3743
1931
|
const end = (_b2 = selectionEndRef.current) != null ? _b2 : 0;
|
|
@@ -3745,10 +1933,10 @@ var WaveformPlaylistProvider = ({
|
|
|
3745
1933
|
setLoopRegion(start, end);
|
|
3746
1934
|
}
|
|
3747
1935
|
}, [setLoopRegion, selectionStartRef, selectionEndRef]);
|
|
3748
|
-
|
|
1936
|
+
useEffect5(() => {
|
|
3749
1937
|
isAutomaticScrollRef.current = isAutomaticScroll;
|
|
3750
1938
|
}, [isAutomaticScroll]);
|
|
3751
|
-
|
|
1939
|
+
useEffect5(() => {
|
|
3752
1940
|
trackStatesRef.current = trackStates;
|
|
3753
1941
|
}, [trackStates]);
|
|
3754
1942
|
tracksRef.current = tracks;
|
|
@@ -3759,7 +1947,7 @@ var WaveformPlaylistProvider = ({
|
|
|
3759
1947
|
return current === pt;
|
|
3760
1948
|
});
|
|
3761
1949
|
skipEngineDisposeRef.current = isEngineTracks || isDraggingRef.current || isIncrementalAdd;
|
|
3762
|
-
|
|
1950
|
+
useEffect5(() => {
|
|
3763
1951
|
if (!scrollContainerRef.current || duration === 0) return;
|
|
3764
1952
|
const container = scrollContainerRef.current;
|
|
3765
1953
|
const oldSamplesPerPixel = samplesPerPixelRef.current;
|
|
@@ -3775,8 +1963,8 @@ var WaveformPlaylistProvider = ({
|
|
|
3775
1963
|
container.scrollLeft = newScrollLeft;
|
|
3776
1964
|
samplesPerPixelRef.current = newSamplesPerPixel;
|
|
3777
1965
|
}, [samplesPerPixel, duration]);
|
|
3778
|
-
const pendingResumeRef =
|
|
3779
|
-
|
|
1966
|
+
const pendingResumeRef = useRef9(null);
|
|
1967
|
+
useEffect5(() => {
|
|
3780
1968
|
var _a2, _b2, _c2, _d2;
|
|
3781
1969
|
if (isEngineTracks || isDraggingRef.current) {
|
|
3782
1970
|
if (isEngineTracks) {
|
|
@@ -3881,6 +2069,7 @@ var WaveformPlaylistProvider = ({
|
|
|
3881
2069
|
stopAnimationFrameLoop();
|
|
3882
2070
|
pendingResumeRef.current = { position: resumePosition };
|
|
3883
2071
|
}
|
|
2072
|
+
let cancelled = false;
|
|
3884
2073
|
const loadAudio = () => __async(null, null, function* () {
|
|
3885
2074
|
var _a3, _b3, _c3, _d3, _e;
|
|
3886
2075
|
try {
|
|
@@ -3923,7 +2112,17 @@ var WaveformPlaylistProvider = ({
|
|
|
3923
2112
|
lastTracksVersionRef.current = 0;
|
|
3924
2113
|
engineTracksRef.current = null;
|
|
3925
2114
|
audioInitializedRef.current = false;
|
|
3926
|
-
const adapter =
|
|
2115
|
+
const adapter = yield resolvePlayoutAdapter({
|
|
2116
|
+
createAdapter,
|
|
2117
|
+
effects,
|
|
2118
|
+
soundFontCache: soundFontCacheRef.current,
|
|
2119
|
+
sampleRate: sampleRateProp
|
|
2120
|
+
});
|
|
2121
|
+
if (cancelled) {
|
|
2122
|
+
adapter.dispose();
|
|
2123
|
+
return;
|
|
2124
|
+
}
|
|
2125
|
+
sampleRateRef.current = adapter.audioContext.sampleRate;
|
|
3927
2126
|
adapterRef.current = adapter;
|
|
3928
2127
|
const engine = new PlaylistEngine({
|
|
3929
2128
|
adapter,
|
|
@@ -3981,11 +2180,23 @@ var WaveformPlaylistProvider = ({
|
|
|
3981
2180
|
prevTracksRef.current = tracks;
|
|
3982
2181
|
onReady == null ? void 0 : onReady();
|
|
3983
2182
|
} catch (error) {
|
|
3984
|
-
|
|
2183
|
+
if (!engineRef.current && adapterRef.current) {
|
|
2184
|
+
try {
|
|
2185
|
+
adapterRef.current.dispose();
|
|
2186
|
+
} catch (disposeErr) {
|
|
2187
|
+
console.warn(
|
|
2188
|
+
"[waveform-playlist] adapter dispose after load failure threw: " + String(disposeErr)
|
|
2189
|
+
);
|
|
2190
|
+
}
|
|
2191
|
+
adapterRef.current = null;
|
|
2192
|
+
}
|
|
2193
|
+
console.warn("[waveform-playlist] Error loading audio: " + String(error));
|
|
2194
|
+
onError == null ? void 0 : onError(error instanceof Error ? error : new Error(String(error)));
|
|
3985
2195
|
}
|
|
3986
2196
|
});
|
|
3987
2197
|
loadAudio();
|
|
3988
2198
|
return () => {
|
|
2199
|
+
cancelled = true;
|
|
3989
2200
|
if (skipEngineDisposeRef.current) {
|
|
3990
2201
|
skipEngineDisposeRef.current = false;
|
|
3991
2202
|
return;
|
|
@@ -4008,6 +2219,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4008
2219
|
// to the live adapter by the sync effect below; only adapter creation reads it
|
|
4009
2220
|
// (via soundFontCacheRef).
|
|
4010
2221
|
onReady,
|
|
2222
|
+
onError,
|
|
4011
2223
|
effects,
|
|
4012
2224
|
stopAnimationFrameLoop,
|
|
4013
2225
|
onSelectionEngineState,
|
|
@@ -4026,10 +2238,10 @@ var WaveformPlaylistProvider = ({
|
|
|
4026
2238
|
stableZoomLevels,
|
|
4027
2239
|
deferEngineRebuild
|
|
4028
2240
|
]);
|
|
4029
|
-
|
|
2241
|
+
useEffect5(() => {
|
|
4030
2242
|
syncSoundFontCacheToAdapter(adapterRef.current, soundFontCache);
|
|
4031
2243
|
}, [soundFontCache]);
|
|
4032
|
-
|
|
2244
|
+
useEffect5(() => {
|
|
4033
2245
|
if (tracks.length === 0) return;
|
|
4034
2246
|
const allTrackPeaks = tracks.map((track) => {
|
|
4035
2247
|
const clipPeaks = track.clips.map((clip) => {
|
|
@@ -4110,8 +2322,15 @@ var WaveformPlaylistProvider = ({
|
|
|
4110
2322
|
});
|
|
4111
2323
|
setPeaksDataArray(allTrackPeaks);
|
|
4112
2324
|
}, [tracks, samplesPerPixel, mono, waveformDataCache, deferEngineRebuild]);
|
|
4113
|
-
const
|
|
4114
|
-
|
|
2325
|
+
const getAudioContextTime = useCallback13(
|
|
2326
|
+
() => {
|
|
2327
|
+
var _a2, _b2;
|
|
2328
|
+
return (_b2 = (_a2 = adapterRef.current) == null ? void 0 : _a2.audioContext.currentTime) != null ? _b2 : 0;
|
|
2329
|
+
},
|
|
2330
|
+
[]
|
|
2331
|
+
);
|
|
2332
|
+
const getPlaybackTimeFallbackWarnedRef = useRef9(false);
|
|
2333
|
+
const getPlaybackTime = useCallback13(() => {
|
|
4115
2334
|
var _a2, _b2;
|
|
4116
2335
|
if (engineRef.current) {
|
|
4117
2336
|
return engineRef.current.getCurrentTime();
|
|
@@ -4122,30 +2341,35 @@ var WaveformPlaylistProvider = ({
|
|
|
4122
2341
|
"[waveform-playlist] getPlaybackTime called without engine. Falling back to manual elapsed time (loop wrapping will not work)."
|
|
4123
2342
|
);
|
|
4124
2343
|
}
|
|
4125
|
-
const elapsed =
|
|
2344
|
+
const elapsed = getAudioContextTime() - ((_a2 = playbackStartTimeRef.current) != null ? _a2 : 0);
|
|
4126
2345
|
return ((_b2 = audioStartPositionRef.current) != null ? _b2 : 0) + elapsed;
|
|
4127
|
-
}, []);
|
|
4128
|
-
const toVisualTime =
|
|
2346
|
+
}, [getAudioContextTime]);
|
|
2347
|
+
const toVisualTime = useCallback13((rawTime) => {
|
|
4129
2348
|
return Number.isFinite(rawTime) ? Math.max(0, rawTime) : 0;
|
|
4130
2349
|
}, []);
|
|
4131
|
-
const setCurrentTimeRefs =
|
|
2350
|
+
const setCurrentTimeRefs = useCallback13(
|
|
4132
2351
|
(rawTime) => {
|
|
4133
2352
|
currentTimeRef.current = rawTime;
|
|
4134
2353
|
visualTimeRef.current = toVisualTime(rawTime);
|
|
4135
2354
|
},
|
|
4136
2355
|
[toVisualTime]
|
|
4137
2356
|
);
|
|
4138
|
-
const getLookAhead =
|
|
2357
|
+
const getLookAhead = useCallback13(() => {
|
|
4139
2358
|
var _a2, _b2;
|
|
4140
2359
|
return (_b2 = (_a2 = engineRef.current) == null ? void 0 : _a2.lookAhead) != null ? _b2 : 0;
|
|
4141
2360
|
}, []);
|
|
4142
|
-
const
|
|
2361
|
+
const getOutputLatency = useCallback13(() => {
|
|
2362
|
+
var _a2;
|
|
2363
|
+
const audioCtx = (_a2 = adapterRef.current) == null ? void 0 : _a2.audioContext;
|
|
2364
|
+
return audioCtx && "outputLatency" in audioCtx ? audioCtx.outputLatency : 0;
|
|
2365
|
+
}, []);
|
|
2366
|
+
const registerFrameCallback = useCallback13((id, cb) => {
|
|
4143
2367
|
frameCallbacksRef.current.set(id, cb);
|
|
4144
2368
|
}, []);
|
|
4145
|
-
const unregisterFrameCallback =
|
|
2369
|
+
const unregisterFrameCallback = useCallback13((id) => {
|
|
4146
2370
|
frameCallbacksRef.current.delete(id);
|
|
4147
2371
|
}, []);
|
|
4148
|
-
const startAnimationLoop =
|
|
2372
|
+
const startAnimationLoop = useCallback13(() => {
|
|
4149
2373
|
const updateTime = () => {
|
|
4150
2374
|
const time = getPlaybackTime();
|
|
4151
2375
|
currentTimeRef.current = time;
|
|
@@ -4233,15 +2457,14 @@ var WaveformPlaylistProvider = ({
|
|
|
4233
2457
|
setCurrentTimeRefs
|
|
4234
2458
|
]);
|
|
4235
2459
|
const stopAnimationLoop = stopAnimationFrameLoop;
|
|
4236
|
-
|
|
2460
|
+
useEffect5(() => {
|
|
4237
2461
|
const reschedulePlayback = () => __async(null, null, function* () {
|
|
4238
2462
|
if (isPlaying && animationFrameRef.current && engineRef.current) {
|
|
4239
2463
|
if (continuousPlay) {
|
|
4240
2464
|
const currentPos = currentTimeRef.current;
|
|
4241
2465
|
engineRef.current.stop();
|
|
4242
2466
|
stopAnimationLoop();
|
|
4243
|
-
const
|
|
4244
|
-
const timeNow = context.currentTime;
|
|
2467
|
+
const timeNow = getAudioContextTime();
|
|
4245
2468
|
playbackStartTimeRef.current = timeNow;
|
|
4246
2469
|
audioStartPositionRef.current = currentPos;
|
|
4247
2470
|
engineRef.current.play(currentPos);
|
|
@@ -4257,14 +2480,20 @@ var WaveformPlaylistProvider = ({
|
|
|
4257
2480
|
setIsPlaying(false);
|
|
4258
2481
|
stopAnimationLoop();
|
|
4259
2482
|
});
|
|
4260
|
-
}, [
|
|
4261
|
-
|
|
2483
|
+
}, [
|
|
2484
|
+
continuousPlay,
|
|
2485
|
+
isPlaying,
|
|
2486
|
+
startAnimationLoop,
|
|
2487
|
+
stopAnimationLoop,
|
|
2488
|
+
animationFrameRef,
|
|
2489
|
+
getAudioContextTime
|
|
2490
|
+
]);
|
|
2491
|
+
useEffect5(() => {
|
|
4262
2492
|
const resumePlayback = () => __async(null, null, function* () {
|
|
4263
2493
|
if (pendingResumeRef.current && engineRef.current) {
|
|
4264
2494
|
const { position } = pendingResumeRef.current;
|
|
4265
2495
|
pendingResumeRef.current = null;
|
|
4266
|
-
const
|
|
4267
|
-
const timeNow = context.currentTime;
|
|
2496
|
+
const timeNow = getAudioContextTime();
|
|
4268
2497
|
playbackStartTimeRef.current = timeNow;
|
|
4269
2498
|
audioStartPositionRef.current = position;
|
|
4270
2499
|
if (!audioInitializedRef.current) {
|
|
@@ -4281,8 +2510,8 @@ var WaveformPlaylistProvider = ({
|
|
|
4281
2510
|
setIsPlaying(false);
|
|
4282
2511
|
stopAnimationLoop();
|
|
4283
2512
|
});
|
|
4284
|
-
}, [tracks, startAnimationLoop, stopAnimationLoop]);
|
|
4285
|
-
const play =
|
|
2513
|
+
}, [tracks, startAnimationLoop, stopAnimationLoop, getAudioContextTime]);
|
|
2514
|
+
const play = useCallback13(
|
|
4286
2515
|
(startTime, playDuration) => __async(null, null, function* () {
|
|
4287
2516
|
if (!engineRef.current) return;
|
|
4288
2517
|
const actualStartTime = startTime != null ? startTime : currentTimeRef.current;
|
|
@@ -4291,8 +2520,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4291
2520
|
engineRef.current.stop();
|
|
4292
2521
|
engineRef.current.seek(actualStartTime);
|
|
4293
2522
|
stopAnimationLoop();
|
|
4294
|
-
const
|
|
4295
|
-
const startTimeNow = context.currentTime;
|
|
2523
|
+
const startTimeNow = getAudioContextTime();
|
|
4296
2524
|
playbackStartTimeRef.current = startTimeNow;
|
|
4297
2525
|
audioStartPositionRef.current = actualStartTime;
|
|
4298
2526
|
playbackEndTimeRef.current = playDuration !== void 0 ? actualStartTime + playDuration : null;
|
|
@@ -4311,9 +2539,9 @@ var WaveformPlaylistProvider = ({
|
|
|
4311
2539
|
setIsPlaying(true);
|
|
4312
2540
|
startAnimationLoop();
|
|
4313
2541
|
}),
|
|
4314
|
-
[startAnimationLoop, stopAnimationLoop, setCurrentTimeRefs]
|
|
2542
|
+
[startAnimationLoop, stopAnimationLoop, setCurrentTimeRefs, getAudioContextTime]
|
|
4315
2543
|
);
|
|
4316
|
-
const pause =
|
|
2544
|
+
const pause = useCallback13(() => {
|
|
4317
2545
|
if (!engineRef.current) return;
|
|
4318
2546
|
const pauseTime = getPlaybackTime();
|
|
4319
2547
|
engineRef.current.pause();
|
|
@@ -4322,7 +2550,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4322
2550
|
setCurrentTimeRefs(pauseTime);
|
|
4323
2551
|
setCurrentTime(pauseTime);
|
|
4324
2552
|
}, [stopAnimationLoop, getPlaybackTime, setCurrentTimeRefs]);
|
|
4325
|
-
const stop =
|
|
2553
|
+
const stop = useCallback13(() => {
|
|
4326
2554
|
if (!engineRef.current) return;
|
|
4327
2555
|
engineRef.current.stop();
|
|
4328
2556
|
setIsPlaying(false);
|
|
@@ -4331,7 +2559,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4331
2559
|
setCurrentTime(playStartPositionRef.current);
|
|
4332
2560
|
setActiveAnnotationId(null);
|
|
4333
2561
|
}, [stopAnimationLoop, setActiveAnnotationId, setCurrentTimeRefs]);
|
|
4334
|
-
const seekTo =
|
|
2562
|
+
const seekTo = useCallback13(
|
|
4335
2563
|
(time) => {
|
|
4336
2564
|
const clampedTime = Math.max(0, Math.min(time, duration));
|
|
4337
2565
|
setCurrentTimeRefs(clampedTime);
|
|
@@ -4342,7 +2570,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4342
2570
|
},
|
|
4343
2571
|
[duration, isPlaying, play, setCurrentTimeRefs]
|
|
4344
2572
|
);
|
|
4345
|
-
const setTrackMute =
|
|
2573
|
+
const setTrackMute = useCallback13(
|
|
4346
2574
|
(trackIndex, muted) => {
|
|
4347
2575
|
var _a2;
|
|
4348
2576
|
const trackId = (_a2 = tracksRef.current[trackIndex]) == null ? void 0 : _a2.id;
|
|
@@ -4356,7 +2584,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4356
2584
|
},
|
|
4357
2585
|
[trackStates]
|
|
4358
2586
|
);
|
|
4359
|
-
const setTrackSolo =
|
|
2587
|
+
const setTrackSolo = useCallback13(
|
|
4360
2588
|
(trackIndex, soloed) => {
|
|
4361
2589
|
var _a2;
|
|
4362
2590
|
const trackId = (_a2 = tracksRef.current[trackIndex]) == null ? void 0 : _a2.id;
|
|
@@ -4370,7 +2598,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4370
2598
|
},
|
|
4371
2599
|
[trackStates]
|
|
4372
2600
|
);
|
|
4373
|
-
const setTrackVolume =
|
|
2601
|
+
const setTrackVolume = useCallback13(
|
|
4374
2602
|
(trackIndex, volume2) => {
|
|
4375
2603
|
var _a2;
|
|
4376
2604
|
const trackId = (_a2 = tracksRef.current[trackIndex]) == null ? void 0 : _a2.id;
|
|
@@ -4384,7 +2612,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4384
2612
|
},
|
|
4385
2613
|
[trackStates]
|
|
4386
2614
|
);
|
|
4387
|
-
const setTrackPan =
|
|
2615
|
+
const setTrackPan = useCallback13(
|
|
4388
2616
|
(trackIndex, pan) => {
|
|
4389
2617
|
var _a2;
|
|
4390
2618
|
const trackId = (_a2 = tracksRef.current[trackIndex]) == null ? void 0 : _a2.id;
|
|
@@ -4398,7 +2626,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4398
2626
|
},
|
|
4399
2627
|
[trackStates]
|
|
4400
2628
|
);
|
|
4401
|
-
const setSelection =
|
|
2629
|
+
const setSelection = useCallback13(
|
|
4402
2630
|
(start, end) => {
|
|
4403
2631
|
setSelectionEngine(start, end);
|
|
4404
2632
|
setCurrentTimeRefs(start);
|
|
@@ -4411,12 +2639,12 @@ var WaveformPlaylistProvider = ({
|
|
|
4411
2639
|
},
|
|
4412
2640
|
[isPlaying, setSelectionEngine, setCurrentTimeRefs]
|
|
4413
2641
|
);
|
|
4414
|
-
const setScrollContainer =
|
|
2642
|
+
const setScrollContainer = useCallback13((element) => {
|
|
4415
2643
|
scrollContainerRef.current = element;
|
|
4416
2644
|
}, []);
|
|
4417
|
-
const onAnnotationsChangeRef =
|
|
2645
|
+
const onAnnotationsChangeRef = useRef9(onAnnotationsChange);
|
|
4418
2646
|
onAnnotationsChangeRef.current = onAnnotationsChange;
|
|
4419
|
-
const setAnnotations =
|
|
2647
|
+
const setAnnotations = useCallback13(
|
|
4420
2648
|
(action) => {
|
|
4421
2649
|
const updated = typeof action === "function" ? action(annotationsRef.current) : action;
|
|
4422
2650
|
if (!onAnnotationsChangeRef.current) {
|
|
@@ -4434,7 +2662,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4434
2662
|
const sampleRate = sampleRateRef.current;
|
|
4435
2663
|
const timeScaleHeight = timescale ? 30 : 0;
|
|
4436
2664
|
const minimumPlaylistHeight = tracks.length * waveHeight + timeScaleHeight;
|
|
4437
|
-
const animationValue =
|
|
2665
|
+
const animationValue = useMemo3(
|
|
4438
2666
|
() => ({
|
|
4439
2667
|
isPlaying,
|
|
4440
2668
|
currentTime,
|
|
@@ -4443,7 +2671,9 @@ var WaveformPlaylistProvider = ({
|
|
|
4443
2671
|
playbackStartTimeRef,
|
|
4444
2672
|
audioStartPositionRef,
|
|
4445
2673
|
getPlaybackTime,
|
|
2674
|
+
getAudioContextTime,
|
|
4446
2675
|
getLookAhead,
|
|
2676
|
+
getOutputLatency,
|
|
4447
2677
|
registerFrameCallback,
|
|
4448
2678
|
unregisterFrameCallback
|
|
4449
2679
|
}),
|
|
@@ -4455,12 +2685,14 @@ var WaveformPlaylistProvider = ({
|
|
|
4455
2685
|
playbackStartTimeRef,
|
|
4456
2686
|
audioStartPositionRef,
|
|
4457
2687
|
getPlaybackTime,
|
|
2688
|
+
getAudioContextTime,
|
|
4458
2689
|
getLookAhead,
|
|
2690
|
+
getOutputLatency,
|
|
4459
2691
|
registerFrameCallback,
|
|
4460
2692
|
unregisterFrameCallback
|
|
4461
2693
|
]
|
|
4462
2694
|
);
|
|
4463
|
-
const stateValue =
|
|
2695
|
+
const stateValue = useMemo3(
|
|
4464
2696
|
() => ({
|
|
4465
2697
|
continuousPlay,
|
|
4466
2698
|
linkEndpoints,
|
|
@@ -4496,17 +2728,17 @@ var WaveformPlaylistProvider = ({
|
|
|
4496
2728
|
canRedo
|
|
4497
2729
|
]
|
|
4498
2730
|
);
|
|
4499
|
-
const setCurrentTimeControl =
|
|
2731
|
+
const setCurrentTimeControl = useCallback13(
|
|
4500
2732
|
(time) => {
|
|
4501
2733
|
setCurrentTimeRefs(time);
|
|
4502
2734
|
setCurrentTime(time);
|
|
4503
2735
|
},
|
|
4504
2736
|
[setCurrentTimeRefs]
|
|
4505
2737
|
);
|
|
4506
|
-
const setAutomaticScrollControl =
|
|
2738
|
+
const setAutomaticScrollControl = useCallback13((enabled) => {
|
|
4507
2739
|
setIsAutomaticScroll(enabled);
|
|
4508
2740
|
}, []);
|
|
4509
|
-
const controlsValue =
|
|
2741
|
+
const controlsValue = useMemo3(
|
|
4510
2742
|
() => ({
|
|
4511
2743
|
// Playback controls
|
|
4512
2744
|
play,
|
|
@@ -4582,7 +2814,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4582
2814
|
redo
|
|
4583
2815
|
]
|
|
4584
2816
|
);
|
|
4585
|
-
const dataValue =
|
|
2817
|
+
const dataValue = useMemo3(
|
|
4586
2818
|
() => ({
|
|
4587
2819
|
duration,
|
|
4588
2820
|
audioBuffers,
|
|
@@ -4671,14 +2903,38 @@ var usePlaylistDataOptional = () => useContext(PlaylistDataContext);
|
|
|
4671
2903
|
import {
|
|
4672
2904
|
createContext as createContext2,
|
|
4673
2905
|
useContext as useContext2,
|
|
4674
|
-
useState as
|
|
4675
|
-
useEffect as
|
|
4676
|
-
useRef as
|
|
4677
|
-
useCallback as
|
|
4678
|
-
useMemo as
|
|
2906
|
+
useState as useState10,
|
|
2907
|
+
useEffect as useEffect6,
|
|
2908
|
+
useRef as useRef10,
|
|
2909
|
+
useCallback as useCallback14,
|
|
2910
|
+
useMemo as useMemo4
|
|
4679
2911
|
} from "react";
|
|
4680
2912
|
import { ThemeProvider as ThemeProvider2 } from "styled-components";
|
|
4681
|
-
|
|
2913
|
+
|
|
2914
|
+
// src/playout/resolveMediaElementPlayout.ts
|
|
2915
|
+
var INSTALL_HINT2 = "@waveform-playlist/media-element-playout is required for the default MediaElement engine. Install with: npm install @waveform-playlist/media-element-playout \u2014 or pass a custom `createPlayout`.";
|
|
2916
|
+
function resolveMediaElementPlayout(opts) {
|
|
2917
|
+
return __async(this, null, function* () {
|
|
2918
|
+
if (opts.createPlayout) {
|
|
2919
|
+
return opts.createPlayout();
|
|
2920
|
+
}
|
|
2921
|
+
let mod;
|
|
2922
|
+
try {
|
|
2923
|
+
mod = yield import("@waveform-playlist/media-element-playout");
|
|
2924
|
+
} catch (originalErr) {
|
|
2925
|
+
console.warn(
|
|
2926
|
+
"[waveform-playlist] @waveform-playlist/media-element-playout dynamic import failed: " + String(originalErr)
|
|
2927
|
+
);
|
|
2928
|
+
throw new Error(INSTALL_HINT2);
|
|
2929
|
+
}
|
|
2930
|
+
return new mod.MediaElementPlayout({
|
|
2931
|
+
playbackRate: opts.playbackRate,
|
|
2932
|
+
preservesPitch: opts.preservesPitch
|
|
2933
|
+
});
|
|
2934
|
+
});
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2937
|
+
// src/MediaElementPlaylistContext.tsx
|
|
4682
2938
|
import { defaultTheme as defaultTheme2 } from "@waveform-playlist/ui-components";
|
|
4683
2939
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
4684
2940
|
var MediaElementAnimationContext = createContext2(null);
|
|
@@ -4702,16 +2958,18 @@ var MediaElementPlaylistProvider = ({
|
|
|
4702
2958
|
audioContext,
|
|
4703
2959
|
onAnnotationsChange,
|
|
4704
2960
|
onReady,
|
|
2961
|
+
onError,
|
|
2962
|
+
createPlayout,
|
|
4705
2963
|
children
|
|
4706
2964
|
}) => {
|
|
4707
2965
|
var _a;
|
|
4708
2966
|
const progressBarWidth = progressBarWidthProp != null ? progressBarWidthProp : barWidth + barGap;
|
|
4709
|
-
const [isPlaying, setIsPlaying] =
|
|
4710
|
-
const [currentTime, setCurrentTime] =
|
|
4711
|
-
const [duration, setDuration] =
|
|
4712
|
-
const [peaksDataArray, setPeaksDataArray] =
|
|
4713
|
-
const [playbackRate, setPlaybackRateState] =
|
|
4714
|
-
const annotations =
|
|
2967
|
+
const [isPlaying, setIsPlaying] = useState10(false);
|
|
2968
|
+
const [currentTime, setCurrentTime] = useState10(0);
|
|
2969
|
+
const [duration, setDuration] = useState10(0);
|
|
2970
|
+
const [peaksDataArray, setPeaksDataArray] = useState10([]);
|
|
2971
|
+
const [playbackRate, setPlaybackRateState] = useState10(initialPlaybackRate);
|
|
2972
|
+
const annotations = useMemo4(() => {
|
|
4715
2973
|
if (!(annotationList == null ? void 0 : annotationList.annotations)) return [];
|
|
4716
2974
|
if (process.env.NODE_ENV !== "production" && annotationList.annotations.length > 0) {
|
|
4717
2975
|
const first = annotationList.annotations[0];
|
|
@@ -4724,73 +2982,92 @@ var MediaElementPlaylistProvider = ({
|
|
|
4724
2982
|
}
|
|
4725
2983
|
return annotationList.annotations;
|
|
4726
2984
|
}, [annotationList == null ? void 0 : annotationList.annotations]);
|
|
4727
|
-
const annotationsRef =
|
|
2985
|
+
const annotationsRef = useRef10(annotations);
|
|
4728
2986
|
annotationsRef.current = annotations;
|
|
4729
|
-
const [activeAnnotationId, setActiveAnnotationIdState] =
|
|
4730
|
-
const [continuousPlay, setContinuousPlayState] =
|
|
2987
|
+
const [activeAnnotationId, setActiveAnnotationIdState] = useState10(null);
|
|
2988
|
+
const [continuousPlay, setContinuousPlayState] = useState10(
|
|
4731
2989
|
(_a = annotationList == null ? void 0 : annotationList.isContinuousPlay) != null ? _a : false
|
|
4732
2990
|
);
|
|
4733
|
-
const [samplesPerPixel] =
|
|
4734
|
-
const [isAutomaticScroll, setIsAutomaticScroll] =
|
|
4735
|
-
const playoutRef =
|
|
4736
|
-
const currentTimeRef =
|
|
4737
|
-
const continuousPlayRef =
|
|
4738
|
-
const activeAnnotationIdRef =
|
|
4739
|
-
const scrollContainerRef =
|
|
4740
|
-
const isAutomaticScrollRef =
|
|
4741
|
-
const samplesPerPixelRef =
|
|
2991
|
+
const [samplesPerPixel] = useState10(initialSamplesPerPixel);
|
|
2992
|
+
const [isAutomaticScroll, setIsAutomaticScroll] = useState10(automaticScroll);
|
|
2993
|
+
const playoutRef = useRef10(null);
|
|
2994
|
+
const currentTimeRef = useRef10(0);
|
|
2995
|
+
const continuousPlayRef = useRef10(continuousPlay);
|
|
2996
|
+
const activeAnnotationIdRef = useRef10(null);
|
|
2997
|
+
const scrollContainerRef = useRef10(null);
|
|
2998
|
+
const isAutomaticScrollRef = useRef10(automaticScroll);
|
|
2999
|
+
const samplesPerPixelRef = useRef10(initialSamplesPerPixel);
|
|
4742
3000
|
const { startAnimationFrameLoop, stopAnimationFrameLoop } = useAnimationFrameLoop();
|
|
4743
|
-
|
|
3001
|
+
useEffect6(() => {
|
|
4744
3002
|
continuousPlayRef.current = continuousPlay;
|
|
4745
3003
|
}, [continuousPlay]);
|
|
4746
|
-
|
|
3004
|
+
useEffect6(() => {
|
|
4747
3005
|
isAutomaticScrollRef.current = isAutomaticScroll;
|
|
4748
3006
|
}, [isAutomaticScroll]);
|
|
4749
|
-
const setActiveAnnotationId =
|
|
3007
|
+
const setActiveAnnotationId = useCallback14((value) => {
|
|
4750
3008
|
activeAnnotationIdRef.current = value;
|
|
4751
3009
|
setActiveAnnotationIdState(value);
|
|
4752
3010
|
}, []);
|
|
4753
|
-
const setContinuousPlay =
|
|
3011
|
+
const setContinuousPlay = useCallback14((value) => {
|
|
4754
3012
|
continuousPlayRef.current = value;
|
|
4755
3013
|
setContinuousPlayState(value);
|
|
4756
3014
|
}, []);
|
|
4757
|
-
const setScrollContainer =
|
|
3015
|
+
const setScrollContainer = useCallback14((element) => {
|
|
4758
3016
|
scrollContainerRef.current = element;
|
|
4759
3017
|
}, []);
|
|
4760
3018
|
const sampleRate = track.waveformData.sample_rate;
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
3019
|
+
useEffect6(() => {
|
|
3020
|
+
let cancelled = false;
|
|
3021
|
+
let createdPlayout = null;
|
|
3022
|
+
(() => __async(null, null, function* () {
|
|
3023
|
+
var _a2, _b;
|
|
3024
|
+
try {
|
|
3025
|
+
const playout = yield resolveMediaElementPlayout({
|
|
3026
|
+
createPlayout,
|
|
3027
|
+
playbackRate: initialPlaybackRate,
|
|
3028
|
+
preservesPitch
|
|
3029
|
+
});
|
|
3030
|
+
if (cancelled) {
|
|
3031
|
+
playout.dispose();
|
|
3032
|
+
return;
|
|
3033
|
+
}
|
|
3034
|
+
createdPlayout = playout;
|
|
3035
|
+
playout.addTrack({
|
|
3036
|
+
source: track.source,
|
|
3037
|
+
peaks: track.waveformData,
|
|
3038
|
+
name: track.name,
|
|
3039
|
+
audioContext,
|
|
3040
|
+
fadeIn: track.fadeIn,
|
|
3041
|
+
fadeOut: track.fadeOut
|
|
3042
|
+
});
|
|
3043
|
+
const mediaTrack = playout.getTrack((_b = (_a2 = playout["track"]) == null ? void 0 : _a2.id) != null ? _b : "");
|
|
3044
|
+
if (mediaTrack) {
|
|
3045
|
+
mediaTrack.setOnTimeUpdateCallback((time) => {
|
|
3046
|
+
currentTimeRef.current = time;
|
|
3047
|
+
});
|
|
3048
|
+
}
|
|
3049
|
+
playout.setOnPlaybackComplete(() => {
|
|
3050
|
+
stopAnimationFrameLoop();
|
|
3051
|
+
setIsPlaying(false);
|
|
3052
|
+
setActiveAnnotationId(null);
|
|
3053
|
+
currentTimeRef.current = 0;
|
|
3054
|
+
setCurrentTime(0);
|
|
3055
|
+
});
|
|
3056
|
+
playoutRef.current = playout;
|
|
3057
|
+
setDuration(track.waveformData.duration);
|
|
3058
|
+
onReady == null ? void 0 : onReady();
|
|
3059
|
+
} catch (err) {
|
|
3060
|
+
console.warn("[waveform-playlist] MediaElement playout init failed: " + String(err));
|
|
3061
|
+
onError == null ? void 0 : onError(err instanceof Error ? err : new Error(String(err)));
|
|
3062
|
+
}
|
|
3063
|
+
}))();
|
|
4791
3064
|
return () => {
|
|
3065
|
+
cancelled = true;
|
|
4792
3066
|
stopAnimationFrameLoop();
|
|
4793
|
-
|
|
3067
|
+
if (createdPlayout) {
|
|
3068
|
+
createdPlayout.dispose();
|
|
3069
|
+
}
|
|
3070
|
+
playoutRef.current = null;
|
|
4794
3071
|
};
|
|
4795
3072
|
}, [
|
|
4796
3073
|
track.source,
|
|
@@ -4802,10 +3079,12 @@ var MediaElementPlaylistProvider = ({
|
|
|
4802
3079
|
initialPlaybackRate,
|
|
4803
3080
|
preservesPitch,
|
|
4804
3081
|
onReady,
|
|
3082
|
+
onError,
|
|
4805
3083
|
stopAnimationFrameLoop,
|
|
4806
|
-
setActiveAnnotationId
|
|
3084
|
+
setActiveAnnotationId,
|
|
3085
|
+
createPlayout
|
|
4807
3086
|
]);
|
|
4808
|
-
|
|
3087
|
+
useEffect6(() => {
|
|
4809
3088
|
var _a2;
|
|
4810
3089
|
try {
|
|
4811
3090
|
const extractedPeaks = extractPeaksFromWaveformData(
|
|
@@ -4834,7 +3113,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4834
3113
|
console.warn("[waveform-playlist] Failed to extract peaks from waveform data:", err);
|
|
4835
3114
|
}
|
|
4836
3115
|
}, [track.waveformData, track.name, samplesPerPixel, sampleRate]);
|
|
4837
|
-
const startAnimationLoop =
|
|
3116
|
+
const startAnimationLoop = useCallback14(() => {
|
|
4838
3117
|
const updateTime = () => {
|
|
4839
3118
|
var _a2, _b, _c;
|
|
4840
3119
|
const time = (_b = (_a2 = playoutRef.current) == null ? void 0 : _a2.getCurrentTime()) != null ? _b : 0;
|
|
@@ -4877,7 +3156,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4877
3156
|
startAnimationFrameLoop(updateTime);
|
|
4878
3157
|
}, [setActiveAnnotationId, sampleRate, startAnimationFrameLoop]);
|
|
4879
3158
|
const stopAnimationLoop = stopAnimationFrameLoop;
|
|
4880
|
-
const play =
|
|
3159
|
+
const play = useCallback14(
|
|
4881
3160
|
(startTime) => {
|
|
4882
3161
|
if (!playoutRef.current) return;
|
|
4883
3162
|
const actualStartTime = startTime != null ? startTime : currentTimeRef.current;
|
|
@@ -4887,14 +3166,14 @@ var MediaElementPlaylistProvider = ({
|
|
|
4887
3166
|
},
|
|
4888
3167
|
[startAnimationLoop]
|
|
4889
3168
|
);
|
|
4890
|
-
const pause =
|
|
3169
|
+
const pause = useCallback14(() => {
|
|
4891
3170
|
if (!playoutRef.current) return;
|
|
4892
3171
|
playoutRef.current.pause();
|
|
4893
3172
|
setIsPlaying(false);
|
|
4894
3173
|
stopAnimationLoop();
|
|
4895
3174
|
setCurrentTime(playoutRef.current.getCurrentTime());
|
|
4896
3175
|
}, [stopAnimationLoop]);
|
|
4897
|
-
const stop =
|
|
3176
|
+
const stop = useCallback14(() => {
|
|
4898
3177
|
if (!playoutRef.current) return;
|
|
4899
3178
|
playoutRef.current.stop();
|
|
4900
3179
|
setIsPlaying(false);
|
|
@@ -4903,7 +3182,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4903
3182
|
setCurrentTime(0);
|
|
4904
3183
|
setActiveAnnotationId(null);
|
|
4905
3184
|
}, [stopAnimationLoop, setActiveAnnotationId]);
|
|
4906
|
-
const seekTo =
|
|
3185
|
+
const seekTo = useCallback14(
|
|
4907
3186
|
(time) => {
|
|
4908
3187
|
const clampedTime = Math.max(0, Math.min(time, duration));
|
|
4909
3188
|
currentTimeRef.current = clampedTime;
|
|
@@ -4914,7 +3193,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4914
3193
|
},
|
|
4915
3194
|
[duration]
|
|
4916
3195
|
);
|
|
4917
|
-
const setPlaybackRate =
|
|
3196
|
+
const setPlaybackRate = useCallback14((rate) => {
|
|
4918
3197
|
const clampedRate = Math.max(0.5, Math.min(2, rate));
|
|
4919
3198
|
setPlaybackRateState(clampedRate);
|
|
4920
3199
|
if (playoutRef.current) {
|
|
@@ -4922,7 +3201,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4922
3201
|
}
|
|
4923
3202
|
}, []);
|
|
4924
3203
|
const timeScaleHeight = timescale ? 30 : 0;
|
|
4925
|
-
const animationValue =
|
|
3204
|
+
const animationValue = useMemo4(
|
|
4926
3205
|
() => ({
|
|
4927
3206
|
isPlaying,
|
|
4928
3207
|
currentTime,
|
|
@@ -4930,7 +3209,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4930
3209
|
}),
|
|
4931
3210
|
[isPlaying, currentTime]
|
|
4932
3211
|
);
|
|
4933
|
-
const stateValue =
|
|
3212
|
+
const stateValue = useMemo4(
|
|
4934
3213
|
() => ({
|
|
4935
3214
|
continuousPlay,
|
|
4936
3215
|
annotations,
|
|
@@ -4940,9 +3219,9 @@ var MediaElementPlaylistProvider = ({
|
|
|
4940
3219
|
}),
|
|
4941
3220
|
[continuousPlay, annotations, activeAnnotationId, playbackRate, isAutomaticScroll]
|
|
4942
3221
|
);
|
|
4943
|
-
const onAnnotationsChangeRef =
|
|
3222
|
+
const onAnnotationsChangeRef = useRef10(onAnnotationsChange);
|
|
4944
3223
|
onAnnotationsChangeRef.current = onAnnotationsChange;
|
|
4945
|
-
const setAnnotations =
|
|
3224
|
+
const setAnnotations = useCallback14(
|
|
4946
3225
|
(action) => {
|
|
4947
3226
|
const updated = typeof action === "function" ? action(annotationsRef.current) : action;
|
|
4948
3227
|
if (!onAnnotationsChangeRef.current) {
|
|
@@ -4957,7 +3236,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4957
3236
|
},
|
|
4958
3237
|
[]
|
|
4959
3238
|
);
|
|
4960
|
-
const controlsValue =
|
|
3239
|
+
const controlsValue = useMemo4(
|
|
4961
3240
|
() => ({
|
|
4962
3241
|
play,
|
|
4963
3242
|
pause,
|
|
@@ -4985,7 +3264,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4985
3264
|
setScrollContainer
|
|
4986
3265
|
]
|
|
4987
3266
|
);
|
|
4988
|
-
const dataValue =
|
|
3267
|
+
const dataValue = useMemo4(
|
|
4989
3268
|
() => ({
|
|
4990
3269
|
duration,
|
|
4991
3270
|
peaksDataArray,
|
|
@@ -5049,7 +3328,7 @@ var useMediaElementData = () => {
|
|
|
5049
3328
|
};
|
|
5050
3329
|
|
|
5051
3330
|
// src/components/PlaybackControls.tsx
|
|
5052
|
-
import { useCallback as
|
|
3331
|
+
import { useCallback as useCallback15 } from "react";
|
|
5053
3332
|
import { BaseControlButton } from "@waveform-playlist/ui-components";
|
|
5054
3333
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
5055
3334
|
var PlayButton = ({ className }) => {
|
|
@@ -5185,7 +3464,7 @@ var ClearAllButton = ({
|
|
|
5185
3464
|
className
|
|
5186
3465
|
}) => {
|
|
5187
3466
|
const { stop } = usePlaylistControls();
|
|
5188
|
-
const handleClick =
|
|
3467
|
+
const handleClick = useCallback15(() => {
|
|
5189
3468
|
stop();
|
|
5190
3469
|
onClearAll();
|
|
5191
3470
|
}, [stop, onClearAll]);
|
|
@@ -5213,7 +3492,7 @@ var ZoomOutButton = ({
|
|
|
5213
3492
|
};
|
|
5214
3493
|
|
|
5215
3494
|
// src/components/ContextualControls.tsx
|
|
5216
|
-
import { useRef as
|
|
3495
|
+
import { useRef as useRef11, useEffect as useEffect7 } from "react";
|
|
5217
3496
|
import {
|
|
5218
3497
|
MasterVolumeControl as BaseMasterVolumeControl,
|
|
5219
3498
|
TimeFormatSelect as BaseTimeFormatSelect,
|
|
@@ -5252,10 +3531,10 @@ var PositionDisplay = styled.span`
|
|
|
5252
3531
|
`;
|
|
5253
3532
|
var AudioPosition = ({ className }) => {
|
|
5254
3533
|
var _a;
|
|
5255
|
-
const timeRef =
|
|
3534
|
+
const timeRef = useRef11(null);
|
|
5256
3535
|
const { isPlaying, currentTimeRef, registerFrameCallback, unregisterFrameCallback } = usePlaybackAnimation();
|
|
5257
3536
|
const { timeFormat: format } = usePlaylistData();
|
|
5258
|
-
|
|
3537
|
+
useEffect7(() => {
|
|
5259
3538
|
const id = "audio-position";
|
|
5260
3539
|
if (isPlaying) {
|
|
5261
3540
|
registerFrameCallback(id, ({ time }) => {
|
|
@@ -5266,7 +3545,7 @@ var AudioPosition = ({ className }) => {
|
|
|
5266
3545
|
}
|
|
5267
3546
|
return () => unregisterFrameCallback(id);
|
|
5268
3547
|
}, [isPlaying, format, registerFrameCallback, unregisterFrameCallback]);
|
|
5269
|
-
|
|
3548
|
+
useEffect7(() => {
|
|
5270
3549
|
var _a2;
|
|
5271
3550
|
if (!isPlaying && timeRef.current) {
|
|
5272
3551
|
timeRef.current.textContent = formatTime((_a2 = currentTimeRef.current) != null ? _a2 : 0, format);
|
|
@@ -5343,53 +3622,6 @@ var DownloadAnnotationsButton = ({
|
|
|
5343
3622
|
return /* @__PURE__ */ jsx6(Base, { annotations, filename, className });
|
|
5344
3623
|
};
|
|
5345
3624
|
|
|
5346
|
-
// src/components/ExportControls.tsx
|
|
5347
|
-
import { BaseControlButton as BaseControlButton3 } from "@waveform-playlist/ui-components";
|
|
5348
|
-
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
5349
|
-
var ExportWavButton = ({
|
|
5350
|
-
label = "Export WAV",
|
|
5351
|
-
filename = "export",
|
|
5352
|
-
mode = "master",
|
|
5353
|
-
trackIndex,
|
|
5354
|
-
bitDepth = 16,
|
|
5355
|
-
applyEffects = true,
|
|
5356
|
-
effectsFunction,
|
|
5357
|
-
createOfflineTrackEffects,
|
|
5358
|
-
className,
|
|
5359
|
-
onExportComplete,
|
|
5360
|
-
onExportError
|
|
5361
|
-
}) => {
|
|
5362
|
-
const { tracks, trackStates } = usePlaylistData();
|
|
5363
|
-
const { exportWav, isExporting, progress } = useExportWav();
|
|
5364
|
-
const handleExport = () => __async(null, null, function* () {
|
|
5365
|
-
try {
|
|
5366
|
-
const result = yield exportWav(tracks, trackStates, {
|
|
5367
|
-
filename,
|
|
5368
|
-
mode,
|
|
5369
|
-
trackIndex,
|
|
5370
|
-
bitDepth,
|
|
5371
|
-
applyEffects,
|
|
5372
|
-
effectsFunction,
|
|
5373
|
-
createOfflineTrackEffects,
|
|
5374
|
-
autoDownload: true
|
|
5375
|
-
});
|
|
5376
|
-
onExportComplete == null ? void 0 : onExportComplete(result.blob);
|
|
5377
|
-
} catch (error) {
|
|
5378
|
-
onExportError == null ? void 0 : onExportError(error instanceof Error ? error : new Error("Export failed"));
|
|
5379
|
-
}
|
|
5380
|
-
});
|
|
5381
|
-
const buttonLabel = isExporting ? `Exporting ${Math.round(progress * 100)}%` : label;
|
|
5382
|
-
return /* @__PURE__ */ jsx7(
|
|
5383
|
-
BaseControlButton3,
|
|
5384
|
-
{
|
|
5385
|
-
onClick: handleExport,
|
|
5386
|
-
disabled: isExporting || tracks.length === 0,
|
|
5387
|
-
className,
|
|
5388
|
-
children: buttonLabel
|
|
5389
|
-
}
|
|
5390
|
-
);
|
|
5391
|
-
};
|
|
5392
|
-
|
|
5393
3625
|
// src/contexts/ClipInteractionContext.tsx
|
|
5394
3626
|
import { createContext as createContext4, useContext as useContext4 } from "react";
|
|
5395
3627
|
var ClipInteractionContext = createContext4(false);
|
|
@@ -5399,10 +3631,9 @@ function useClipInteractionEnabled() {
|
|
|
5399
3631
|
}
|
|
5400
3632
|
|
|
5401
3633
|
// src/components/PlaylistVisualization.tsx
|
|
5402
|
-
import { useContext as useContext6, useRef as
|
|
3634
|
+
import { useContext as useContext6, useRef as useRef14, useState as useState11, useMemo as useMemo5, useCallback as useCallback16 } from "react";
|
|
5403
3635
|
import { createPortal } from "react-dom";
|
|
5404
3636
|
import styled4 from "styled-components";
|
|
5405
|
-
import { getGlobalAudioContext as getGlobalAudioContext5 } from "@waveform-playlist/playout";
|
|
5406
3637
|
import {
|
|
5407
3638
|
Playlist,
|
|
5408
3639
|
Track as TrackComponent,
|
|
@@ -5430,9 +3661,9 @@ import {
|
|
|
5430
3661
|
import { audibleLatencySamples } from "@waveform-playlist/core";
|
|
5431
3662
|
|
|
5432
3663
|
// src/components/AnimatedPlayhead.tsx
|
|
5433
|
-
import { useRef as
|
|
3664
|
+
import { useRef as useRef12, useEffect as useEffect8 } from "react";
|
|
5434
3665
|
import styled2 from "styled-components";
|
|
5435
|
-
import { jsx as
|
|
3666
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
5436
3667
|
var PlayheadLine = styled2.div.attrs((props) => ({
|
|
5437
3668
|
style: {
|
|
5438
3669
|
width: `${props.$width}px`,
|
|
@@ -5448,7 +3679,7 @@ var PlayheadLine = styled2.div.attrs((props) => ({
|
|
|
5448
3679
|
will-change: transform;
|
|
5449
3680
|
`;
|
|
5450
3681
|
var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
5451
|
-
const playheadRef =
|
|
3682
|
+
const playheadRef = useRef12(null);
|
|
5452
3683
|
const {
|
|
5453
3684
|
isPlaying,
|
|
5454
3685
|
currentTimeRef,
|
|
@@ -5457,7 +3688,7 @@ var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
|
5457
3688
|
unregisterFrameCallback
|
|
5458
3689
|
} = usePlaybackAnimation();
|
|
5459
3690
|
const { samplesPerPixel, sampleRate, progressBarWidth } = usePlaylistData();
|
|
5460
|
-
|
|
3691
|
+
useEffect8(() => {
|
|
5461
3692
|
const id = "playhead";
|
|
5462
3693
|
if (isPlaying) {
|
|
5463
3694
|
registerFrameCallback(id, ({ visualTime, sampleRate: sr, samplesPerPixel: spp }) => {
|
|
@@ -5469,7 +3700,7 @@ var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
|
5469
3700
|
}
|
|
5470
3701
|
return () => unregisterFrameCallback(id);
|
|
5471
3702
|
}, [isPlaying, registerFrameCallback, unregisterFrameCallback]);
|
|
5472
|
-
|
|
3703
|
+
useEffect8(() => {
|
|
5473
3704
|
var _a, _b;
|
|
5474
3705
|
if (!isPlaying && playheadRef.current) {
|
|
5475
3706
|
const time = (_b = (_a = visualTimeRef.current) != null ? _a : currentTimeRef.current) != null ? _b : 0;
|
|
@@ -5477,11 +3708,11 @@ var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
|
5477
3708
|
playheadRef.current.style.transform = `translate3d(${position}px, 0, 0)`;
|
|
5478
3709
|
}
|
|
5479
3710
|
});
|
|
5480
|
-
return /* @__PURE__ */
|
|
3711
|
+
return /* @__PURE__ */ jsx7(PlayheadLine, { ref: playheadRef, $color: color, $width: progressBarWidth, "data-playhead": true });
|
|
5481
3712
|
};
|
|
5482
3713
|
|
|
5483
3714
|
// src/components/ChannelWithProgress.tsx
|
|
5484
|
-
import { useId, useRef as
|
|
3715
|
+
import { useId, useRef as useRef13, useEffect as useEffect9 } from "react";
|
|
5485
3716
|
import styled3 from "styled-components";
|
|
5486
3717
|
import {
|
|
5487
3718
|
clipPixelWidth as computeClipPixelWidth
|
|
@@ -5492,7 +3723,7 @@ import {
|
|
|
5492
3723
|
usePlaylistInfo,
|
|
5493
3724
|
waveformColorToCss
|
|
5494
3725
|
} from "@waveform-playlist/ui-components";
|
|
5495
|
-
import { Fragment, jsx as
|
|
3726
|
+
import { Fragment, jsx as jsx8, jsxs } from "react/jsx-runtime";
|
|
5496
3727
|
var ChannelWrapper = styled3.div`
|
|
5497
3728
|
position: relative;
|
|
5498
3729
|
`;
|
|
@@ -5546,7 +3777,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5546
3777
|
"clipSampleRate",
|
|
5547
3778
|
"clipOffsetSeconds"
|
|
5548
3779
|
]);
|
|
5549
|
-
const progressRef =
|
|
3780
|
+
const progressRef = useRef13(null);
|
|
5550
3781
|
const callbackId = useId();
|
|
5551
3782
|
const theme = useTheme();
|
|
5552
3783
|
const { waveHeight } = usePlaylistInfo();
|
|
@@ -5564,7 +3795,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5564
3795
|
clipDurationSamples,
|
|
5565
3796
|
samplesPerPixel
|
|
5566
3797
|
);
|
|
5567
|
-
|
|
3798
|
+
useEffect9(() => {
|
|
5568
3799
|
if (isPlaying) {
|
|
5569
3800
|
registerFrameCallback(callbackId, ({ visualTime, sampleRate: sr }) => {
|
|
5570
3801
|
if (progressRef.current) {
|
|
@@ -5592,7 +3823,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5592
3823
|
registerFrameCallback,
|
|
5593
3824
|
unregisterFrameCallback
|
|
5594
3825
|
]);
|
|
5595
|
-
|
|
3826
|
+
useEffect9(() => {
|
|
5596
3827
|
var _a2, _b2;
|
|
5597
3828
|
if (!isPlaying && progressRef.current) {
|
|
5598
3829
|
const currentTime = (_b2 = (_a2 = visualTimeRef.current) != null ? _a2 : currentTimeRef.current) != null ? _b2 : 0;
|
|
@@ -5627,7 +3858,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5627
3858
|
const waveformBackgroundCss = waveformColorToCss(backgroundColor);
|
|
5628
3859
|
return /* @__PURE__ */ jsxs(ChannelWrapper, { children: [
|
|
5629
3860
|
isBothMode ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5630
|
-
/* @__PURE__ */
|
|
3861
|
+
/* @__PURE__ */ jsx8(
|
|
5631
3862
|
Background,
|
|
5632
3863
|
{
|
|
5633
3864
|
$color: "#000",
|
|
@@ -5636,7 +3867,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5636
3867
|
$width: smartChannelProps.length
|
|
5637
3868
|
}
|
|
5638
3869
|
),
|
|
5639
|
-
/* @__PURE__ */
|
|
3870
|
+
/* @__PURE__ */ jsx8(
|
|
5640
3871
|
Background,
|
|
5641
3872
|
{
|
|
5642
3873
|
$color: waveformBackgroundCss,
|
|
@@ -5645,7 +3876,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5645
3876
|
$width: smartChannelProps.length
|
|
5646
3877
|
}
|
|
5647
3878
|
)
|
|
5648
|
-
] }) : /* @__PURE__ */
|
|
3879
|
+
] }) : /* @__PURE__ */ jsx8(
|
|
5649
3880
|
Background,
|
|
5650
3881
|
{
|
|
5651
3882
|
$color: backgroundCss,
|
|
@@ -5654,7 +3885,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5654
3885
|
$width: smartChannelProps.length
|
|
5655
3886
|
}
|
|
5656
3887
|
),
|
|
5657
|
-
!isPianoRollMode && /* @__PURE__ */
|
|
3888
|
+
!isPianoRollMode && /* @__PURE__ */ jsx8(
|
|
5658
3889
|
ProgressOverlay,
|
|
5659
3890
|
{
|
|
5660
3891
|
ref: progressRef,
|
|
@@ -5664,7 +3895,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5664
3895
|
$width: clipPixelWidth
|
|
5665
3896
|
}
|
|
5666
3897
|
),
|
|
5667
|
-
/* @__PURE__ */
|
|
3898
|
+
/* @__PURE__ */ jsx8(ChannelContainer, { children: /* @__PURE__ */ jsx8(
|
|
5668
3899
|
SmartChannel,
|
|
5669
3900
|
__spreadProps(__spreadValues({}, smartChannelProps), {
|
|
5670
3901
|
transparentBackground: true,
|
|
@@ -5691,7 +3922,7 @@ function useSpectrogramIntegration() {
|
|
|
5691
3922
|
}
|
|
5692
3923
|
|
|
5693
3924
|
// src/components/PlaylistVisualization.tsx
|
|
5694
|
-
import { Fragment as Fragment2, jsx as
|
|
3925
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
5695
3926
|
var DEFAULT_EMPTY_TRACK_DURATION = 60;
|
|
5696
3927
|
var ControlSlot = styled4.div.attrs((props) => ({
|
|
5697
3928
|
style: { height: `${props.$height}px` }
|
|
@@ -5710,7 +3941,8 @@ var CustomPlayhead = ({ renderPlayhead, color, samplesPerPixel, sampleRate }) =>
|
|
|
5710
3941
|
visualTimeRef,
|
|
5711
3942
|
playbackStartTimeRef,
|
|
5712
3943
|
audioStartPositionRef,
|
|
5713
|
-
getPlaybackTime
|
|
3944
|
+
getPlaybackTime,
|
|
3945
|
+
getAudioContextTime
|
|
5714
3946
|
} = usePlaybackAnimation();
|
|
5715
3947
|
const visualTime = (_b = (_a = visualTimeRef.current) != null ? _a : currentTimeRef.current) != null ? _b : 0;
|
|
5716
3948
|
return renderPlayhead({
|
|
@@ -5724,7 +3956,7 @@ var CustomPlayhead = ({ renderPlayhead, color, samplesPerPixel, sampleRate }) =>
|
|
|
5724
3956
|
samplesPerPixel,
|
|
5725
3957
|
sampleRate,
|
|
5726
3958
|
controlsOffset: 0,
|
|
5727
|
-
getAudioContextTime
|
|
3959
|
+
getAudioContextTime,
|
|
5728
3960
|
getPlaybackTime
|
|
5729
3961
|
});
|
|
5730
3962
|
};
|
|
@@ -5749,7 +3981,7 @@ var PlaylistVisualization = ({
|
|
|
5749
3981
|
}) => {
|
|
5750
3982
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
5751
3983
|
const theme = useTheme2();
|
|
5752
|
-
const { isPlaying, getLookAhead } = usePlaybackAnimation();
|
|
3984
|
+
const { isPlaying, getLookAhead, getOutputLatency } = usePlaybackAnimation();
|
|
5753
3985
|
const {
|
|
5754
3986
|
selectionStart,
|
|
5755
3987
|
selectionEnd,
|
|
@@ -5795,7 +4027,7 @@ var PlaylistVisualization = ({
|
|
|
5795
4027
|
mono
|
|
5796
4028
|
} = usePlaylistData();
|
|
5797
4029
|
const spectrogram = useContext6(SpectrogramIntegrationContext);
|
|
5798
|
-
const perTrackSpectrogramHelpers =
|
|
4030
|
+
const perTrackSpectrogramHelpers = useMemo5(() => {
|
|
5799
4031
|
if (!spectrogram)
|
|
5800
4032
|
return /* @__PURE__ */ new Map();
|
|
5801
4033
|
const helpers = /* @__PURE__ */ new Map();
|
|
@@ -5814,11 +4046,11 @@ var PlaylistVisualization = ({
|
|
|
5814
4046
|
});
|
|
5815
4047
|
return helpers;
|
|
5816
4048
|
}, [tracks, spectrogram]);
|
|
5817
|
-
const [settingsModalTrackId, setSettingsModalTrackId] =
|
|
5818
|
-
const [isSelecting, setIsSelecting] =
|
|
5819
|
-
const mouseDownTimeRef =
|
|
5820
|
-
const scrollContainerRef =
|
|
5821
|
-
const handleScrollContainerRef =
|
|
4049
|
+
const [settingsModalTrackId, setSettingsModalTrackId] = useState11(null);
|
|
4050
|
+
const [isSelecting, setIsSelecting] = useState11(false);
|
|
4051
|
+
const mouseDownTimeRef = useRef14(0);
|
|
4052
|
+
const scrollContainerRef = useRef14(null);
|
|
4053
|
+
const handleScrollContainerRef = useCallback16(
|
|
5822
4054
|
(element) => {
|
|
5823
4055
|
scrollContainerRef.current = element;
|
|
5824
4056
|
setScrollContainer(element);
|
|
@@ -5856,7 +4088,7 @@ var PlaylistVisualization = ({
|
|
|
5856
4088
|
);
|
|
5857
4089
|
}
|
|
5858
4090
|
});
|
|
5859
|
-
const selectTrack =
|
|
4091
|
+
const selectTrack = useCallback16(
|
|
5860
4092
|
(trackIndex) => {
|
|
5861
4093
|
if (trackIndex >= 0 && trackIndex < tracks.length) {
|
|
5862
4094
|
const track = tracks[trackIndex];
|
|
@@ -5926,7 +4158,7 @@ var PlaylistVisualization = ({
|
|
|
5926
4158
|
};
|
|
5927
4159
|
const hasClips = tracks.some((track) => track.clips.length > 0);
|
|
5928
4160
|
if (hasClips && peaksDataArray.length === 0) {
|
|
5929
|
-
return /* @__PURE__ */
|
|
4161
|
+
return /* @__PURE__ */ jsx9("div", { className, children: "Loading waveform..." });
|
|
5930
4162
|
}
|
|
5931
4163
|
const trackControlsSlots = controls.show ? peaksDataArray.map((trackClipPeaks, trackIndex) => {
|
|
5932
4164
|
var _a2, _b2, _c2;
|
|
@@ -5945,7 +4177,7 @@ var PlaylistVisualization = ({
|
|
|
5945
4177
|
const slotHeight = waveHeight * maxChannels + (showClipHeaders ? CLIP_HEADER_HEIGHT : 0);
|
|
5946
4178
|
const trackControlContent = renderTrackControls ? renderTrackControls(trackIndex) : /* @__PURE__ */ jsxs2(Controls, { onClick: () => selectTrack(trackIndex), children: [
|
|
5947
4179
|
/* @__PURE__ */ jsxs2(Header, { style: { justifyContent: "center", position: "relative" }, children: [
|
|
5948
|
-
onRemoveTrack && /* @__PURE__ */
|
|
4180
|
+
onRemoveTrack && /* @__PURE__ */ jsx9(
|
|
5949
4181
|
CloseButton,
|
|
5950
4182
|
{
|
|
5951
4183
|
onClick: (e) => {
|
|
@@ -5954,7 +4186,7 @@ var PlaylistVisualization = ({
|
|
|
5954
4186
|
}
|
|
5955
4187
|
}
|
|
5956
4188
|
),
|
|
5957
|
-
/* @__PURE__ */
|
|
4189
|
+
/* @__PURE__ */ jsx9(
|
|
5958
4190
|
"span",
|
|
5959
4191
|
{
|
|
5960
4192
|
style: {
|
|
@@ -5967,7 +4199,7 @@ var PlaylistVisualization = ({
|
|
|
5967
4199
|
children: trackState.name || `Track ${trackIndex + 1}`
|
|
5968
4200
|
}
|
|
5969
4201
|
),
|
|
5970
|
-
(spectrogram == null ? void 0 : spectrogram.renderMenuItems) && /* @__PURE__ */
|
|
4202
|
+
(spectrogram == null ? void 0 : spectrogram.renderMenuItems) && /* @__PURE__ */ jsx9("span", { style: { position: "absolute", right: 0, top: 0 }, children: /* @__PURE__ */ jsx9(
|
|
5971
4203
|
TrackMenu,
|
|
5972
4204
|
{
|
|
5973
4205
|
items: (onClose) => spectrogram.renderMenuItems({
|
|
@@ -5980,7 +4212,7 @@ var PlaylistVisualization = ({
|
|
|
5980
4212
|
) })
|
|
5981
4213
|
] }),
|
|
5982
4214
|
/* @__PURE__ */ jsxs2(ButtonGroup, { children: [
|
|
5983
|
-
/* @__PURE__ */
|
|
4215
|
+
/* @__PURE__ */ jsx9(
|
|
5984
4216
|
Button,
|
|
5985
4217
|
{
|
|
5986
4218
|
$variant: trackState.muted ? "danger" : "outline",
|
|
@@ -5988,7 +4220,7 @@ var PlaylistVisualization = ({
|
|
|
5988
4220
|
children: "Mute"
|
|
5989
4221
|
}
|
|
5990
4222
|
),
|
|
5991
|
-
/* @__PURE__ */
|
|
4223
|
+
/* @__PURE__ */ jsx9(
|
|
5992
4224
|
Button,
|
|
5993
4225
|
{
|
|
5994
4226
|
$variant: trackState.soloed ? "info" : "outline",
|
|
@@ -5998,8 +4230,8 @@ var PlaylistVisualization = ({
|
|
|
5998
4230
|
)
|
|
5999
4231
|
] }),
|
|
6000
4232
|
/* @__PURE__ */ jsxs2(SliderWrapper, { children: [
|
|
6001
|
-
/* @__PURE__ */
|
|
6002
|
-
/* @__PURE__ */
|
|
4233
|
+
/* @__PURE__ */ jsx9(VolumeDownIcon, {}),
|
|
4234
|
+
/* @__PURE__ */ jsx9(
|
|
6003
4235
|
Slider,
|
|
6004
4236
|
{
|
|
6005
4237
|
min: "0",
|
|
@@ -6009,11 +4241,11 @@ var PlaylistVisualization = ({
|
|
|
6009
4241
|
onChange: (e) => setTrackVolume(trackIndex, parseFloat(e.target.value))
|
|
6010
4242
|
}
|
|
6011
4243
|
),
|
|
6012
|
-
/* @__PURE__ */
|
|
4244
|
+
/* @__PURE__ */ jsx9(VolumeUpIcon, {})
|
|
6013
4245
|
] }),
|
|
6014
4246
|
/* @__PURE__ */ jsxs2(SliderWrapper, { children: [
|
|
6015
|
-
/* @__PURE__ */
|
|
6016
|
-
/* @__PURE__ */
|
|
4247
|
+
/* @__PURE__ */ jsx9("span", { children: "L" }),
|
|
4248
|
+
/* @__PURE__ */ jsx9(
|
|
6017
4249
|
Slider,
|
|
6018
4250
|
{
|
|
6019
4251
|
min: "-1",
|
|
@@ -6023,10 +4255,10 @@ var PlaylistVisualization = ({
|
|
|
6023
4255
|
onChange: (e) => setTrackPan(trackIndex, parseFloat(e.target.value))
|
|
6024
4256
|
}
|
|
6025
4257
|
),
|
|
6026
|
-
/* @__PURE__ */
|
|
4258
|
+
/* @__PURE__ */ jsx9("span", { children: "R" })
|
|
6027
4259
|
] })
|
|
6028
4260
|
] });
|
|
6029
|
-
return /* @__PURE__ */
|
|
4261
|
+
return /* @__PURE__ */ jsx9(
|
|
6030
4262
|
ControlSlot,
|
|
6031
4263
|
{
|
|
6032
4264
|
$height: slotHeight,
|
|
@@ -6037,7 +4269,7 @@ var PlaylistVisualization = ({
|
|
|
6037
4269
|
);
|
|
6038
4270
|
}) : void 0;
|
|
6039
4271
|
return /* @__PURE__ */ jsxs2(DevicePixelRatioProvider, { children: [
|
|
6040
|
-
/* @__PURE__ */
|
|
4272
|
+
/* @__PURE__ */ jsx9(
|
|
6041
4273
|
PlaylistInfoContext.Provider,
|
|
6042
4274
|
{
|
|
6043
4275
|
value: {
|
|
@@ -6051,7 +4283,7 @@ var PlaylistVisualization = ({
|
|
|
6051
4283
|
barWidth,
|
|
6052
4284
|
barGap
|
|
6053
4285
|
},
|
|
6054
|
-
children: /* @__PURE__ */
|
|
4286
|
+
children: /* @__PURE__ */ jsx9(
|
|
6055
4287
|
Playlist,
|
|
6056
4288
|
{
|
|
6057
4289
|
theme,
|
|
@@ -6069,8 +4301,8 @@ var PlaylistVisualization = ({
|
|
|
6069
4301
|
trackControlsSlots,
|
|
6070
4302
|
timescaleGapHeight: timeScaleHeight > 0 ? timeScaleHeight + 1 : 0,
|
|
6071
4303
|
timescale: timeScaleHeight > 0 ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
6072
|
-
/* @__PURE__ */
|
|
6073
|
-
isLoopEnabled && /* @__PURE__ */
|
|
4304
|
+
/* @__PURE__ */ jsx9(SmartScale, { renderTick }),
|
|
4305
|
+
isLoopEnabled && /* @__PURE__ */ jsx9(
|
|
6074
4306
|
TimescaleLoopRegion,
|
|
6075
4307
|
{
|
|
6076
4308
|
startPosition: Math.min(loopStart, loopEnd) * sampleRate / samplesPerPixel,
|
|
@@ -6116,7 +4348,7 @@ var PlaylistVisualization = ({
|
|
|
6116
4348
|
const helpers = perTrackSpectrogramHelpers.get(track.id);
|
|
6117
4349
|
const trackCfg = helpers == null ? void 0 : helpers.config;
|
|
6118
4350
|
if (!(trackCfg == null ? void 0 : trackCfg.labels) || !helpers) return null;
|
|
6119
|
-
return /* @__PURE__ */
|
|
4351
|
+
return /* @__PURE__ */ jsx9(
|
|
6120
4352
|
SpectrogramLabels,
|
|
6121
4353
|
{
|
|
6122
4354
|
waveHeight,
|
|
@@ -6134,7 +4366,7 @@ var PlaylistVisualization = ({
|
|
|
6134
4366
|
trackClipPeaks.map((clip, clipIndex) => {
|
|
6135
4367
|
const peaksData = clip.peaks;
|
|
6136
4368
|
const width = peaksData.length;
|
|
6137
|
-
return /* @__PURE__ */
|
|
4369
|
+
return /* @__PURE__ */ jsx9(
|
|
6138
4370
|
Clip,
|
|
6139
4371
|
{
|
|
6140
4372
|
clipId: clip.clipId,
|
|
@@ -6164,7 +4396,7 @@ var PlaylistVisualization = ({
|
|
|
6164
4396
|
selectTrack(trackIndex);
|
|
6165
4397
|
},
|
|
6166
4398
|
children: peaksData.data.map((channelPeaks, channelIndex) => {
|
|
6167
|
-
return /* @__PURE__ */
|
|
4399
|
+
return /* @__PURE__ */ jsx9(
|
|
6168
4400
|
ChannelWithProgress,
|
|
6169
4401
|
{
|
|
6170
4402
|
index: channelIndex,
|
|
@@ -6191,8 +4423,7 @@ var PlaylistVisualization = ({
|
|
|
6191
4423
|
);
|
|
6192
4424
|
}),
|
|
6193
4425
|
(recordingState == null ? void 0 : recordingState.isRecording) && recordingState.trackId === track.id && ((_d2 = recordingState.peaks[0]) == null ? void 0 : _d2.length) > 0 && (() => {
|
|
6194
|
-
const
|
|
6195
|
-
const outputLatency = "outputLatency" in audioCtx ? audioCtx.outputLatency : 0;
|
|
4426
|
+
const outputLatency = getOutputLatency();
|
|
6196
4427
|
const lookAhead = getLookAhead();
|
|
6197
4428
|
const latencyOffsetSamples = audibleLatencySamples(
|
|
6198
4429
|
outputLatency,
|
|
@@ -6208,7 +4439,7 @@ var PlaylistVisualization = ({
|
|
|
6208
4439
|
const previewChannels = (mono ? recordingState.peaks.slice(0, 1) : recordingState.peaks).map(
|
|
6209
4440
|
(channelPeaks) => skipPeakElements > 0 && skipPeakElements < channelPeaks.length ? channelPeaks.subarray(skipPeakElements) : channelPeaks
|
|
6210
4441
|
);
|
|
6211
|
-
return /* @__PURE__ */
|
|
4442
|
+
return /* @__PURE__ */ jsx9(
|
|
6212
4443
|
Clip,
|
|
6213
4444
|
{
|
|
6214
4445
|
clipId: "recording-preview",
|
|
@@ -6222,7 +4453,7 @@ var PlaylistVisualization = ({
|
|
|
6222
4453
|
disableHeaderDrag: true,
|
|
6223
4454
|
isSelected: track.id === selectedTrackId,
|
|
6224
4455
|
trackId: track.id,
|
|
6225
|
-
children: previewChannels.map((channelPeaks, chIdx) => /* @__PURE__ */
|
|
4456
|
+
children: previewChannels.map((channelPeaks, chIdx) => /* @__PURE__ */ jsx9(
|
|
6226
4457
|
ChannelWithProgress,
|
|
6227
4458
|
{
|
|
6228
4459
|
index: chIdx,
|
|
@@ -6244,11 +4475,11 @@ var PlaylistVisualization = ({
|
|
|
6244
4475
|
track.id
|
|
6245
4476
|
);
|
|
6246
4477
|
}),
|
|
6247
|
-
annotations.length > 0 && annotationIntegration && /* @__PURE__ */
|
|
4478
|
+
annotations.length > 0 && annotationIntegration && /* @__PURE__ */ jsx9(annotationIntegration.AnnotationBoxesWrapper, { height: 30, width: tracksFullWidth, children: annotations.map((annotation, index) => {
|
|
6248
4479
|
const startPosition = annotation.start * sampleRate / samplesPerPixel;
|
|
6249
4480
|
const endPosition = annotation.end * sampleRate / samplesPerPixel;
|
|
6250
4481
|
const label = getAnnotationBoxLabel ? getAnnotationBoxLabel(annotation, index) : annotation.id;
|
|
6251
|
-
return /* @__PURE__ */
|
|
4482
|
+
return /* @__PURE__ */ jsx9(
|
|
6252
4483
|
annotationIntegration.AnnotationBox,
|
|
6253
4484
|
{
|
|
6254
4485
|
annotationId: annotation.id,
|
|
@@ -6264,7 +4495,7 @@ var PlaylistVisualization = ({
|
|
|
6264
4495
|
annotation.id
|
|
6265
4496
|
);
|
|
6266
4497
|
}) }),
|
|
6267
|
-
selectionStart !== selectionEnd && /* @__PURE__ */
|
|
4498
|
+
selectionStart !== selectionEnd && /* @__PURE__ */ jsx9(
|
|
6268
4499
|
Selection,
|
|
6269
4500
|
{
|
|
6270
4501
|
startPosition: Math.min(selectionStart, selectionEnd) * sampleRate / samplesPerPixel,
|
|
@@ -6272,7 +4503,7 @@ var PlaylistVisualization = ({
|
|
|
6272
4503
|
color: theme.selectionColor
|
|
6273
4504
|
}
|
|
6274
4505
|
),
|
|
6275
|
-
(isPlaying || selectionStart === selectionEnd) && (renderPlayhead ? /* @__PURE__ */
|
|
4506
|
+
(isPlaying || selectionStart === selectionEnd) && (renderPlayhead ? /* @__PURE__ */ jsx9(
|
|
6276
4507
|
CustomPlayhead,
|
|
6277
4508
|
{
|
|
6278
4509
|
renderPlayhead,
|
|
@@ -6280,14 +4511,14 @@ var PlaylistVisualization = ({
|
|
|
6280
4511
|
samplesPerPixel,
|
|
6281
4512
|
sampleRate
|
|
6282
4513
|
}
|
|
6283
|
-
) : /* @__PURE__ */
|
|
4514
|
+
) : /* @__PURE__ */ jsx9(AnimatedPlayhead, { color: theme.playheadColor }))
|
|
6284
4515
|
] })
|
|
6285
4516
|
}
|
|
6286
4517
|
)
|
|
6287
4518
|
}
|
|
6288
4519
|
),
|
|
6289
4520
|
(spectrogram == null ? void 0 : spectrogram.SettingsModal) && typeof document !== "undefined" && createPortal(
|
|
6290
|
-
/* @__PURE__ */
|
|
4521
|
+
/* @__PURE__ */ jsx9(
|
|
6291
4522
|
spectrogram.SettingsModal,
|
|
6292
4523
|
{
|
|
6293
4524
|
open: settingsModalTrackId !== null,
|
|
@@ -6307,8 +4538,8 @@ var PlaylistVisualization = ({
|
|
|
6307
4538
|
};
|
|
6308
4539
|
|
|
6309
4540
|
// src/components/PlaylistAnnotationList.tsx
|
|
6310
|
-
import { useCallback as
|
|
6311
|
-
import { jsx as
|
|
4541
|
+
import { useCallback as useCallback17 } from "react";
|
|
4542
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
6312
4543
|
var PlaylistAnnotationList = ({
|
|
6313
4544
|
height,
|
|
6314
4545
|
renderAnnotationItem,
|
|
@@ -6322,7 +4553,7 @@ var PlaylistAnnotationList = ({
|
|
|
6322
4553
|
const integration = useAnnotationIntegration();
|
|
6323
4554
|
const { setAnnotations } = usePlaylistControls();
|
|
6324
4555
|
const resolvedConfig = annotationListConfig != null ? annotationListConfig : { linkEndpoints, continuousPlay };
|
|
6325
|
-
const handleAnnotationUpdate =
|
|
4556
|
+
const handleAnnotationUpdate = useCallback17(
|
|
6326
4557
|
(updatedAnnotations) => {
|
|
6327
4558
|
setAnnotations(updatedAnnotations);
|
|
6328
4559
|
onAnnotationUpdate == null ? void 0 : onAnnotationUpdate(updatedAnnotations);
|
|
@@ -6330,7 +4561,7 @@ var PlaylistAnnotationList = ({
|
|
|
6330
4561
|
[setAnnotations, onAnnotationUpdate]
|
|
6331
4562
|
);
|
|
6332
4563
|
const { AnnotationText } = integration;
|
|
6333
|
-
return /* @__PURE__ */
|
|
4564
|
+
return /* @__PURE__ */ jsx10(
|
|
6334
4565
|
AnnotationText,
|
|
6335
4566
|
{
|
|
6336
4567
|
annotations,
|
|
@@ -6349,7 +4580,7 @@ var PlaylistAnnotationList = ({
|
|
|
6349
4580
|
};
|
|
6350
4581
|
|
|
6351
4582
|
// src/components/Waveform.tsx
|
|
6352
|
-
import { Fragment as Fragment3, jsx as
|
|
4583
|
+
import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
6353
4584
|
var Waveform = ({
|
|
6354
4585
|
renderTrackControls,
|
|
6355
4586
|
renderTick,
|
|
@@ -6374,7 +4605,7 @@ var Waveform = ({
|
|
|
6374
4605
|
const clipInteractionEnabled = useClipInteractionEnabled();
|
|
6375
4606
|
const effectiveInteractiveClips = interactiveClips || clipInteractionEnabled;
|
|
6376
4607
|
return /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
6377
|
-
/* @__PURE__ */
|
|
4608
|
+
/* @__PURE__ */ jsx11(
|
|
6378
4609
|
PlaylistVisualization,
|
|
6379
4610
|
{
|
|
6380
4611
|
renderTrackControls,
|
|
@@ -6391,7 +4622,7 @@ var Waveform = ({
|
|
|
6391
4622
|
recordingState
|
|
6392
4623
|
}
|
|
6393
4624
|
),
|
|
6394
|
-
annotations.length > 0 && /* @__PURE__ */
|
|
4625
|
+
annotations.length > 0 && /* @__PURE__ */ jsx11(
|
|
6395
4626
|
PlaylistAnnotationList,
|
|
6396
4627
|
{
|
|
6397
4628
|
height: annotationTextHeight,
|
|
@@ -6406,7 +4637,7 @@ var Waveform = ({
|
|
|
6406
4637
|
};
|
|
6407
4638
|
|
|
6408
4639
|
// src/components/MediaElementPlaylist.tsx
|
|
6409
|
-
import { useContext as useContext7, useRef as
|
|
4640
|
+
import { useContext as useContext7, useRef as useRef17, useState as useState12, useCallback as useCallback18 } from "react";
|
|
6410
4641
|
import { DragDropProvider } from "@dnd-kit/react";
|
|
6411
4642
|
import { RestrictToHorizontalAxis } from "@dnd-kit/abstract/modifiers";
|
|
6412
4643
|
import {
|
|
@@ -6442,9 +4673,9 @@ var noDropAnimationPlugins = (defaults) => {
|
|
|
6442
4673
|
};
|
|
6443
4674
|
|
|
6444
4675
|
// src/components/AnimatedMediaElementPlayhead.tsx
|
|
6445
|
-
import { useRef as
|
|
4676
|
+
import { useRef as useRef15, useEffect as useEffect10 } from "react";
|
|
6446
4677
|
import styled5 from "styled-components";
|
|
6447
|
-
import { jsx as
|
|
4678
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
6448
4679
|
var PlayheadLine2 = styled5.div`
|
|
6449
4680
|
position: absolute;
|
|
6450
4681
|
top: 0;
|
|
@@ -6459,11 +4690,11 @@ var PlayheadLine2 = styled5.div`
|
|
|
6459
4690
|
var AnimatedMediaElementPlayhead = ({
|
|
6460
4691
|
color = "#ff0000"
|
|
6461
4692
|
}) => {
|
|
6462
|
-
const playheadRef =
|
|
6463
|
-
const animationFrameRef =
|
|
4693
|
+
const playheadRef = useRef15(null);
|
|
4694
|
+
const animationFrameRef = useRef15(null);
|
|
6464
4695
|
const { isPlaying, currentTimeRef } = useMediaElementAnimation();
|
|
6465
4696
|
const { samplesPerPixel, sampleRate, progressBarWidth } = useMediaElementData();
|
|
6466
|
-
|
|
4697
|
+
useEffect10(() => {
|
|
6467
4698
|
const updatePosition = () => {
|
|
6468
4699
|
var _a;
|
|
6469
4700
|
if (playheadRef.current) {
|
|
@@ -6487,7 +4718,7 @@ var AnimatedMediaElementPlayhead = ({
|
|
|
6487
4718
|
}
|
|
6488
4719
|
};
|
|
6489
4720
|
}, [isPlaying, sampleRate, samplesPerPixel, currentTimeRef]);
|
|
6490
|
-
|
|
4721
|
+
useEffect10(() => {
|
|
6491
4722
|
var _a;
|
|
6492
4723
|
if (!isPlaying && playheadRef.current) {
|
|
6493
4724
|
const time = (_a = currentTimeRef.current) != null ? _a : 0;
|
|
@@ -6495,11 +4726,11 @@ var AnimatedMediaElementPlayhead = ({
|
|
|
6495
4726
|
playheadRef.current.style.transform = `translate3d(${position}px, 0, 0)`;
|
|
6496
4727
|
}
|
|
6497
4728
|
});
|
|
6498
|
-
return /* @__PURE__ */
|
|
4729
|
+
return /* @__PURE__ */ jsx12(PlayheadLine2, { ref: playheadRef, $color: color, $width: progressBarWidth, "data-playhead": true });
|
|
6499
4730
|
};
|
|
6500
4731
|
|
|
6501
4732
|
// src/components/ChannelWithMediaElementProgress.tsx
|
|
6502
|
-
import { useRef as
|
|
4733
|
+
import { useRef as useRef16, useEffect as useEffect11 } from "react";
|
|
6503
4734
|
import styled6 from "styled-components";
|
|
6504
4735
|
import {
|
|
6505
4736
|
SmartChannel as SmartChannel2,
|
|
@@ -6507,7 +4738,7 @@ import {
|
|
|
6507
4738
|
usePlaylistInfo as usePlaylistInfo2,
|
|
6508
4739
|
waveformColorToCss as waveformColorToCss3
|
|
6509
4740
|
} from "@waveform-playlist/ui-components";
|
|
6510
|
-
import { jsx as
|
|
4741
|
+
import { jsx as jsx13, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
6511
4742
|
var ChannelWrapper2 = styled6.div`
|
|
6512
4743
|
position: relative;
|
|
6513
4744
|
`;
|
|
@@ -6544,14 +4775,14 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6544
4775
|
"clipStartSample",
|
|
6545
4776
|
"clipDurationSamples"
|
|
6546
4777
|
]);
|
|
6547
|
-
const progressRef =
|
|
6548
|
-
const animationFrameRef =
|
|
4778
|
+
const progressRef = useRef16(null);
|
|
4779
|
+
const animationFrameRef = useRef16(null);
|
|
6549
4780
|
const theme = useTheme3();
|
|
6550
4781
|
const { waveHeight } = usePlaylistInfo2();
|
|
6551
4782
|
const { isPlaying, currentTimeRef } = useMediaElementAnimation();
|
|
6552
4783
|
const { samplesPerPixel, sampleRate } = useMediaElementData();
|
|
6553
4784
|
const progressColor = (theme == null ? void 0 : theme.waveProgressColor) || "rgba(0, 0, 0, 0.1)";
|
|
6554
|
-
|
|
4785
|
+
useEffect11(() => {
|
|
6555
4786
|
const updateProgress = () => {
|
|
6556
4787
|
var _a2;
|
|
6557
4788
|
if (progressRef.current) {
|
|
@@ -6593,7 +4824,7 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6593
4824
|
smartChannelProps.length,
|
|
6594
4825
|
currentTimeRef
|
|
6595
4826
|
]);
|
|
6596
|
-
|
|
4827
|
+
useEffect11(() => {
|
|
6597
4828
|
var _a2;
|
|
6598
4829
|
if (!isPlaying && progressRef.current) {
|
|
6599
4830
|
const currentTime = (_a2 = currentTimeRef.current) != null ? _a2 : 0;
|
|
@@ -6620,7 +4851,7 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6620
4851
|
}
|
|
6621
4852
|
const backgroundCss = waveformColorToCss3(backgroundColor);
|
|
6622
4853
|
return /* @__PURE__ */ jsxs4(ChannelWrapper2, { children: [
|
|
6623
|
-
/* @__PURE__ */
|
|
4854
|
+
/* @__PURE__ */ jsx13(
|
|
6624
4855
|
Background2,
|
|
6625
4856
|
{
|
|
6626
4857
|
$color: backgroundCss,
|
|
@@ -6629,7 +4860,7 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6629
4860
|
$width: smartChannelProps.length
|
|
6630
4861
|
}
|
|
6631
4862
|
),
|
|
6632
|
-
/* @__PURE__ */
|
|
4863
|
+
/* @__PURE__ */ jsx13(
|
|
6633
4864
|
ProgressOverlay2,
|
|
6634
4865
|
{
|
|
6635
4866
|
ref: progressRef,
|
|
@@ -6638,12 +4869,12 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6638
4869
|
$top: smartChannelProps.index * waveHeight
|
|
6639
4870
|
}
|
|
6640
4871
|
),
|
|
6641
|
-
/* @__PURE__ */
|
|
4872
|
+
/* @__PURE__ */ jsx13(ChannelContainer2, { children: /* @__PURE__ */ jsx13(SmartChannel2, __spreadProps(__spreadValues({}, smartChannelProps), { isSelected: true, transparentBackground: true })) })
|
|
6642
4873
|
] });
|
|
6643
4874
|
};
|
|
6644
4875
|
|
|
6645
4876
|
// src/components/MediaElementPlaylist.tsx
|
|
6646
|
-
import { Fragment as Fragment4, jsx as
|
|
4877
|
+
import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
6647
4878
|
var ZERO_REF = { current: 0 };
|
|
6648
4879
|
var CustomMediaElementPlayhead = ({ renderPlayhead, color, samplesPerPixel, sampleRate }) => {
|
|
6649
4880
|
var _a;
|
|
@@ -6688,11 +4919,11 @@ var MediaElementPlaylist = ({
|
|
|
6688
4919
|
fadeIn,
|
|
6689
4920
|
fadeOut
|
|
6690
4921
|
} = useMediaElementData();
|
|
6691
|
-
const [selectionStart, setSelectionStart] =
|
|
6692
|
-
const [selectionEnd, setSelectionEnd] =
|
|
6693
|
-
const [isSelecting, setIsSelecting] =
|
|
6694
|
-
const scrollContainerRef =
|
|
6695
|
-
const handleScrollContainerRef =
|
|
4922
|
+
const [selectionStart, setSelectionStart] = useState12(0);
|
|
4923
|
+
const [selectionEnd, setSelectionEnd] = useState12(0);
|
|
4924
|
+
const [isSelecting, setIsSelecting] = useState12(false);
|
|
4925
|
+
const scrollContainerRef = useRef17(null);
|
|
4926
|
+
const handleScrollContainerRef = useCallback18(
|
|
6696
4927
|
(el) => {
|
|
6697
4928
|
scrollContainerRef.current = el;
|
|
6698
4929
|
setScrollContainer(el);
|
|
@@ -6700,7 +4931,7 @@ var MediaElementPlaylist = ({
|
|
|
6700
4931
|
[setScrollContainer]
|
|
6701
4932
|
);
|
|
6702
4933
|
const tracksFullWidth = Math.floor(duration * sampleRate / samplesPerPixel);
|
|
6703
|
-
const handleAnnotationClick =
|
|
4934
|
+
const handleAnnotationClick = useCallback18(
|
|
6704
4935
|
(annotation) => __async(null, null, function* () {
|
|
6705
4936
|
setActiveAnnotationId(annotation.id);
|
|
6706
4937
|
try {
|
|
@@ -6715,7 +4946,7 @@ var MediaElementPlaylist = ({
|
|
|
6715
4946
|
}),
|
|
6716
4947
|
[setActiveAnnotationId, play]
|
|
6717
4948
|
);
|
|
6718
|
-
const handleAnnotationUpdate =
|
|
4949
|
+
const handleAnnotationUpdate = useCallback18(
|
|
6719
4950
|
(updatedAnnotations) => {
|
|
6720
4951
|
setAnnotations(updatedAnnotations);
|
|
6721
4952
|
onAnnotationUpdate == null ? void 0 : onAnnotationUpdate(updatedAnnotations);
|
|
@@ -6729,8 +4960,8 @@ var MediaElementPlaylist = ({
|
|
|
6729
4960
|
duration,
|
|
6730
4961
|
linkEndpoints: linkEndpointsProp
|
|
6731
4962
|
});
|
|
6732
|
-
const mouseDownTimeRef =
|
|
6733
|
-
const handleMouseDown =
|
|
4963
|
+
const mouseDownTimeRef = useRef17(0);
|
|
4964
|
+
const handleMouseDown = useCallback18(
|
|
6734
4965
|
(e) => {
|
|
6735
4966
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
6736
4967
|
const x = e.clientX - rect.left;
|
|
@@ -6742,7 +4973,7 @@ var MediaElementPlaylist = ({
|
|
|
6742
4973
|
},
|
|
6743
4974
|
[samplesPerPixel, sampleRate]
|
|
6744
4975
|
);
|
|
6745
|
-
const handleMouseMove =
|
|
4976
|
+
const handleMouseMove = useCallback18(
|
|
6746
4977
|
(e) => {
|
|
6747
4978
|
if (!isSelecting) return;
|
|
6748
4979
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
@@ -6752,7 +4983,7 @@ var MediaElementPlaylist = ({
|
|
|
6752
4983
|
},
|
|
6753
4984
|
[isSelecting, samplesPerPixel, sampleRate]
|
|
6754
4985
|
);
|
|
6755
|
-
const handleMouseUp =
|
|
4986
|
+
const handleMouseUp = useCallback18(
|
|
6756
4987
|
(e) => {
|
|
6757
4988
|
if (!isSelecting) return;
|
|
6758
4989
|
setIsSelecting(false);
|
|
@@ -6782,9 +5013,9 @@ var MediaElementPlaylist = ({
|
|
|
6782
5013
|
[isSelecting, selectionStart, samplesPerPixel, sampleRate, seekTo, isPlaying, playoutRef, play]
|
|
6783
5014
|
);
|
|
6784
5015
|
if (peaksDataArray.length === 0) {
|
|
6785
|
-
return /* @__PURE__ */
|
|
5016
|
+
return /* @__PURE__ */ jsx14("div", { className, children: "Loading waveform..." });
|
|
6786
5017
|
}
|
|
6787
|
-
return /* @__PURE__ */
|
|
5018
|
+
return /* @__PURE__ */ jsx14(DevicePixelRatioProvider2, { children: /* @__PURE__ */ jsx14(
|
|
6788
5019
|
PlaylistInfoContext2.Provider,
|
|
6789
5020
|
{
|
|
6790
5021
|
value: {
|
|
@@ -6798,7 +5029,7 @@ var MediaElementPlaylist = ({
|
|
|
6798
5029
|
barWidth,
|
|
6799
5030
|
barGap
|
|
6800
5031
|
},
|
|
6801
|
-
children: /* @__PURE__ */
|
|
5032
|
+
children: /* @__PURE__ */ jsx14(
|
|
6802
5033
|
Playlist2,
|
|
6803
5034
|
{
|
|
6804
5035
|
theme,
|
|
@@ -6812,11 +5043,11 @@ var MediaElementPlaylist = ({
|
|
|
6812
5043
|
onTracksMouseUp: handleMouseUp,
|
|
6813
5044
|
scrollContainerRef: handleScrollContainerRef,
|
|
6814
5045
|
isSelecting,
|
|
6815
|
-
timescale: timeScaleHeight > 0 ? /* @__PURE__ */
|
|
5046
|
+
timescale: timeScaleHeight > 0 ? /* @__PURE__ */ jsx14(SmartScale2, {}) : void 0,
|
|
6816
5047
|
children: /* @__PURE__ */ jsxs5(Fragment4, { children: [
|
|
6817
5048
|
peaksDataArray.map((trackClipPeaks, trackIndex) => {
|
|
6818
5049
|
const maxChannels = trackClipPeaks.length > 0 ? Math.max(...trackClipPeaks.map((clip) => clip.peaks.data.length)) : 1;
|
|
6819
|
-
return /* @__PURE__ */
|
|
5050
|
+
return /* @__PURE__ */ jsx14(
|
|
6820
5051
|
TrackComponent2,
|
|
6821
5052
|
{
|
|
6822
5053
|
numChannels: maxChannels,
|
|
@@ -6844,7 +5075,7 @@ var MediaElementPlaylist = ({
|
|
|
6844
5075
|
isSelected: true,
|
|
6845
5076
|
trackId: `media-element-track-${trackIndex}`,
|
|
6846
5077
|
children: [
|
|
6847
|
-
peaksData.data.map((channelPeaks, channelIndex) => /* @__PURE__ */
|
|
5078
|
+
peaksData.data.map((channelPeaks, channelIndex) => /* @__PURE__ */ jsx14(
|
|
6848
5079
|
ChannelWithMediaElementProgress,
|
|
6849
5080
|
{
|
|
6850
5081
|
index: channelIndex,
|
|
@@ -6856,7 +5087,7 @@ var MediaElementPlaylist = ({
|
|
|
6856
5087
|
},
|
|
6857
5088
|
`${trackIndex}-${clipIndex}-${channelIndex}`
|
|
6858
5089
|
)),
|
|
6859
|
-
showFades && fadeIn && fadeIn.duration > 0 && /* @__PURE__ */
|
|
5090
|
+
showFades && fadeIn && fadeIn.duration > 0 && /* @__PURE__ */ jsx14(
|
|
6860
5091
|
FadeOverlay,
|
|
6861
5092
|
{
|
|
6862
5093
|
left: 0,
|
|
@@ -6865,7 +5096,7 @@ var MediaElementPlaylist = ({
|
|
|
6865
5096
|
curveType: fadeIn.type
|
|
6866
5097
|
}
|
|
6867
5098
|
),
|
|
6868
|
-
showFades && fadeOut && fadeOut.duration > 0 && /* @__PURE__ */
|
|
5099
|
+
showFades && fadeOut && fadeOut.duration > 0 && /* @__PURE__ */ jsx14(
|
|
6869
5100
|
FadeOverlay,
|
|
6870
5101
|
{
|
|
6871
5102
|
left: width - Math.floor(fadeOut.duration * sampleRate / samplesPerPixel),
|
|
@@ -6883,7 +5114,7 @@ var MediaElementPlaylist = ({
|
|
|
6883
5114
|
trackIndex
|
|
6884
5115
|
);
|
|
6885
5116
|
}),
|
|
6886
|
-
annotations.length > 0 && annotationIntegration && /* @__PURE__ */
|
|
5117
|
+
annotations.length > 0 && annotationIntegration && /* @__PURE__ */ jsx14(
|
|
6887
5118
|
DragDropProvider,
|
|
6888
5119
|
{
|
|
6889
5120
|
onDragStart,
|
|
@@ -6891,11 +5122,11 @@ var MediaElementPlaylist = ({
|
|
|
6891
5122
|
onDragEnd,
|
|
6892
5123
|
modifiers: editable ? [RestrictToHorizontalAxis] : [],
|
|
6893
5124
|
plugins: noDropAnimationPlugins,
|
|
6894
|
-
children: /* @__PURE__ */
|
|
5125
|
+
children: /* @__PURE__ */ jsx14(annotationIntegration.AnnotationBoxesWrapper, { height: 30, width: tracksFullWidth, children: annotations.map((annotation, index) => {
|
|
6895
5126
|
const startPosition = annotation.start * sampleRate / samplesPerPixel;
|
|
6896
5127
|
const endPosition = annotation.end * sampleRate / samplesPerPixel;
|
|
6897
5128
|
const label = getAnnotationBoxLabel ? getAnnotationBoxLabel(annotation, index) : annotation.id;
|
|
6898
|
-
return /* @__PURE__ */
|
|
5129
|
+
return /* @__PURE__ */ jsx14(
|
|
6899
5130
|
annotationIntegration.AnnotationBox,
|
|
6900
5131
|
{
|
|
6901
5132
|
annotationId: annotation.id,
|
|
@@ -6913,7 +5144,7 @@ var MediaElementPlaylist = ({
|
|
|
6913
5144
|
}) })
|
|
6914
5145
|
}
|
|
6915
5146
|
),
|
|
6916
|
-
selectionStart !== selectionEnd && /* @__PURE__ */
|
|
5147
|
+
selectionStart !== selectionEnd && /* @__PURE__ */ jsx14(
|
|
6917
5148
|
Selection2,
|
|
6918
5149
|
{
|
|
6919
5150
|
startPosition: Math.min(selectionStart, selectionEnd) * sampleRate / samplesPerPixel,
|
|
@@ -6921,7 +5152,7 @@ var MediaElementPlaylist = ({
|
|
|
6921
5152
|
color: theme.selectionColor
|
|
6922
5153
|
}
|
|
6923
5154
|
),
|
|
6924
|
-
renderPlayhead ? /* @__PURE__ */
|
|
5155
|
+
renderPlayhead ? /* @__PURE__ */ jsx14(
|
|
6925
5156
|
CustomMediaElementPlayhead,
|
|
6926
5157
|
{
|
|
6927
5158
|
renderPlayhead,
|
|
@@ -6929,7 +5160,7 @@ var MediaElementPlaylist = ({
|
|
|
6929
5160
|
samplesPerPixel,
|
|
6930
5161
|
sampleRate
|
|
6931
5162
|
}
|
|
6932
|
-
) : /* @__PURE__ */
|
|
5163
|
+
) : /* @__PURE__ */ jsx14(AnimatedMediaElementPlayhead, { color: theme.playheadColor })
|
|
6933
5164
|
] })
|
|
6934
5165
|
}
|
|
6935
5166
|
)
|
|
@@ -6938,8 +5169,8 @@ var MediaElementPlaylist = ({
|
|
|
6938
5169
|
};
|
|
6939
5170
|
|
|
6940
5171
|
// src/components/MediaElementAnnotationList.tsx
|
|
6941
|
-
import { useCallback as
|
|
6942
|
-
import { jsx as
|
|
5172
|
+
import { useCallback as useCallback19 } from "react";
|
|
5173
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
6943
5174
|
var MediaElementAnnotationList = ({
|
|
6944
5175
|
height,
|
|
6945
5176
|
renderAnnotationItem,
|
|
@@ -6954,7 +5185,7 @@ var MediaElementAnnotationList = ({
|
|
|
6954
5185
|
const integration = useAnnotationIntegration();
|
|
6955
5186
|
const { setAnnotations } = useMediaElementControls();
|
|
6956
5187
|
const resolvedConfig = annotationListConfig != null ? annotationListConfig : { linkEndpoints: false, continuousPlay };
|
|
6957
|
-
const handleAnnotationUpdate =
|
|
5188
|
+
const handleAnnotationUpdate = useCallback19(
|
|
6958
5189
|
(updatedAnnotations) => {
|
|
6959
5190
|
setAnnotations(updatedAnnotations);
|
|
6960
5191
|
onAnnotationUpdate == null ? void 0 : onAnnotationUpdate(updatedAnnotations);
|
|
@@ -6962,7 +5193,7 @@ var MediaElementAnnotationList = ({
|
|
|
6962
5193
|
[setAnnotations, onAnnotationUpdate]
|
|
6963
5194
|
);
|
|
6964
5195
|
const { AnnotationText } = integration;
|
|
6965
|
-
return /* @__PURE__ */
|
|
5196
|
+
return /* @__PURE__ */ jsx15(
|
|
6966
5197
|
AnnotationText,
|
|
6967
5198
|
{
|
|
6968
5199
|
annotations,
|
|
@@ -6981,7 +5212,7 @@ var MediaElementAnnotationList = ({
|
|
|
6981
5212
|
};
|
|
6982
5213
|
|
|
6983
5214
|
// src/components/MediaElementWaveform.tsx
|
|
6984
|
-
import { Fragment as Fragment5, jsx as
|
|
5215
|
+
import { Fragment as Fragment5, jsx as jsx16, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
6985
5216
|
var MediaElementWaveform = ({
|
|
6986
5217
|
annotationTextHeight,
|
|
6987
5218
|
getAnnotationBoxLabel,
|
|
@@ -6997,7 +5228,7 @@ var MediaElementWaveform = ({
|
|
|
6997
5228
|
}) => {
|
|
6998
5229
|
const { annotations } = useMediaElementState();
|
|
6999
5230
|
return /* @__PURE__ */ jsxs6(Fragment5, { children: [
|
|
7000
|
-
/* @__PURE__ */
|
|
5231
|
+
/* @__PURE__ */ jsx16(
|
|
7001
5232
|
MediaElementPlaylist,
|
|
7002
5233
|
{
|
|
7003
5234
|
getAnnotationBoxLabel,
|
|
@@ -7009,7 +5240,7 @@ var MediaElementWaveform = ({
|
|
|
7009
5240
|
className
|
|
7010
5241
|
}
|
|
7011
5242
|
),
|
|
7012
|
-
annotations.length > 0 && /* @__PURE__ */
|
|
5243
|
+
annotations.length > 0 && /* @__PURE__ */ jsx16(
|
|
7013
5244
|
MediaElementAnnotationList,
|
|
7014
5245
|
{
|
|
7015
5246
|
height: annotationTextHeight,
|
|
@@ -7084,7 +5315,7 @@ var KeyboardShortcuts = ({
|
|
|
7084
5315
|
};
|
|
7085
5316
|
|
|
7086
5317
|
// src/components/ClipInteractionProvider.tsx
|
|
7087
|
-
import React16, { useEffect as
|
|
5318
|
+
import React16, { useEffect as useEffect12, useMemo as useMemo6 } from "react";
|
|
7088
5319
|
import { DragDropProvider as DragDropProvider2 } from "@dnd-kit/react";
|
|
7089
5320
|
import { RestrictToHorizontalAxis as RestrictToHorizontalAxis2 } from "@dnd-kit/abstract/modifiers";
|
|
7090
5321
|
import {
|
|
@@ -7174,7 +5405,7 @@ _SnapToGridModifier.configure = configurator2(_SnapToGridModifier);
|
|
|
7174
5405
|
var SnapToGridModifier = _SnapToGridModifier;
|
|
7175
5406
|
|
|
7176
5407
|
// src/components/ClipInteractionProvider.tsx
|
|
7177
|
-
import { jsx as
|
|
5408
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
7178
5409
|
var NOOP_TRACKS_CHANGE = () => {
|
|
7179
5410
|
};
|
|
7180
5411
|
var ClipInteractionProvider = ({
|
|
@@ -7187,14 +5418,14 @@ var ClipInteractionProvider = ({
|
|
|
7187
5418
|
const beatsAndBars = useBeatsAndBars();
|
|
7188
5419
|
const useBeatsSnap = snap && beatsAndBars != null && beatsAndBars.scaleMode === "beats" && beatsAndBars.snapTo !== "off";
|
|
7189
5420
|
const useTimescaleSnap = snap && !useBeatsSnap;
|
|
7190
|
-
|
|
5421
|
+
useEffect12(() => {
|
|
7191
5422
|
if (onTracksChange == null) {
|
|
7192
5423
|
console.warn(
|
|
7193
5424
|
"[waveform-playlist] ClipInteractionProvider: onTracksChange is not set on WaveformPlaylistProvider. Drag and trim edits will not be persisted."
|
|
7194
5425
|
);
|
|
7195
5426
|
}
|
|
7196
5427
|
}, [onTracksChange]);
|
|
7197
|
-
const snapSamplePosition =
|
|
5428
|
+
const snapSamplePosition = useMemo6(() => {
|
|
7198
5429
|
if (useBeatsSnap && beatsAndBars) {
|
|
7199
5430
|
const { bpm, timeSignature, snapTo } = beatsAndBars;
|
|
7200
5431
|
const gridTicks = snapTo === "bar" ? ticksPerBar2(timeSignature) : ticksPerBeat2(timeSignature);
|
|
@@ -7234,7 +5465,7 @@ var ClipInteractionProvider = ({
|
|
|
7234
5465
|
},
|
|
7235
5466
|
[handleDragStart, tracks, setSelectedTrackId]
|
|
7236
5467
|
);
|
|
7237
|
-
const modifiers =
|
|
5468
|
+
const modifiers = useMemo6(() => {
|
|
7238
5469
|
const mods = [RestrictToHorizontalAxis2];
|
|
7239
5470
|
if (useBeatsSnap && beatsAndBars) {
|
|
7240
5471
|
mods.push(
|
|
@@ -7259,7 +5490,7 @@ var ClipInteractionProvider = ({
|
|
|
7259
5490
|
mods.push(ClipCollisionModifier.configure({ tracks, samplesPerPixel }));
|
|
7260
5491
|
return mods;
|
|
7261
5492
|
}, [useBeatsSnap, useTimescaleSnap, beatsAndBars, tracks, samplesPerPixel, sampleRate]);
|
|
7262
|
-
return /* @__PURE__ */
|
|
5493
|
+
return /* @__PURE__ */ jsx17(ClipInteractionContextProvider, { value: true, children: /* @__PURE__ */ jsx17(
|
|
7263
5494
|
DragDropProvider2,
|
|
7264
5495
|
{
|
|
7265
5496
|
sensors,
|
|
@@ -7282,7 +5513,6 @@ export {
|
|
|
7282
5513
|
ContinuousPlayCheckbox,
|
|
7283
5514
|
DownloadAnnotationsButton,
|
|
7284
5515
|
EditableCheckbox,
|
|
7285
|
-
ExportWavButton,
|
|
7286
5516
|
FastForwardButton,
|
|
7287
5517
|
KeyboardShortcuts,
|
|
7288
5518
|
LinkEndpointsCheckbox,
|
|
@@ -7305,17 +5535,10 @@ export {
|
|
|
7305
5535
|
SpectrogramIntegrationProvider,
|
|
7306
5536
|
StopButton,
|
|
7307
5537
|
TimeFormatSelect,
|
|
7308
|
-
Tone2 as Tone,
|
|
7309
5538
|
Waveform,
|
|
7310
5539
|
WaveformPlaylistProvider,
|
|
7311
5540
|
ZoomInButton,
|
|
7312
5541
|
ZoomOutButton,
|
|
7313
|
-
createEffectChain,
|
|
7314
|
-
createEffectInstance,
|
|
7315
|
-
effectCategories,
|
|
7316
|
-
effectDefinitions,
|
|
7317
|
-
getEffectDefinition,
|
|
7318
|
-
getEffectsByCategory,
|
|
7319
5542
|
getShortcutLabel,
|
|
7320
5543
|
getWaveformDataMetadata,
|
|
7321
5544
|
loadPeaksFromWaveformData,
|
|
@@ -7324,22 +5547,16 @@ export {
|
|
|
7324
5547
|
useAnnotationDragHandlers,
|
|
7325
5548
|
useAnnotationIntegration,
|
|
7326
5549
|
useAnnotationKeyboardControls,
|
|
7327
|
-
useAudioTracks,
|
|
7328
5550
|
useClipDragHandlers,
|
|
7329
5551
|
useClipInteractionEnabled,
|
|
7330
5552
|
useClipSplitting,
|
|
7331
5553
|
useDragSensors,
|
|
7332
|
-
useDynamicEffects,
|
|
7333
|
-
useDynamicTracks,
|
|
7334
|
-
useExportWav,
|
|
7335
5554
|
useKeyboardShortcuts,
|
|
7336
|
-
useMasterAnalyser,
|
|
7337
5555
|
useMasterVolume,
|
|
7338
5556
|
useMediaElementAnimation,
|
|
7339
5557
|
useMediaElementControls,
|
|
7340
5558
|
useMediaElementData,
|
|
7341
5559
|
useMediaElementState,
|
|
7342
|
-
useOutputMeter,
|
|
7343
5560
|
usePlaybackAnimation,
|
|
7344
5561
|
usePlaybackShortcuts,
|
|
7345
5562
|
usePlaylistControls,
|
|
@@ -7348,7 +5565,6 @@ export {
|
|
|
7348
5565
|
usePlaylistState,
|
|
7349
5566
|
useSpectrogramIntegration,
|
|
7350
5567
|
useTimeFormat,
|
|
7351
|
-
useTrackDynamicEffects,
|
|
7352
5568
|
useZoomControls,
|
|
7353
5569
|
waveformDataToPeaks
|
|
7354
5570
|
};
|