@waveform-playlist/browser 13.1.3 → 15.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 +46 -433
- package/dist/index.d.ts +46 -433
- package/dist/index.js +610 -2374
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +509 -2296
- 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 +22 -7
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",
|
|
@@ -1539,1445 +1345,58 @@ function useAnnotationKeyboardControls({
|
|
|
1539
1345
|
},
|
|
1540
1346
|
{
|
|
1541
1347
|
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);
|
|
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,21 +1933,21 @@ 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;
|
|
3755
1943
|
const isEngineTracks = tracks === engineTracksRef.current;
|
|
3756
1944
|
const prevTracks = prevTracksRef.current;
|
|
3757
|
-
const isIncrementalAdd = engineRef.current !== null &&
|
|
1945
|
+
const isIncrementalAdd = engineRef.current !== null && tracks.length > prevTracks.length && prevTracks.every((pt) => {
|
|
3758
1946
|
const current = tracks.find((t) => t.id === pt.id);
|
|
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) {
|
|
@@ -3867,12 +2055,10 @@ var WaveformPlaylistProvider = ({
|
|
|
3867
2055
|
setTrackStates([]);
|
|
3868
2056
|
setPeaksDataArray([]);
|
|
3869
2057
|
if (engineRef.current) {
|
|
3870
|
-
engineRef.current.
|
|
3871
|
-
|
|
3872
|
-
|
|
2058
|
+
engineRef.current.setTracks([]);
|
|
2059
|
+
prevTracksRef.current = tracks;
|
|
2060
|
+
return;
|
|
3873
2061
|
}
|
|
3874
|
-
prevTracksRef.current = tracks;
|
|
3875
|
-
return;
|
|
3876
2062
|
}
|
|
3877
2063
|
const wasPlaying = isPlayingRef.current;
|
|
3878
2064
|
const resumePosition = currentTimeRef.current;
|
|
@@ -3881,6 +2067,7 @@ var WaveformPlaylistProvider = ({
|
|
|
3881
2067
|
stopAnimationFrameLoop();
|
|
3882
2068
|
pendingResumeRef.current = { position: resumePosition };
|
|
3883
2069
|
}
|
|
2070
|
+
let cancelled = false;
|
|
3884
2071
|
const loadAudio = () => __async(null, null, function* () {
|
|
3885
2072
|
var _a3, _b3, _c3, _d3, _e;
|
|
3886
2073
|
try {
|
|
@@ -3923,7 +2110,17 @@ var WaveformPlaylistProvider = ({
|
|
|
3923
2110
|
lastTracksVersionRef.current = 0;
|
|
3924
2111
|
engineTracksRef.current = null;
|
|
3925
2112
|
audioInitializedRef.current = false;
|
|
3926
|
-
const adapter =
|
|
2113
|
+
const adapter = yield resolvePlayoutAdapter({
|
|
2114
|
+
createAdapter,
|
|
2115
|
+
effects,
|
|
2116
|
+
soundFontCache: soundFontCacheRef.current,
|
|
2117
|
+
sampleRate: sampleRateProp
|
|
2118
|
+
});
|
|
2119
|
+
if (cancelled) {
|
|
2120
|
+
adapter.dispose();
|
|
2121
|
+
return;
|
|
2122
|
+
}
|
|
2123
|
+
sampleRateRef.current = adapter.audioContext.sampleRate;
|
|
3927
2124
|
adapterRef.current = adapter;
|
|
3928
2125
|
const engine = new PlaylistEngine({
|
|
3929
2126
|
adapter,
|
|
@@ -3981,11 +2178,23 @@ var WaveformPlaylistProvider = ({
|
|
|
3981
2178
|
prevTracksRef.current = tracks;
|
|
3982
2179
|
onReady == null ? void 0 : onReady();
|
|
3983
2180
|
} catch (error) {
|
|
3984
|
-
|
|
2181
|
+
if (!engineRef.current && adapterRef.current) {
|
|
2182
|
+
try {
|
|
2183
|
+
adapterRef.current.dispose();
|
|
2184
|
+
} catch (disposeErr) {
|
|
2185
|
+
console.warn(
|
|
2186
|
+
"[waveform-playlist] adapter dispose after load failure threw: " + String(disposeErr)
|
|
2187
|
+
);
|
|
2188
|
+
}
|
|
2189
|
+
adapterRef.current = null;
|
|
2190
|
+
}
|
|
2191
|
+
console.warn("[waveform-playlist] Error loading audio: " + String(error));
|
|
2192
|
+
onError == null ? void 0 : onError(error instanceof Error ? error : new Error(String(error)));
|
|
3985
2193
|
}
|
|
3986
2194
|
});
|
|
3987
2195
|
loadAudio();
|
|
3988
2196
|
return () => {
|
|
2197
|
+
cancelled = true;
|
|
3989
2198
|
if (skipEngineDisposeRef.current) {
|
|
3990
2199
|
skipEngineDisposeRef.current = false;
|
|
3991
2200
|
return;
|
|
@@ -4008,6 +2217,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4008
2217
|
// to the live adapter by the sync effect below; only adapter creation reads it
|
|
4009
2218
|
// (via soundFontCacheRef).
|
|
4010
2219
|
onReady,
|
|
2220
|
+
onError,
|
|
4011
2221
|
effects,
|
|
4012
2222
|
stopAnimationFrameLoop,
|
|
4013
2223
|
onSelectionEngineState,
|
|
@@ -4026,10 +2236,10 @@ var WaveformPlaylistProvider = ({
|
|
|
4026
2236
|
stableZoomLevels,
|
|
4027
2237
|
deferEngineRebuild
|
|
4028
2238
|
]);
|
|
4029
|
-
|
|
2239
|
+
useEffect5(() => {
|
|
4030
2240
|
syncSoundFontCacheToAdapter(adapterRef.current, soundFontCache);
|
|
4031
2241
|
}, [soundFontCache]);
|
|
4032
|
-
|
|
2242
|
+
useEffect5(() => {
|
|
4033
2243
|
if (tracks.length === 0) return;
|
|
4034
2244
|
const allTrackPeaks = tracks.map((track) => {
|
|
4035
2245
|
const clipPeaks = track.clips.map((clip) => {
|
|
@@ -4110,8 +2320,15 @@ var WaveformPlaylistProvider = ({
|
|
|
4110
2320
|
});
|
|
4111
2321
|
setPeaksDataArray(allTrackPeaks);
|
|
4112
2322
|
}, [tracks, samplesPerPixel, mono, waveformDataCache, deferEngineRebuild]);
|
|
4113
|
-
const
|
|
4114
|
-
|
|
2323
|
+
const getAudioContextTime = useCallback13(
|
|
2324
|
+
() => {
|
|
2325
|
+
var _a2, _b2;
|
|
2326
|
+
return (_b2 = (_a2 = adapterRef.current) == null ? void 0 : _a2.audioContext.currentTime) != null ? _b2 : 0;
|
|
2327
|
+
},
|
|
2328
|
+
[]
|
|
2329
|
+
);
|
|
2330
|
+
const getPlaybackTimeFallbackWarnedRef = useRef9(false);
|
|
2331
|
+
const getPlaybackTime = useCallback13(() => {
|
|
4115
2332
|
var _a2, _b2;
|
|
4116
2333
|
if (engineRef.current) {
|
|
4117
2334
|
return engineRef.current.getCurrentTime();
|
|
@@ -4122,30 +2339,35 @@ var WaveformPlaylistProvider = ({
|
|
|
4122
2339
|
"[waveform-playlist] getPlaybackTime called without engine. Falling back to manual elapsed time (loop wrapping will not work)."
|
|
4123
2340
|
);
|
|
4124
2341
|
}
|
|
4125
|
-
const elapsed =
|
|
2342
|
+
const elapsed = getAudioContextTime() - ((_a2 = playbackStartTimeRef.current) != null ? _a2 : 0);
|
|
4126
2343
|
return ((_b2 = audioStartPositionRef.current) != null ? _b2 : 0) + elapsed;
|
|
4127
|
-
}, []);
|
|
4128
|
-
const toVisualTime =
|
|
2344
|
+
}, [getAudioContextTime]);
|
|
2345
|
+
const toVisualTime = useCallback13((rawTime) => {
|
|
4129
2346
|
return Number.isFinite(rawTime) ? Math.max(0, rawTime) : 0;
|
|
4130
2347
|
}, []);
|
|
4131
|
-
const setCurrentTimeRefs =
|
|
2348
|
+
const setCurrentTimeRefs = useCallback13(
|
|
4132
2349
|
(rawTime) => {
|
|
4133
2350
|
currentTimeRef.current = rawTime;
|
|
4134
2351
|
visualTimeRef.current = toVisualTime(rawTime);
|
|
4135
2352
|
},
|
|
4136
2353
|
[toVisualTime]
|
|
4137
2354
|
);
|
|
4138
|
-
const getLookAhead =
|
|
2355
|
+
const getLookAhead = useCallback13(() => {
|
|
4139
2356
|
var _a2, _b2;
|
|
4140
2357
|
return (_b2 = (_a2 = engineRef.current) == null ? void 0 : _a2.lookAhead) != null ? _b2 : 0;
|
|
4141
2358
|
}, []);
|
|
4142
|
-
const
|
|
2359
|
+
const getOutputLatency = useCallback13(() => {
|
|
2360
|
+
var _a2;
|
|
2361
|
+
const audioCtx = (_a2 = adapterRef.current) == null ? void 0 : _a2.audioContext;
|
|
2362
|
+
return audioCtx && "outputLatency" in audioCtx ? audioCtx.outputLatency : 0;
|
|
2363
|
+
}, []);
|
|
2364
|
+
const registerFrameCallback = useCallback13((id, cb) => {
|
|
4143
2365
|
frameCallbacksRef.current.set(id, cb);
|
|
4144
2366
|
}, []);
|
|
4145
|
-
const unregisterFrameCallback =
|
|
2367
|
+
const unregisterFrameCallback = useCallback13((id) => {
|
|
4146
2368
|
frameCallbacksRef.current.delete(id);
|
|
4147
2369
|
}, []);
|
|
4148
|
-
const startAnimationLoop =
|
|
2370
|
+
const startAnimationLoop = useCallback13(() => {
|
|
4149
2371
|
const updateTime = () => {
|
|
4150
2372
|
const time = getPlaybackTime();
|
|
4151
2373
|
currentTimeRef.current = time;
|
|
@@ -4233,15 +2455,14 @@ var WaveformPlaylistProvider = ({
|
|
|
4233
2455
|
setCurrentTimeRefs
|
|
4234
2456
|
]);
|
|
4235
2457
|
const stopAnimationLoop = stopAnimationFrameLoop;
|
|
4236
|
-
|
|
2458
|
+
useEffect5(() => {
|
|
4237
2459
|
const reschedulePlayback = () => __async(null, null, function* () {
|
|
4238
2460
|
if (isPlaying && animationFrameRef.current && engineRef.current) {
|
|
4239
2461
|
if (continuousPlay) {
|
|
4240
2462
|
const currentPos = currentTimeRef.current;
|
|
4241
2463
|
engineRef.current.stop();
|
|
4242
2464
|
stopAnimationLoop();
|
|
4243
|
-
const
|
|
4244
|
-
const timeNow = context.currentTime;
|
|
2465
|
+
const timeNow = getAudioContextTime();
|
|
4245
2466
|
playbackStartTimeRef.current = timeNow;
|
|
4246
2467
|
audioStartPositionRef.current = currentPos;
|
|
4247
2468
|
engineRef.current.play(currentPos);
|
|
@@ -4257,14 +2478,20 @@ var WaveformPlaylistProvider = ({
|
|
|
4257
2478
|
setIsPlaying(false);
|
|
4258
2479
|
stopAnimationLoop();
|
|
4259
2480
|
});
|
|
4260
|
-
}, [
|
|
4261
|
-
|
|
2481
|
+
}, [
|
|
2482
|
+
continuousPlay,
|
|
2483
|
+
isPlaying,
|
|
2484
|
+
startAnimationLoop,
|
|
2485
|
+
stopAnimationLoop,
|
|
2486
|
+
animationFrameRef,
|
|
2487
|
+
getAudioContextTime
|
|
2488
|
+
]);
|
|
2489
|
+
useEffect5(() => {
|
|
4262
2490
|
const resumePlayback = () => __async(null, null, function* () {
|
|
4263
2491
|
if (pendingResumeRef.current && engineRef.current) {
|
|
4264
2492
|
const { position } = pendingResumeRef.current;
|
|
4265
2493
|
pendingResumeRef.current = null;
|
|
4266
|
-
const
|
|
4267
|
-
const timeNow = context.currentTime;
|
|
2494
|
+
const timeNow = getAudioContextTime();
|
|
4268
2495
|
playbackStartTimeRef.current = timeNow;
|
|
4269
2496
|
audioStartPositionRef.current = position;
|
|
4270
2497
|
if (!audioInitializedRef.current) {
|
|
@@ -4281,8 +2508,8 @@ var WaveformPlaylistProvider = ({
|
|
|
4281
2508
|
setIsPlaying(false);
|
|
4282
2509
|
stopAnimationLoop();
|
|
4283
2510
|
});
|
|
4284
|
-
}, [tracks, startAnimationLoop, stopAnimationLoop]);
|
|
4285
|
-
const play =
|
|
2511
|
+
}, [tracks, startAnimationLoop, stopAnimationLoop, getAudioContextTime]);
|
|
2512
|
+
const play = useCallback13(
|
|
4286
2513
|
(startTime, playDuration) => __async(null, null, function* () {
|
|
4287
2514
|
if (!engineRef.current) return;
|
|
4288
2515
|
const actualStartTime = startTime != null ? startTime : currentTimeRef.current;
|
|
@@ -4291,8 +2518,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4291
2518
|
engineRef.current.stop();
|
|
4292
2519
|
engineRef.current.seek(actualStartTime);
|
|
4293
2520
|
stopAnimationLoop();
|
|
4294
|
-
const
|
|
4295
|
-
const startTimeNow = context.currentTime;
|
|
2521
|
+
const startTimeNow = getAudioContextTime();
|
|
4296
2522
|
playbackStartTimeRef.current = startTimeNow;
|
|
4297
2523
|
audioStartPositionRef.current = actualStartTime;
|
|
4298
2524
|
playbackEndTimeRef.current = playDuration !== void 0 ? actualStartTime + playDuration : null;
|
|
@@ -4311,9 +2537,9 @@ var WaveformPlaylistProvider = ({
|
|
|
4311
2537
|
setIsPlaying(true);
|
|
4312
2538
|
startAnimationLoop();
|
|
4313
2539
|
}),
|
|
4314
|
-
[startAnimationLoop, stopAnimationLoop, setCurrentTimeRefs]
|
|
2540
|
+
[startAnimationLoop, stopAnimationLoop, setCurrentTimeRefs, getAudioContextTime]
|
|
4315
2541
|
);
|
|
4316
|
-
const pause =
|
|
2542
|
+
const pause = useCallback13(() => {
|
|
4317
2543
|
if (!engineRef.current) return;
|
|
4318
2544
|
const pauseTime = getPlaybackTime();
|
|
4319
2545
|
engineRef.current.pause();
|
|
@@ -4322,7 +2548,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4322
2548
|
setCurrentTimeRefs(pauseTime);
|
|
4323
2549
|
setCurrentTime(pauseTime);
|
|
4324
2550
|
}, [stopAnimationLoop, getPlaybackTime, setCurrentTimeRefs]);
|
|
4325
|
-
const stop =
|
|
2551
|
+
const stop = useCallback13(() => {
|
|
4326
2552
|
if (!engineRef.current) return;
|
|
4327
2553
|
engineRef.current.stop();
|
|
4328
2554
|
setIsPlaying(false);
|
|
@@ -4331,7 +2557,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4331
2557
|
setCurrentTime(playStartPositionRef.current);
|
|
4332
2558
|
setActiveAnnotationId(null);
|
|
4333
2559
|
}, [stopAnimationLoop, setActiveAnnotationId, setCurrentTimeRefs]);
|
|
4334
|
-
const seekTo =
|
|
2560
|
+
const seekTo = useCallback13(
|
|
4335
2561
|
(time) => {
|
|
4336
2562
|
const clampedTime = Math.max(0, Math.min(time, duration));
|
|
4337
2563
|
setCurrentTimeRefs(clampedTime);
|
|
@@ -4342,7 +2568,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4342
2568
|
},
|
|
4343
2569
|
[duration, isPlaying, play, setCurrentTimeRefs]
|
|
4344
2570
|
);
|
|
4345
|
-
const setTrackMute =
|
|
2571
|
+
const setTrackMute = useCallback13(
|
|
4346
2572
|
(trackIndex, muted) => {
|
|
4347
2573
|
var _a2;
|
|
4348
2574
|
const trackId = (_a2 = tracksRef.current[trackIndex]) == null ? void 0 : _a2.id;
|
|
@@ -4356,7 +2582,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4356
2582
|
},
|
|
4357
2583
|
[trackStates]
|
|
4358
2584
|
);
|
|
4359
|
-
const setTrackSolo =
|
|
2585
|
+
const setTrackSolo = useCallback13(
|
|
4360
2586
|
(trackIndex, soloed) => {
|
|
4361
2587
|
var _a2;
|
|
4362
2588
|
const trackId = (_a2 = tracksRef.current[trackIndex]) == null ? void 0 : _a2.id;
|
|
@@ -4370,7 +2596,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4370
2596
|
},
|
|
4371
2597
|
[trackStates]
|
|
4372
2598
|
);
|
|
4373
|
-
const setTrackVolume =
|
|
2599
|
+
const setTrackVolume = useCallback13(
|
|
4374
2600
|
(trackIndex, volume2) => {
|
|
4375
2601
|
var _a2;
|
|
4376
2602
|
const trackId = (_a2 = tracksRef.current[trackIndex]) == null ? void 0 : _a2.id;
|
|
@@ -4384,7 +2610,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4384
2610
|
},
|
|
4385
2611
|
[trackStates]
|
|
4386
2612
|
);
|
|
4387
|
-
const setTrackPan =
|
|
2613
|
+
const setTrackPan = useCallback13(
|
|
4388
2614
|
(trackIndex, pan) => {
|
|
4389
2615
|
var _a2;
|
|
4390
2616
|
const trackId = (_a2 = tracksRef.current[trackIndex]) == null ? void 0 : _a2.id;
|
|
@@ -4398,7 +2624,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4398
2624
|
},
|
|
4399
2625
|
[trackStates]
|
|
4400
2626
|
);
|
|
4401
|
-
const setSelection =
|
|
2627
|
+
const setSelection = useCallback13(
|
|
4402
2628
|
(start, end) => {
|
|
4403
2629
|
setSelectionEngine(start, end);
|
|
4404
2630
|
setCurrentTimeRefs(start);
|
|
@@ -4411,12 +2637,12 @@ var WaveformPlaylistProvider = ({
|
|
|
4411
2637
|
},
|
|
4412
2638
|
[isPlaying, setSelectionEngine, setCurrentTimeRefs]
|
|
4413
2639
|
);
|
|
4414
|
-
const setScrollContainer =
|
|
2640
|
+
const setScrollContainer = useCallback13((element) => {
|
|
4415
2641
|
scrollContainerRef.current = element;
|
|
4416
2642
|
}, []);
|
|
4417
|
-
const onAnnotationsChangeRef =
|
|
2643
|
+
const onAnnotationsChangeRef = useRef9(onAnnotationsChange);
|
|
4418
2644
|
onAnnotationsChangeRef.current = onAnnotationsChange;
|
|
4419
|
-
const setAnnotations =
|
|
2645
|
+
const setAnnotations = useCallback13(
|
|
4420
2646
|
(action) => {
|
|
4421
2647
|
const updated = typeof action === "function" ? action(annotationsRef.current) : action;
|
|
4422
2648
|
if (!onAnnotationsChangeRef.current) {
|
|
@@ -4434,7 +2660,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4434
2660
|
const sampleRate = sampleRateRef.current;
|
|
4435
2661
|
const timeScaleHeight = timescale ? 30 : 0;
|
|
4436
2662
|
const minimumPlaylistHeight = tracks.length * waveHeight + timeScaleHeight;
|
|
4437
|
-
const animationValue =
|
|
2663
|
+
const animationValue = useMemo3(
|
|
4438
2664
|
() => ({
|
|
4439
2665
|
isPlaying,
|
|
4440
2666
|
currentTime,
|
|
@@ -4443,7 +2669,9 @@ var WaveformPlaylistProvider = ({
|
|
|
4443
2669
|
playbackStartTimeRef,
|
|
4444
2670
|
audioStartPositionRef,
|
|
4445
2671
|
getPlaybackTime,
|
|
2672
|
+
getAudioContextTime,
|
|
4446
2673
|
getLookAhead,
|
|
2674
|
+
getOutputLatency,
|
|
4447
2675
|
registerFrameCallback,
|
|
4448
2676
|
unregisterFrameCallback
|
|
4449
2677
|
}),
|
|
@@ -4455,12 +2683,14 @@ var WaveformPlaylistProvider = ({
|
|
|
4455
2683
|
playbackStartTimeRef,
|
|
4456
2684
|
audioStartPositionRef,
|
|
4457
2685
|
getPlaybackTime,
|
|
2686
|
+
getAudioContextTime,
|
|
4458
2687
|
getLookAhead,
|
|
2688
|
+
getOutputLatency,
|
|
4459
2689
|
registerFrameCallback,
|
|
4460
2690
|
unregisterFrameCallback
|
|
4461
2691
|
]
|
|
4462
2692
|
);
|
|
4463
|
-
const stateValue =
|
|
2693
|
+
const stateValue = useMemo3(
|
|
4464
2694
|
() => ({
|
|
4465
2695
|
continuousPlay,
|
|
4466
2696
|
linkEndpoints,
|
|
@@ -4496,17 +2726,17 @@ var WaveformPlaylistProvider = ({
|
|
|
4496
2726
|
canRedo
|
|
4497
2727
|
]
|
|
4498
2728
|
);
|
|
4499
|
-
const setCurrentTimeControl =
|
|
2729
|
+
const setCurrentTimeControl = useCallback13(
|
|
4500
2730
|
(time) => {
|
|
4501
2731
|
setCurrentTimeRefs(time);
|
|
4502
2732
|
setCurrentTime(time);
|
|
4503
2733
|
},
|
|
4504
2734
|
[setCurrentTimeRefs]
|
|
4505
2735
|
);
|
|
4506
|
-
const setAutomaticScrollControl =
|
|
2736
|
+
const setAutomaticScrollControl = useCallback13((enabled) => {
|
|
4507
2737
|
setIsAutomaticScroll(enabled);
|
|
4508
2738
|
}, []);
|
|
4509
|
-
const controlsValue =
|
|
2739
|
+
const controlsValue = useMemo3(
|
|
4510
2740
|
() => ({
|
|
4511
2741
|
// Playback controls
|
|
4512
2742
|
play,
|
|
@@ -4582,7 +2812,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4582
2812
|
redo
|
|
4583
2813
|
]
|
|
4584
2814
|
);
|
|
4585
|
-
const dataValue =
|
|
2815
|
+
const dataValue = useMemo3(
|
|
4586
2816
|
() => ({
|
|
4587
2817
|
duration,
|
|
4588
2818
|
audioBuffers,
|
|
@@ -4671,14 +2901,38 @@ var usePlaylistDataOptional = () => useContext(PlaylistDataContext);
|
|
|
4671
2901
|
import {
|
|
4672
2902
|
createContext as createContext2,
|
|
4673
2903
|
useContext as useContext2,
|
|
4674
|
-
useState as
|
|
4675
|
-
useEffect as
|
|
4676
|
-
useRef as
|
|
4677
|
-
useCallback as
|
|
4678
|
-
useMemo as
|
|
2904
|
+
useState as useState10,
|
|
2905
|
+
useEffect as useEffect6,
|
|
2906
|
+
useRef as useRef10,
|
|
2907
|
+
useCallback as useCallback14,
|
|
2908
|
+
useMemo as useMemo4
|
|
4679
2909
|
} from "react";
|
|
4680
2910
|
import { ThemeProvider as ThemeProvider2 } from "styled-components";
|
|
4681
|
-
|
|
2911
|
+
|
|
2912
|
+
// src/playout/resolveMediaElementPlayout.ts
|
|
2913
|
+
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`.";
|
|
2914
|
+
function resolveMediaElementPlayout(opts) {
|
|
2915
|
+
return __async(this, null, function* () {
|
|
2916
|
+
if (opts.createPlayout) {
|
|
2917
|
+
return opts.createPlayout();
|
|
2918
|
+
}
|
|
2919
|
+
let mod;
|
|
2920
|
+
try {
|
|
2921
|
+
mod = yield import("@waveform-playlist/media-element-playout");
|
|
2922
|
+
} catch (originalErr) {
|
|
2923
|
+
console.warn(
|
|
2924
|
+
"[waveform-playlist] @waveform-playlist/media-element-playout dynamic import failed: " + String(originalErr)
|
|
2925
|
+
);
|
|
2926
|
+
throw new Error(INSTALL_HINT2);
|
|
2927
|
+
}
|
|
2928
|
+
return new mod.MediaElementPlayout({
|
|
2929
|
+
playbackRate: opts.playbackRate,
|
|
2930
|
+
preservesPitch: opts.preservesPitch
|
|
2931
|
+
});
|
|
2932
|
+
});
|
|
2933
|
+
}
|
|
2934
|
+
|
|
2935
|
+
// src/MediaElementPlaylistContext.tsx
|
|
4682
2936
|
import { defaultTheme as defaultTheme2 } from "@waveform-playlist/ui-components";
|
|
4683
2937
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
4684
2938
|
var MediaElementAnimationContext = createContext2(null);
|
|
@@ -4702,16 +2956,18 @@ var MediaElementPlaylistProvider = ({
|
|
|
4702
2956
|
audioContext,
|
|
4703
2957
|
onAnnotationsChange,
|
|
4704
2958
|
onReady,
|
|
2959
|
+
onError,
|
|
2960
|
+
createPlayout,
|
|
4705
2961
|
children
|
|
4706
2962
|
}) => {
|
|
4707
2963
|
var _a;
|
|
4708
2964
|
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 =
|
|
2965
|
+
const [isPlaying, setIsPlaying] = useState10(false);
|
|
2966
|
+
const [currentTime, setCurrentTime] = useState10(0);
|
|
2967
|
+
const [duration, setDuration] = useState10(0);
|
|
2968
|
+
const [peaksDataArray, setPeaksDataArray] = useState10([]);
|
|
2969
|
+
const [playbackRate, setPlaybackRateState] = useState10(initialPlaybackRate);
|
|
2970
|
+
const annotations = useMemo4(() => {
|
|
4715
2971
|
if (!(annotationList == null ? void 0 : annotationList.annotations)) return [];
|
|
4716
2972
|
if (process.env.NODE_ENV !== "production" && annotationList.annotations.length > 0) {
|
|
4717
2973
|
const first = annotationList.annotations[0];
|
|
@@ -4724,73 +2980,92 @@ var MediaElementPlaylistProvider = ({
|
|
|
4724
2980
|
}
|
|
4725
2981
|
return annotationList.annotations;
|
|
4726
2982
|
}, [annotationList == null ? void 0 : annotationList.annotations]);
|
|
4727
|
-
const annotationsRef =
|
|
2983
|
+
const annotationsRef = useRef10(annotations);
|
|
4728
2984
|
annotationsRef.current = annotations;
|
|
4729
|
-
const [activeAnnotationId, setActiveAnnotationIdState] =
|
|
4730
|
-
const [continuousPlay, setContinuousPlayState] =
|
|
2985
|
+
const [activeAnnotationId, setActiveAnnotationIdState] = useState10(null);
|
|
2986
|
+
const [continuousPlay, setContinuousPlayState] = useState10(
|
|
4731
2987
|
(_a = annotationList == null ? void 0 : annotationList.isContinuousPlay) != null ? _a : false
|
|
4732
2988
|
);
|
|
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 =
|
|
2989
|
+
const [samplesPerPixel] = useState10(initialSamplesPerPixel);
|
|
2990
|
+
const [isAutomaticScroll, setIsAutomaticScroll] = useState10(automaticScroll);
|
|
2991
|
+
const playoutRef = useRef10(null);
|
|
2992
|
+
const currentTimeRef = useRef10(0);
|
|
2993
|
+
const continuousPlayRef = useRef10(continuousPlay);
|
|
2994
|
+
const activeAnnotationIdRef = useRef10(null);
|
|
2995
|
+
const scrollContainerRef = useRef10(null);
|
|
2996
|
+
const isAutomaticScrollRef = useRef10(automaticScroll);
|
|
2997
|
+
const samplesPerPixelRef = useRef10(initialSamplesPerPixel);
|
|
4742
2998
|
const { startAnimationFrameLoop, stopAnimationFrameLoop } = useAnimationFrameLoop();
|
|
4743
|
-
|
|
2999
|
+
useEffect6(() => {
|
|
4744
3000
|
continuousPlayRef.current = continuousPlay;
|
|
4745
3001
|
}, [continuousPlay]);
|
|
4746
|
-
|
|
3002
|
+
useEffect6(() => {
|
|
4747
3003
|
isAutomaticScrollRef.current = isAutomaticScroll;
|
|
4748
3004
|
}, [isAutomaticScroll]);
|
|
4749
|
-
const setActiveAnnotationId =
|
|
3005
|
+
const setActiveAnnotationId = useCallback14((value) => {
|
|
4750
3006
|
activeAnnotationIdRef.current = value;
|
|
4751
3007
|
setActiveAnnotationIdState(value);
|
|
4752
3008
|
}, []);
|
|
4753
|
-
const setContinuousPlay =
|
|
3009
|
+
const setContinuousPlay = useCallback14((value) => {
|
|
4754
3010
|
continuousPlayRef.current = value;
|
|
4755
3011
|
setContinuousPlayState(value);
|
|
4756
3012
|
}, []);
|
|
4757
|
-
const setScrollContainer =
|
|
3013
|
+
const setScrollContainer = useCallback14((element) => {
|
|
4758
3014
|
scrollContainerRef.current = element;
|
|
4759
3015
|
}, []);
|
|
4760
3016
|
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
|
-
|
|
3017
|
+
useEffect6(() => {
|
|
3018
|
+
let cancelled = false;
|
|
3019
|
+
let createdPlayout = null;
|
|
3020
|
+
(() => __async(null, null, function* () {
|
|
3021
|
+
var _a2, _b;
|
|
3022
|
+
try {
|
|
3023
|
+
const playout = yield resolveMediaElementPlayout({
|
|
3024
|
+
createPlayout,
|
|
3025
|
+
playbackRate: initialPlaybackRate,
|
|
3026
|
+
preservesPitch
|
|
3027
|
+
});
|
|
3028
|
+
if (cancelled) {
|
|
3029
|
+
playout.dispose();
|
|
3030
|
+
return;
|
|
3031
|
+
}
|
|
3032
|
+
createdPlayout = playout;
|
|
3033
|
+
playout.addTrack({
|
|
3034
|
+
source: track.source,
|
|
3035
|
+
peaks: track.waveformData,
|
|
3036
|
+
name: track.name,
|
|
3037
|
+
audioContext,
|
|
3038
|
+
fadeIn: track.fadeIn,
|
|
3039
|
+
fadeOut: track.fadeOut
|
|
3040
|
+
});
|
|
3041
|
+
const mediaTrack = playout.getTrack((_b = (_a2 = playout["track"]) == null ? void 0 : _a2.id) != null ? _b : "");
|
|
3042
|
+
if (mediaTrack) {
|
|
3043
|
+
mediaTrack.setOnTimeUpdateCallback((time) => {
|
|
3044
|
+
currentTimeRef.current = time;
|
|
3045
|
+
});
|
|
3046
|
+
}
|
|
3047
|
+
playout.setOnPlaybackComplete(() => {
|
|
3048
|
+
stopAnimationFrameLoop();
|
|
3049
|
+
setIsPlaying(false);
|
|
3050
|
+
setActiveAnnotationId(null);
|
|
3051
|
+
currentTimeRef.current = 0;
|
|
3052
|
+
setCurrentTime(0);
|
|
3053
|
+
});
|
|
3054
|
+
playoutRef.current = playout;
|
|
3055
|
+
setDuration(track.waveformData.duration);
|
|
3056
|
+
onReady == null ? void 0 : onReady();
|
|
3057
|
+
} catch (err) {
|
|
3058
|
+
console.warn("[waveform-playlist] MediaElement playout init failed: " + String(err));
|
|
3059
|
+
onError == null ? void 0 : onError(err instanceof Error ? err : new Error(String(err)));
|
|
3060
|
+
}
|
|
3061
|
+
}))();
|
|
4791
3062
|
return () => {
|
|
3063
|
+
cancelled = true;
|
|
4792
3064
|
stopAnimationFrameLoop();
|
|
4793
|
-
|
|
3065
|
+
if (createdPlayout) {
|
|
3066
|
+
createdPlayout.dispose();
|
|
3067
|
+
}
|
|
3068
|
+
playoutRef.current = null;
|
|
4794
3069
|
};
|
|
4795
3070
|
}, [
|
|
4796
3071
|
track.source,
|
|
@@ -4802,10 +3077,12 @@ var MediaElementPlaylistProvider = ({
|
|
|
4802
3077
|
initialPlaybackRate,
|
|
4803
3078
|
preservesPitch,
|
|
4804
3079
|
onReady,
|
|
3080
|
+
onError,
|
|
4805
3081
|
stopAnimationFrameLoop,
|
|
4806
|
-
setActiveAnnotationId
|
|
3082
|
+
setActiveAnnotationId,
|
|
3083
|
+
createPlayout
|
|
4807
3084
|
]);
|
|
4808
|
-
|
|
3085
|
+
useEffect6(() => {
|
|
4809
3086
|
var _a2;
|
|
4810
3087
|
try {
|
|
4811
3088
|
const extractedPeaks = extractPeaksFromWaveformData(
|
|
@@ -4834,7 +3111,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4834
3111
|
console.warn("[waveform-playlist] Failed to extract peaks from waveform data:", err);
|
|
4835
3112
|
}
|
|
4836
3113
|
}, [track.waveformData, track.name, samplesPerPixel, sampleRate]);
|
|
4837
|
-
const startAnimationLoop =
|
|
3114
|
+
const startAnimationLoop = useCallback14(() => {
|
|
4838
3115
|
const updateTime = () => {
|
|
4839
3116
|
var _a2, _b, _c;
|
|
4840
3117
|
const time = (_b = (_a2 = playoutRef.current) == null ? void 0 : _a2.getCurrentTime()) != null ? _b : 0;
|
|
@@ -4877,7 +3154,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4877
3154
|
startAnimationFrameLoop(updateTime);
|
|
4878
3155
|
}, [setActiveAnnotationId, sampleRate, startAnimationFrameLoop]);
|
|
4879
3156
|
const stopAnimationLoop = stopAnimationFrameLoop;
|
|
4880
|
-
const play =
|
|
3157
|
+
const play = useCallback14(
|
|
4881
3158
|
(startTime) => {
|
|
4882
3159
|
if (!playoutRef.current) return;
|
|
4883
3160
|
const actualStartTime = startTime != null ? startTime : currentTimeRef.current;
|
|
@@ -4887,14 +3164,14 @@ var MediaElementPlaylistProvider = ({
|
|
|
4887
3164
|
},
|
|
4888
3165
|
[startAnimationLoop]
|
|
4889
3166
|
);
|
|
4890
|
-
const pause =
|
|
3167
|
+
const pause = useCallback14(() => {
|
|
4891
3168
|
if (!playoutRef.current) return;
|
|
4892
3169
|
playoutRef.current.pause();
|
|
4893
3170
|
setIsPlaying(false);
|
|
4894
3171
|
stopAnimationLoop();
|
|
4895
3172
|
setCurrentTime(playoutRef.current.getCurrentTime());
|
|
4896
3173
|
}, [stopAnimationLoop]);
|
|
4897
|
-
const stop =
|
|
3174
|
+
const stop = useCallback14(() => {
|
|
4898
3175
|
if (!playoutRef.current) return;
|
|
4899
3176
|
playoutRef.current.stop();
|
|
4900
3177
|
setIsPlaying(false);
|
|
@@ -4903,7 +3180,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4903
3180
|
setCurrentTime(0);
|
|
4904
3181
|
setActiveAnnotationId(null);
|
|
4905
3182
|
}, [stopAnimationLoop, setActiveAnnotationId]);
|
|
4906
|
-
const seekTo =
|
|
3183
|
+
const seekTo = useCallback14(
|
|
4907
3184
|
(time) => {
|
|
4908
3185
|
const clampedTime = Math.max(0, Math.min(time, duration));
|
|
4909
3186
|
currentTimeRef.current = clampedTime;
|
|
@@ -4914,7 +3191,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4914
3191
|
},
|
|
4915
3192
|
[duration]
|
|
4916
3193
|
);
|
|
4917
|
-
const setPlaybackRate =
|
|
3194
|
+
const setPlaybackRate = useCallback14((rate) => {
|
|
4918
3195
|
const clampedRate = Math.max(0.5, Math.min(2, rate));
|
|
4919
3196
|
setPlaybackRateState(clampedRate);
|
|
4920
3197
|
if (playoutRef.current) {
|
|
@@ -4922,7 +3199,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4922
3199
|
}
|
|
4923
3200
|
}, []);
|
|
4924
3201
|
const timeScaleHeight = timescale ? 30 : 0;
|
|
4925
|
-
const animationValue =
|
|
3202
|
+
const animationValue = useMemo4(
|
|
4926
3203
|
() => ({
|
|
4927
3204
|
isPlaying,
|
|
4928
3205
|
currentTime,
|
|
@@ -4930,7 +3207,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4930
3207
|
}),
|
|
4931
3208
|
[isPlaying, currentTime]
|
|
4932
3209
|
);
|
|
4933
|
-
const stateValue =
|
|
3210
|
+
const stateValue = useMemo4(
|
|
4934
3211
|
() => ({
|
|
4935
3212
|
continuousPlay,
|
|
4936
3213
|
annotations,
|
|
@@ -4940,9 +3217,9 @@ var MediaElementPlaylistProvider = ({
|
|
|
4940
3217
|
}),
|
|
4941
3218
|
[continuousPlay, annotations, activeAnnotationId, playbackRate, isAutomaticScroll]
|
|
4942
3219
|
);
|
|
4943
|
-
const onAnnotationsChangeRef =
|
|
3220
|
+
const onAnnotationsChangeRef = useRef10(onAnnotationsChange);
|
|
4944
3221
|
onAnnotationsChangeRef.current = onAnnotationsChange;
|
|
4945
|
-
const setAnnotations =
|
|
3222
|
+
const setAnnotations = useCallback14(
|
|
4946
3223
|
(action) => {
|
|
4947
3224
|
const updated = typeof action === "function" ? action(annotationsRef.current) : action;
|
|
4948
3225
|
if (!onAnnotationsChangeRef.current) {
|
|
@@ -4957,7 +3234,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4957
3234
|
},
|
|
4958
3235
|
[]
|
|
4959
3236
|
);
|
|
4960
|
-
const controlsValue =
|
|
3237
|
+
const controlsValue = useMemo4(
|
|
4961
3238
|
() => ({
|
|
4962
3239
|
play,
|
|
4963
3240
|
pause,
|
|
@@ -4985,7 +3262,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4985
3262
|
setScrollContainer
|
|
4986
3263
|
]
|
|
4987
3264
|
);
|
|
4988
|
-
const dataValue =
|
|
3265
|
+
const dataValue = useMemo4(
|
|
4989
3266
|
() => ({
|
|
4990
3267
|
duration,
|
|
4991
3268
|
peaksDataArray,
|
|
@@ -5049,7 +3326,7 @@ var useMediaElementData = () => {
|
|
|
5049
3326
|
};
|
|
5050
3327
|
|
|
5051
3328
|
// src/components/PlaybackControls.tsx
|
|
5052
|
-
import { useCallback as
|
|
3329
|
+
import { useCallback as useCallback15 } from "react";
|
|
5053
3330
|
import { BaseControlButton } from "@waveform-playlist/ui-components";
|
|
5054
3331
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
5055
3332
|
var PlayButton = ({ className }) => {
|
|
@@ -5185,7 +3462,7 @@ var ClearAllButton = ({
|
|
|
5185
3462
|
className
|
|
5186
3463
|
}) => {
|
|
5187
3464
|
const { stop } = usePlaylistControls();
|
|
5188
|
-
const handleClick =
|
|
3465
|
+
const handleClick = useCallback15(() => {
|
|
5189
3466
|
stop();
|
|
5190
3467
|
onClearAll();
|
|
5191
3468
|
}, [stop, onClearAll]);
|
|
@@ -5213,7 +3490,7 @@ var ZoomOutButton = ({
|
|
|
5213
3490
|
};
|
|
5214
3491
|
|
|
5215
3492
|
// src/components/ContextualControls.tsx
|
|
5216
|
-
import { useRef as
|
|
3493
|
+
import { useRef as useRef11, useEffect as useEffect7 } from "react";
|
|
5217
3494
|
import {
|
|
5218
3495
|
MasterVolumeControl as BaseMasterVolumeControl,
|
|
5219
3496
|
TimeFormatSelect as BaseTimeFormatSelect,
|
|
@@ -5252,10 +3529,10 @@ var PositionDisplay = styled.span`
|
|
|
5252
3529
|
`;
|
|
5253
3530
|
var AudioPosition = ({ className }) => {
|
|
5254
3531
|
var _a;
|
|
5255
|
-
const timeRef =
|
|
3532
|
+
const timeRef = useRef11(null);
|
|
5256
3533
|
const { isPlaying, currentTimeRef, registerFrameCallback, unregisterFrameCallback } = usePlaybackAnimation();
|
|
5257
3534
|
const { timeFormat: format } = usePlaylistData();
|
|
5258
|
-
|
|
3535
|
+
useEffect7(() => {
|
|
5259
3536
|
const id = "audio-position";
|
|
5260
3537
|
if (isPlaying) {
|
|
5261
3538
|
registerFrameCallback(id, ({ time }) => {
|
|
@@ -5266,7 +3543,7 @@ var AudioPosition = ({ className }) => {
|
|
|
5266
3543
|
}
|
|
5267
3544
|
return () => unregisterFrameCallback(id);
|
|
5268
3545
|
}, [isPlaying, format, registerFrameCallback, unregisterFrameCallback]);
|
|
5269
|
-
|
|
3546
|
+
useEffect7(() => {
|
|
5270
3547
|
var _a2;
|
|
5271
3548
|
if (!isPlaying && timeRef.current) {
|
|
5272
3549
|
timeRef.current.textContent = formatTime((_a2 = currentTimeRef.current) != null ? _a2 : 0, format);
|
|
@@ -5343,53 +3620,6 @@ var DownloadAnnotationsButton = ({
|
|
|
5343
3620
|
return /* @__PURE__ */ jsx6(Base, { annotations, filename, className });
|
|
5344
3621
|
};
|
|
5345
3622
|
|
|
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
3623
|
// src/contexts/ClipInteractionContext.tsx
|
|
5394
3624
|
import { createContext as createContext4, useContext as useContext4 } from "react";
|
|
5395
3625
|
var ClipInteractionContext = createContext4(false);
|
|
@@ -5399,10 +3629,9 @@ function useClipInteractionEnabled() {
|
|
|
5399
3629
|
}
|
|
5400
3630
|
|
|
5401
3631
|
// src/components/PlaylistVisualization.tsx
|
|
5402
|
-
import { useContext as useContext6, useRef as
|
|
3632
|
+
import { useContext as useContext6, useRef as useRef14, useState as useState11, useMemo as useMemo5, useCallback as useCallback16 } from "react";
|
|
5403
3633
|
import { createPortal } from "react-dom";
|
|
5404
3634
|
import styled4 from "styled-components";
|
|
5405
|
-
import { getGlobalAudioContext as getGlobalAudioContext5 } from "@waveform-playlist/playout";
|
|
5406
3635
|
import {
|
|
5407
3636
|
Playlist,
|
|
5408
3637
|
Track as TrackComponent,
|
|
@@ -5427,12 +3656,12 @@ import {
|
|
|
5427
3656
|
SpectrogramLabels,
|
|
5428
3657
|
CLIP_HEADER_HEIGHT
|
|
5429
3658
|
} from "@waveform-playlist/ui-components";
|
|
5430
|
-
import {
|
|
3659
|
+
import { resolveRecordingOffsetSamples } from "@waveform-playlist/core";
|
|
5431
3660
|
|
|
5432
3661
|
// src/components/AnimatedPlayhead.tsx
|
|
5433
|
-
import { useRef as
|
|
3662
|
+
import { useRef as useRef12, useEffect as useEffect8 } from "react";
|
|
5434
3663
|
import styled2 from "styled-components";
|
|
5435
|
-
import { jsx as
|
|
3664
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
5436
3665
|
var PlayheadLine = styled2.div.attrs((props) => ({
|
|
5437
3666
|
style: {
|
|
5438
3667
|
width: `${props.$width}px`,
|
|
@@ -5448,7 +3677,7 @@ var PlayheadLine = styled2.div.attrs((props) => ({
|
|
|
5448
3677
|
will-change: transform;
|
|
5449
3678
|
`;
|
|
5450
3679
|
var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
5451
|
-
const playheadRef =
|
|
3680
|
+
const playheadRef = useRef12(null);
|
|
5452
3681
|
const {
|
|
5453
3682
|
isPlaying,
|
|
5454
3683
|
currentTimeRef,
|
|
@@ -5457,7 +3686,7 @@ var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
|
5457
3686
|
unregisterFrameCallback
|
|
5458
3687
|
} = usePlaybackAnimation();
|
|
5459
3688
|
const { samplesPerPixel, sampleRate, progressBarWidth } = usePlaylistData();
|
|
5460
|
-
|
|
3689
|
+
useEffect8(() => {
|
|
5461
3690
|
const id = "playhead";
|
|
5462
3691
|
if (isPlaying) {
|
|
5463
3692
|
registerFrameCallback(id, ({ visualTime, sampleRate: sr, samplesPerPixel: spp }) => {
|
|
@@ -5469,7 +3698,7 @@ var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
|
5469
3698
|
}
|
|
5470
3699
|
return () => unregisterFrameCallback(id);
|
|
5471
3700
|
}, [isPlaying, registerFrameCallback, unregisterFrameCallback]);
|
|
5472
|
-
|
|
3701
|
+
useEffect8(() => {
|
|
5473
3702
|
var _a, _b;
|
|
5474
3703
|
if (!isPlaying && playheadRef.current) {
|
|
5475
3704
|
const time = (_b = (_a = visualTimeRef.current) != null ? _a : currentTimeRef.current) != null ? _b : 0;
|
|
@@ -5477,11 +3706,11 @@ var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
|
5477
3706
|
playheadRef.current.style.transform = `translate3d(${position}px, 0, 0)`;
|
|
5478
3707
|
}
|
|
5479
3708
|
});
|
|
5480
|
-
return /* @__PURE__ */
|
|
3709
|
+
return /* @__PURE__ */ jsx7(PlayheadLine, { ref: playheadRef, $color: color, $width: progressBarWidth, "data-playhead": true });
|
|
5481
3710
|
};
|
|
5482
3711
|
|
|
5483
3712
|
// src/components/ChannelWithProgress.tsx
|
|
5484
|
-
import { useId, useRef as
|
|
3713
|
+
import { useId, useRef as useRef13, useEffect as useEffect9 } from "react";
|
|
5485
3714
|
import styled3 from "styled-components";
|
|
5486
3715
|
import {
|
|
5487
3716
|
clipPixelWidth as computeClipPixelWidth
|
|
@@ -5492,7 +3721,7 @@ import {
|
|
|
5492
3721
|
usePlaylistInfo,
|
|
5493
3722
|
waveformColorToCss
|
|
5494
3723
|
} from "@waveform-playlist/ui-components";
|
|
5495
|
-
import { Fragment, jsx as
|
|
3724
|
+
import { Fragment, jsx as jsx8, jsxs } from "react/jsx-runtime";
|
|
5496
3725
|
var ChannelWrapper = styled3.div`
|
|
5497
3726
|
position: relative;
|
|
5498
3727
|
`;
|
|
@@ -5546,7 +3775,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5546
3775
|
"clipSampleRate",
|
|
5547
3776
|
"clipOffsetSeconds"
|
|
5548
3777
|
]);
|
|
5549
|
-
const progressRef =
|
|
3778
|
+
const progressRef = useRef13(null);
|
|
5550
3779
|
const callbackId = useId();
|
|
5551
3780
|
const theme = useTheme();
|
|
5552
3781
|
const { waveHeight } = usePlaylistInfo();
|
|
@@ -5564,7 +3793,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5564
3793
|
clipDurationSamples,
|
|
5565
3794
|
samplesPerPixel
|
|
5566
3795
|
);
|
|
5567
|
-
|
|
3796
|
+
useEffect9(() => {
|
|
5568
3797
|
if (isPlaying) {
|
|
5569
3798
|
registerFrameCallback(callbackId, ({ visualTime, sampleRate: sr }) => {
|
|
5570
3799
|
if (progressRef.current) {
|
|
@@ -5592,7 +3821,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5592
3821
|
registerFrameCallback,
|
|
5593
3822
|
unregisterFrameCallback
|
|
5594
3823
|
]);
|
|
5595
|
-
|
|
3824
|
+
useEffect9(() => {
|
|
5596
3825
|
var _a2, _b2;
|
|
5597
3826
|
if (!isPlaying && progressRef.current) {
|
|
5598
3827
|
const currentTime = (_b2 = (_a2 = visualTimeRef.current) != null ? _a2 : currentTimeRef.current) != null ? _b2 : 0;
|
|
@@ -5627,7 +3856,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5627
3856
|
const waveformBackgroundCss = waveformColorToCss(backgroundColor);
|
|
5628
3857
|
return /* @__PURE__ */ jsxs(ChannelWrapper, { children: [
|
|
5629
3858
|
isBothMode ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5630
|
-
/* @__PURE__ */
|
|
3859
|
+
/* @__PURE__ */ jsx8(
|
|
5631
3860
|
Background,
|
|
5632
3861
|
{
|
|
5633
3862
|
$color: "#000",
|
|
@@ -5636,7 +3865,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5636
3865
|
$width: smartChannelProps.length
|
|
5637
3866
|
}
|
|
5638
3867
|
),
|
|
5639
|
-
/* @__PURE__ */
|
|
3868
|
+
/* @__PURE__ */ jsx8(
|
|
5640
3869
|
Background,
|
|
5641
3870
|
{
|
|
5642
3871
|
$color: waveformBackgroundCss,
|
|
@@ -5645,7 +3874,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5645
3874
|
$width: smartChannelProps.length
|
|
5646
3875
|
}
|
|
5647
3876
|
)
|
|
5648
|
-
] }) : /* @__PURE__ */
|
|
3877
|
+
] }) : /* @__PURE__ */ jsx8(
|
|
5649
3878
|
Background,
|
|
5650
3879
|
{
|
|
5651
3880
|
$color: backgroundCss,
|
|
@@ -5654,7 +3883,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5654
3883
|
$width: smartChannelProps.length
|
|
5655
3884
|
}
|
|
5656
3885
|
),
|
|
5657
|
-
!isPianoRollMode && /* @__PURE__ */
|
|
3886
|
+
!isPianoRollMode && /* @__PURE__ */ jsx8(
|
|
5658
3887
|
ProgressOverlay,
|
|
5659
3888
|
{
|
|
5660
3889
|
ref: progressRef,
|
|
@@ -5664,7 +3893,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5664
3893
|
$width: clipPixelWidth
|
|
5665
3894
|
}
|
|
5666
3895
|
),
|
|
5667
|
-
/* @__PURE__ */
|
|
3896
|
+
/* @__PURE__ */ jsx8(ChannelContainer, { children: /* @__PURE__ */ jsx8(
|
|
5668
3897
|
SmartChannel,
|
|
5669
3898
|
__spreadProps(__spreadValues({}, smartChannelProps), {
|
|
5670
3899
|
transparentBackground: true,
|
|
@@ -5691,7 +3920,7 @@ function useSpectrogramIntegration() {
|
|
|
5691
3920
|
}
|
|
5692
3921
|
|
|
5693
3922
|
// src/components/PlaylistVisualization.tsx
|
|
5694
|
-
import { Fragment as Fragment2, jsx as
|
|
3923
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
5695
3924
|
var DEFAULT_EMPTY_TRACK_DURATION = 60;
|
|
5696
3925
|
var ControlSlot = styled4.div.attrs((props) => ({
|
|
5697
3926
|
style: { height: `${props.$height}px` }
|
|
@@ -5710,7 +3939,8 @@ var CustomPlayhead = ({ renderPlayhead, color, samplesPerPixel, sampleRate }) =>
|
|
|
5710
3939
|
visualTimeRef,
|
|
5711
3940
|
playbackStartTimeRef,
|
|
5712
3941
|
audioStartPositionRef,
|
|
5713
|
-
getPlaybackTime
|
|
3942
|
+
getPlaybackTime,
|
|
3943
|
+
getAudioContextTime
|
|
5714
3944
|
} = usePlaybackAnimation();
|
|
5715
3945
|
const visualTime = (_b = (_a = visualTimeRef.current) != null ? _a : currentTimeRef.current) != null ? _b : 0;
|
|
5716
3946
|
return renderPlayhead({
|
|
@@ -5724,7 +3954,7 @@ var CustomPlayhead = ({ renderPlayhead, color, samplesPerPixel, sampleRate }) =>
|
|
|
5724
3954
|
samplesPerPixel,
|
|
5725
3955
|
sampleRate,
|
|
5726
3956
|
controlsOffset: 0,
|
|
5727
|
-
getAudioContextTime
|
|
3957
|
+
getAudioContextTime,
|
|
5728
3958
|
getPlaybackTime
|
|
5729
3959
|
});
|
|
5730
3960
|
};
|
|
@@ -5749,7 +3979,7 @@ var PlaylistVisualization = ({
|
|
|
5749
3979
|
}) => {
|
|
5750
3980
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
5751
3981
|
const theme = useTheme2();
|
|
5752
|
-
const { isPlaying, getLookAhead } = usePlaybackAnimation();
|
|
3982
|
+
const { isPlaying, getLookAhead, getOutputLatency } = usePlaybackAnimation();
|
|
5753
3983
|
const {
|
|
5754
3984
|
selectionStart,
|
|
5755
3985
|
selectionEnd,
|
|
@@ -5795,7 +4025,7 @@ var PlaylistVisualization = ({
|
|
|
5795
4025
|
mono
|
|
5796
4026
|
} = usePlaylistData();
|
|
5797
4027
|
const spectrogram = useContext6(SpectrogramIntegrationContext);
|
|
5798
|
-
const perTrackSpectrogramHelpers =
|
|
4028
|
+
const perTrackSpectrogramHelpers = useMemo5(() => {
|
|
5799
4029
|
if (!spectrogram)
|
|
5800
4030
|
return /* @__PURE__ */ new Map();
|
|
5801
4031
|
const helpers = /* @__PURE__ */ new Map();
|
|
@@ -5814,11 +4044,11 @@ var PlaylistVisualization = ({
|
|
|
5814
4044
|
});
|
|
5815
4045
|
return helpers;
|
|
5816
4046
|
}, [tracks, spectrogram]);
|
|
5817
|
-
const [settingsModalTrackId, setSettingsModalTrackId] =
|
|
5818
|
-
const [isSelecting, setIsSelecting] =
|
|
5819
|
-
const mouseDownTimeRef =
|
|
5820
|
-
const scrollContainerRef =
|
|
5821
|
-
const handleScrollContainerRef =
|
|
4047
|
+
const [settingsModalTrackId, setSettingsModalTrackId] = useState11(null);
|
|
4048
|
+
const [isSelecting, setIsSelecting] = useState11(false);
|
|
4049
|
+
const mouseDownTimeRef = useRef14(0);
|
|
4050
|
+
const scrollContainerRef = useRef14(null);
|
|
4051
|
+
const handleScrollContainerRef = useCallback16(
|
|
5822
4052
|
(element) => {
|
|
5823
4053
|
scrollContainerRef.current = element;
|
|
5824
4054
|
setScrollContainer(element);
|
|
@@ -5856,7 +4086,7 @@ var PlaylistVisualization = ({
|
|
|
5856
4086
|
);
|
|
5857
4087
|
}
|
|
5858
4088
|
});
|
|
5859
|
-
const selectTrack =
|
|
4089
|
+
const selectTrack = useCallback16(
|
|
5860
4090
|
(trackIndex) => {
|
|
5861
4091
|
if (trackIndex >= 0 && trackIndex < tracks.length) {
|
|
5862
4092
|
const track = tracks[trackIndex];
|
|
@@ -5926,7 +4156,7 @@ var PlaylistVisualization = ({
|
|
|
5926
4156
|
};
|
|
5927
4157
|
const hasClips = tracks.some((track) => track.clips.length > 0);
|
|
5928
4158
|
if (hasClips && peaksDataArray.length === 0) {
|
|
5929
|
-
return /* @__PURE__ */
|
|
4159
|
+
return /* @__PURE__ */ jsx9("div", { className, children: "Loading waveform..." });
|
|
5930
4160
|
}
|
|
5931
4161
|
const trackControlsSlots = controls.show ? peaksDataArray.map((trackClipPeaks, trackIndex) => {
|
|
5932
4162
|
var _a2, _b2, _c2;
|
|
@@ -5945,7 +4175,7 @@ var PlaylistVisualization = ({
|
|
|
5945
4175
|
const slotHeight = waveHeight * maxChannels + (showClipHeaders ? CLIP_HEADER_HEIGHT : 0);
|
|
5946
4176
|
const trackControlContent = renderTrackControls ? renderTrackControls(trackIndex) : /* @__PURE__ */ jsxs2(Controls, { onClick: () => selectTrack(trackIndex), children: [
|
|
5947
4177
|
/* @__PURE__ */ jsxs2(Header, { style: { justifyContent: "center", position: "relative" }, children: [
|
|
5948
|
-
onRemoveTrack && /* @__PURE__ */
|
|
4178
|
+
onRemoveTrack && /* @__PURE__ */ jsx9(
|
|
5949
4179
|
CloseButton,
|
|
5950
4180
|
{
|
|
5951
4181
|
onClick: (e) => {
|
|
@@ -5954,7 +4184,7 @@ var PlaylistVisualization = ({
|
|
|
5954
4184
|
}
|
|
5955
4185
|
}
|
|
5956
4186
|
),
|
|
5957
|
-
/* @__PURE__ */
|
|
4187
|
+
/* @__PURE__ */ jsx9(
|
|
5958
4188
|
"span",
|
|
5959
4189
|
{
|
|
5960
4190
|
style: {
|
|
@@ -5967,7 +4197,7 @@ var PlaylistVisualization = ({
|
|
|
5967
4197
|
children: trackState.name || `Track ${trackIndex + 1}`
|
|
5968
4198
|
}
|
|
5969
4199
|
),
|
|
5970
|
-
(spectrogram == null ? void 0 : spectrogram.renderMenuItems) && /* @__PURE__ */
|
|
4200
|
+
(spectrogram == null ? void 0 : spectrogram.renderMenuItems) && /* @__PURE__ */ jsx9("span", { style: { position: "absolute", right: 0, top: 0 }, children: /* @__PURE__ */ jsx9(
|
|
5971
4201
|
TrackMenu,
|
|
5972
4202
|
{
|
|
5973
4203
|
items: (onClose) => spectrogram.renderMenuItems({
|
|
@@ -5980,7 +4210,7 @@ var PlaylistVisualization = ({
|
|
|
5980
4210
|
) })
|
|
5981
4211
|
] }),
|
|
5982
4212
|
/* @__PURE__ */ jsxs2(ButtonGroup, { children: [
|
|
5983
|
-
/* @__PURE__ */
|
|
4213
|
+
/* @__PURE__ */ jsx9(
|
|
5984
4214
|
Button,
|
|
5985
4215
|
{
|
|
5986
4216
|
$variant: trackState.muted ? "danger" : "outline",
|
|
@@ -5988,7 +4218,7 @@ var PlaylistVisualization = ({
|
|
|
5988
4218
|
children: "Mute"
|
|
5989
4219
|
}
|
|
5990
4220
|
),
|
|
5991
|
-
/* @__PURE__ */
|
|
4221
|
+
/* @__PURE__ */ jsx9(
|
|
5992
4222
|
Button,
|
|
5993
4223
|
{
|
|
5994
4224
|
$variant: trackState.soloed ? "info" : "outline",
|
|
@@ -5998,8 +4228,8 @@ var PlaylistVisualization = ({
|
|
|
5998
4228
|
)
|
|
5999
4229
|
] }),
|
|
6000
4230
|
/* @__PURE__ */ jsxs2(SliderWrapper, { children: [
|
|
6001
|
-
/* @__PURE__ */
|
|
6002
|
-
/* @__PURE__ */
|
|
4231
|
+
/* @__PURE__ */ jsx9(VolumeDownIcon, {}),
|
|
4232
|
+
/* @__PURE__ */ jsx9(
|
|
6003
4233
|
Slider,
|
|
6004
4234
|
{
|
|
6005
4235
|
min: "0",
|
|
@@ -6009,11 +4239,11 @@ var PlaylistVisualization = ({
|
|
|
6009
4239
|
onChange: (e) => setTrackVolume(trackIndex, parseFloat(e.target.value))
|
|
6010
4240
|
}
|
|
6011
4241
|
),
|
|
6012
|
-
/* @__PURE__ */
|
|
4242
|
+
/* @__PURE__ */ jsx9(VolumeUpIcon, {})
|
|
6013
4243
|
] }),
|
|
6014
4244
|
/* @__PURE__ */ jsxs2(SliderWrapper, { children: [
|
|
6015
|
-
/* @__PURE__ */
|
|
6016
|
-
/* @__PURE__ */
|
|
4245
|
+
/* @__PURE__ */ jsx9("span", { children: "L" }),
|
|
4246
|
+
/* @__PURE__ */ jsx9(
|
|
6017
4247
|
Slider,
|
|
6018
4248
|
{
|
|
6019
4249
|
min: "-1",
|
|
@@ -6023,10 +4253,10 @@ var PlaylistVisualization = ({
|
|
|
6023
4253
|
onChange: (e) => setTrackPan(trackIndex, parseFloat(e.target.value))
|
|
6024
4254
|
}
|
|
6025
4255
|
),
|
|
6026
|
-
/* @__PURE__ */
|
|
4256
|
+
/* @__PURE__ */ jsx9("span", { children: "R" })
|
|
6027
4257
|
] })
|
|
6028
4258
|
] });
|
|
6029
|
-
return /* @__PURE__ */
|
|
4259
|
+
return /* @__PURE__ */ jsx9(
|
|
6030
4260
|
ControlSlot,
|
|
6031
4261
|
{
|
|
6032
4262
|
$height: slotHeight,
|
|
@@ -6037,7 +4267,7 @@ var PlaylistVisualization = ({
|
|
|
6037
4267
|
);
|
|
6038
4268
|
}) : void 0;
|
|
6039
4269
|
return /* @__PURE__ */ jsxs2(DevicePixelRatioProvider, { children: [
|
|
6040
|
-
/* @__PURE__ */
|
|
4270
|
+
/* @__PURE__ */ jsx9(
|
|
6041
4271
|
PlaylistInfoContext.Provider,
|
|
6042
4272
|
{
|
|
6043
4273
|
value: {
|
|
@@ -6051,7 +4281,7 @@ var PlaylistVisualization = ({
|
|
|
6051
4281
|
barWidth,
|
|
6052
4282
|
barGap
|
|
6053
4283
|
},
|
|
6054
|
-
children: /* @__PURE__ */
|
|
4284
|
+
children: /* @__PURE__ */ jsx9(
|
|
6055
4285
|
Playlist,
|
|
6056
4286
|
{
|
|
6057
4287
|
theme,
|
|
@@ -6069,8 +4299,8 @@ var PlaylistVisualization = ({
|
|
|
6069
4299
|
trackControlsSlots,
|
|
6070
4300
|
timescaleGapHeight: timeScaleHeight > 0 ? timeScaleHeight + 1 : 0,
|
|
6071
4301
|
timescale: timeScaleHeight > 0 ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
6072
|
-
/* @__PURE__ */
|
|
6073
|
-
isLoopEnabled && /* @__PURE__ */
|
|
4302
|
+
/* @__PURE__ */ jsx9(SmartScale, { renderTick }),
|
|
4303
|
+
isLoopEnabled && /* @__PURE__ */ jsx9(
|
|
6074
4304
|
TimescaleLoopRegion,
|
|
6075
4305
|
{
|
|
6076
4306
|
startPosition: Math.min(loopStart, loopEnd) * sampleRate / samplesPerPixel,
|
|
@@ -6116,7 +4346,7 @@ var PlaylistVisualization = ({
|
|
|
6116
4346
|
const helpers = perTrackSpectrogramHelpers.get(track.id);
|
|
6117
4347
|
const trackCfg = helpers == null ? void 0 : helpers.config;
|
|
6118
4348
|
if (!(trackCfg == null ? void 0 : trackCfg.labels) || !helpers) return null;
|
|
6119
|
-
return /* @__PURE__ */
|
|
4349
|
+
return /* @__PURE__ */ jsx9(
|
|
6120
4350
|
SpectrogramLabels,
|
|
6121
4351
|
{
|
|
6122
4352
|
waveHeight,
|
|
@@ -6134,7 +4364,7 @@ var PlaylistVisualization = ({
|
|
|
6134
4364
|
trackClipPeaks.map((clip, clipIndex) => {
|
|
6135
4365
|
const peaksData = clip.peaks;
|
|
6136
4366
|
const width = peaksData.length;
|
|
6137
|
-
return /* @__PURE__ */
|
|
4367
|
+
return /* @__PURE__ */ jsx9(
|
|
6138
4368
|
Clip,
|
|
6139
4369
|
{
|
|
6140
4370
|
clipId: clip.clipId,
|
|
@@ -6164,7 +4394,7 @@ var PlaylistVisualization = ({
|
|
|
6164
4394
|
selectTrack(trackIndex);
|
|
6165
4395
|
},
|
|
6166
4396
|
children: peaksData.data.map((channelPeaks, channelIndex) => {
|
|
6167
|
-
return /* @__PURE__ */
|
|
4397
|
+
return /* @__PURE__ */ jsx9(
|
|
6168
4398
|
ChannelWithProgress,
|
|
6169
4399
|
{
|
|
6170
4400
|
index: channelIndex,
|
|
@@ -6191,14 +4421,12 @@ var PlaylistVisualization = ({
|
|
|
6191
4421
|
);
|
|
6192
4422
|
}),
|
|
6193
4423
|
(recordingState == null ? void 0 : recordingState.isRecording) && recordingState.trackId === track.id && ((_d2 = recordingState.peaks[0]) == null ? void 0 : _d2.length) > 0 && (() => {
|
|
6194
|
-
const
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
outputLatency,
|
|
6199
|
-
lookAhead,
|
|
4424
|
+
const latencyOffsetSamples = resolveRecordingOffsetSamples({
|
|
4425
|
+
overrideSeconds: recordingState.latencyOffset,
|
|
4426
|
+
outputLatency: getOutputLatency(),
|
|
4427
|
+
lookAhead: getLookAhead(),
|
|
6200
4428
|
sampleRate
|
|
6201
|
-
);
|
|
4429
|
+
});
|
|
6202
4430
|
const latencyPixels = Math.floor(latencyOffsetSamples / samplesPerPixel);
|
|
6203
4431
|
const skipPeakElements = latencyPixels * 2;
|
|
6204
4432
|
const previewDuration = Math.max(
|
|
@@ -6208,7 +4436,7 @@ var PlaylistVisualization = ({
|
|
|
6208
4436
|
const previewChannels = (mono ? recordingState.peaks.slice(0, 1) : recordingState.peaks).map(
|
|
6209
4437
|
(channelPeaks) => skipPeakElements > 0 && skipPeakElements < channelPeaks.length ? channelPeaks.subarray(skipPeakElements) : channelPeaks
|
|
6210
4438
|
);
|
|
6211
|
-
return /* @__PURE__ */
|
|
4439
|
+
return /* @__PURE__ */ jsx9(
|
|
6212
4440
|
Clip,
|
|
6213
4441
|
{
|
|
6214
4442
|
clipId: "recording-preview",
|
|
@@ -6222,7 +4450,7 @@ var PlaylistVisualization = ({
|
|
|
6222
4450
|
disableHeaderDrag: true,
|
|
6223
4451
|
isSelected: track.id === selectedTrackId,
|
|
6224
4452
|
trackId: track.id,
|
|
6225
|
-
children: previewChannels.map((channelPeaks, chIdx) => /* @__PURE__ */
|
|
4453
|
+
children: previewChannels.map((channelPeaks, chIdx) => /* @__PURE__ */ jsx9(
|
|
6226
4454
|
ChannelWithProgress,
|
|
6227
4455
|
{
|
|
6228
4456
|
index: chIdx,
|
|
@@ -6244,11 +4472,11 @@ var PlaylistVisualization = ({
|
|
|
6244
4472
|
track.id
|
|
6245
4473
|
);
|
|
6246
4474
|
}),
|
|
6247
|
-
annotations.length > 0 && annotationIntegration && /* @__PURE__ */
|
|
4475
|
+
annotations.length > 0 && annotationIntegration && /* @__PURE__ */ jsx9(annotationIntegration.AnnotationBoxesWrapper, { height: 30, width: tracksFullWidth, children: annotations.map((annotation, index) => {
|
|
6248
4476
|
const startPosition = annotation.start * sampleRate / samplesPerPixel;
|
|
6249
4477
|
const endPosition = annotation.end * sampleRate / samplesPerPixel;
|
|
6250
4478
|
const label = getAnnotationBoxLabel ? getAnnotationBoxLabel(annotation, index) : annotation.id;
|
|
6251
|
-
return /* @__PURE__ */
|
|
4479
|
+
return /* @__PURE__ */ jsx9(
|
|
6252
4480
|
annotationIntegration.AnnotationBox,
|
|
6253
4481
|
{
|
|
6254
4482
|
annotationId: annotation.id,
|
|
@@ -6264,7 +4492,7 @@ var PlaylistVisualization = ({
|
|
|
6264
4492
|
annotation.id
|
|
6265
4493
|
);
|
|
6266
4494
|
}) }),
|
|
6267
|
-
selectionStart !== selectionEnd && /* @__PURE__ */
|
|
4495
|
+
selectionStart !== selectionEnd && /* @__PURE__ */ jsx9(
|
|
6268
4496
|
Selection,
|
|
6269
4497
|
{
|
|
6270
4498
|
startPosition: Math.min(selectionStart, selectionEnd) * sampleRate / samplesPerPixel,
|
|
@@ -6272,7 +4500,7 @@ var PlaylistVisualization = ({
|
|
|
6272
4500
|
color: theme.selectionColor
|
|
6273
4501
|
}
|
|
6274
4502
|
),
|
|
6275
|
-
(isPlaying || selectionStart === selectionEnd) && (renderPlayhead ? /* @__PURE__ */
|
|
4503
|
+
(isPlaying || selectionStart === selectionEnd) && (renderPlayhead ? /* @__PURE__ */ jsx9(
|
|
6276
4504
|
CustomPlayhead,
|
|
6277
4505
|
{
|
|
6278
4506
|
renderPlayhead,
|
|
@@ -6280,14 +4508,14 @@ var PlaylistVisualization = ({
|
|
|
6280
4508
|
samplesPerPixel,
|
|
6281
4509
|
sampleRate
|
|
6282
4510
|
}
|
|
6283
|
-
) : /* @__PURE__ */
|
|
4511
|
+
) : /* @__PURE__ */ jsx9(AnimatedPlayhead, { color: theme.playheadColor }))
|
|
6284
4512
|
] })
|
|
6285
4513
|
}
|
|
6286
4514
|
)
|
|
6287
4515
|
}
|
|
6288
4516
|
),
|
|
6289
4517
|
(spectrogram == null ? void 0 : spectrogram.SettingsModal) && typeof document !== "undefined" && createPortal(
|
|
6290
|
-
/* @__PURE__ */
|
|
4518
|
+
/* @__PURE__ */ jsx9(
|
|
6291
4519
|
spectrogram.SettingsModal,
|
|
6292
4520
|
{
|
|
6293
4521
|
open: settingsModalTrackId !== null,
|
|
@@ -6307,8 +4535,8 @@ var PlaylistVisualization = ({
|
|
|
6307
4535
|
};
|
|
6308
4536
|
|
|
6309
4537
|
// src/components/PlaylistAnnotationList.tsx
|
|
6310
|
-
import { useCallback as
|
|
6311
|
-
import { jsx as
|
|
4538
|
+
import { useCallback as useCallback17 } from "react";
|
|
4539
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
6312
4540
|
var PlaylistAnnotationList = ({
|
|
6313
4541
|
height,
|
|
6314
4542
|
renderAnnotationItem,
|
|
@@ -6322,7 +4550,7 @@ var PlaylistAnnotationList = ({
|
|
|
6322
4550
|
const integration = useAnnotationIntegration();
|
|
6323
4551
|
const { setAnnotations } = usePlaylistControls();
|
|
6324
4552
|
const resolvedConfig = annotationListConfig != null ? annotationListConfig : { linkEndpoints, continuousPlay };
|
|
6325
|
-
const handleAnnotationUpdate =
|
|
4553
|
+
const handleAnnotationUpdate = useCallback17(
|
|
6326
4554
|
(updatedAnnotations) => {
|
|
6327
4555
|
setAnnotations(updatedAnnotations);
|
|
6328
4556
|
onAnnotationUpdate == null ? void 0 : onAnnotationUpdate(updatedAnnotations);
|
|
@@ -6330,7 +4558,7 @@ var PlaylistAnnotationList = ({
|
|
|
6330
4558
|
[setAnnotations, onAnnotationUpdate]
|
|
6331
4559
|
);
|
|
6332
4560
|
const { AnnotationText } = integration;
|
|
6333
|
-
return /* @__PURE__ */
|
|
4561
|
+
return /* @__PURE__ */ jsx10(
|
|
6334
4562
|
AnnotationText,
|
|
6335
4563
|
{
|
|
6336
4564
|
annotations,
|
|
@@ -6349,7 +4577,7 @@ var PlaylistAnnotationList = ({
|
|
|
6349
4577
|
};
|
|
6350
4578
|
|
|
6351
4579
|
// src/components/Waveform.tsx
|
|
6352
|
-
import { Fragment as Fragment3, jsx as
|
|
4580
|
+
import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
6353
4581
|
var Waveform = ({
|
|
6354
4582
|
renderTrackControls,
|
|
6355
4583
|
renderTick,
|
|
@@ -6374,7 +4602,7 @@ var Waveform = ({
|
|
|
6374
4602
|
const clipInteractionEnabled = useClipInteractionEnabled();
|
|
6375
4603
|
const effectiveInteractiveClips = interactiveClips || clipInteractionEnabled;
|
|
6376
4604
|
return /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
6377
|
-
/* @__PURE__ */
|
|
4605
|
+
/* @__PURE__ */ jsx11(
|
|
6378
4606
|
PlaylistVisualization,
|
|
6379
4607
|
{
|
|
6380
4608
|
renderTrackControls,
|
|
@@ -6391,7 +4619,7 @@ var Waveform = ({
|
|
|
6391
4619
|
recordingState
|
|
6392
4620
|
}
|
|
6393
4621
|
),
|
|
6394
|
-
annotations.length > 0 && /* @__PURE__ */
|
|
4622
|
+
annotations.length > 0 && /* @__PURE__ */ jsx11(
|
|
6395
4623
|
PlaylistAnnotationList,
|
|
6396
4624
|
{
|
|
6397
4625
|
height: annotationTextHeight,
|
|
@@ -6406,7 +4634,7 @@ var Waveform = ({
|
|
|
6406
4634
|
};
|
|
6407
4635
|
|
|
6408
4636
|
// src/components/MediaElementPlaylist.tsx
|
|
6409
|
-
import { useContext as useContext7, useRef as
|
|
4637
|
+
import { useContext as useContext7, useRef as useRef17, useState as useState12, useCallback as useCallback18 } from "react";
|
|
6410
4638
|
import { DragDropProvider } from "@dnd-kit/react";
|
|
6411
4639
|
import { RestrictToHorizontalAxis } from "@dnd-kit/abstract/modifiers";
|
|
6412
4640
|
import {
|
|
@@ -6442,9 +4670,9 @@ var noDropAnimationPlugins = (defaults) => {
|
|
|
6442
4670
|
};
|
|
6443
4671
|
|
|
6444
4672
|
// src/components/AnimatedMediaElementPlayhead.tsx
|
|
6445
|
-
import { useRef as
|
|
4673
|
+
import { useRef as useRef15, useEffect as useEffect10 } from "react";
|
|
6446
4674
|
import styled5 from "styled-components";
|
|
6447
|
-
import { jsx as
|
|
4675
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
6448
4676
|
var PlayheadLine2 = styled5.div`
|
|
6449
4677
|
position: absolute;
|
|
6450
4678
|
top: 0;
|
|
@@ -6459,11 +4687,11 @@ var PlayheadLine2 = styled5.div`
|
|
|
6459
4687
|
var AnimatedMediaElementPlayhead = ({
|
|
6460
4688
|
color = "#ff0000"
|
|
6461
4689
|
}) => {
|
|
6462
|
-
const playheadRef =
|
|
6463
|
-
const animationFrameRef =
|
|
4690
|
+
const playheadRef = useRef15(null);
|
|
4691
|
+
const animationFrameRef = useRef15(null);
|
|
6464
4692
|
const { isPlaying, currentTimeRef } = useMediaElementAnimation();
|
|
6465
4693
|
const { samplesPerPixel, sampleRate, progressBarWidth } = useMediaElementData();
|
|
6466
|
-
|
|
4694
|
+
useEffect10(() => {
|
|
6467
4695
|
const updatePosition = () => {
|
|
6468
4696
|
var _a;
|
|
6469
4697
|
if (playheadRef.current) {
|
|
@@ -6487,7 +4715,7 @@ var AnimatedMediaElementPlayhead = ({
|
|
|
6487
4715
|
}
|
|
6488
4716
|
};
|
|
6489
4717
|
}, [isPlaying, sampleRate, samplesPerPixel, currentTimeRef]);
|
|
6490
|
-
|
|
4718
|
+
useEffect10(() => {
|
|
6491
4719
|
var _a;
|
|
6492
4720
|
if (!isPlaying && playheadRef.current) {
|
|
6493
4721
|
const time = (_a = currentTimeRef.current) != null ? _a : 0;
|
|
@@ -6495,11 +4723,11 @@ var AnimatedMediaElementPlayhead = ({
|
|
|
6495
4723
|
playheadRef.current.style.transform = `translate3d(${position}px, 0, 0)`;
|
|
6496
4724
|
}
|
|
6497
4725
|
});
|
|
6498
|
-
return /* @__PURE__ */
|
|
4726
|
+
return /* @__PURE__ */ jsx12(PlayheadLine2, { ref: playheadRef, $color: color, $width: progressBarWidth, "data-playhead": true });
|
|
6499
4727
|
};
|
|
6500
4728
|
|
|
6501
4729
|
// src/components/ChannelWithMediaElementProgress.tsx
|
|
6502
|
-
import { useRef as
|
|
4730
|
+
import { useRef as useRef16, useEffect as useEffect11 } from "react";
|
|
6503
4731
|
import styled6 from "styled-components";
|
|
6504
4732
|
import {
|
|
6505
4733
|
SmartChannel as SmartChannel2,
|
|
@@ -6507,7 +4735,7 @@ import {
|
|
|
6507
4735
|
usePlaylistInfo as usePlaylistInfo2,
|
|
6508
4736
|
waveformColorToCss as waveformColorToCss3
|
|
6509
4737
|
} from "@waveform-playlist/ui-components";
|
|
6510
|
-
import { jsx as
|
|
4738
|
+
import { jsx as jsx13, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
6511
4739
|
var ChannelWrapper2 = styled6.div`
|
|
6512
4740
|
position: relative;
|
|
6513
4741
|
`;
|
|
@@ -6544,14 +4772,14 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6544
4772
|
"clipStartSample",
|
|
6545
4773
|
"clipDurationSamples"
|
|
6546
4774
|
]);
|
|
6547
|
-
const progressRef =
|
|
6548
|
-
const animationFrameRef =
|
|
4775
|
+
const progressRef = useRef16(null);
|
|
4776
|
+
const animationFrameRef = useRef16(null);
|
|
6549
4777
|
const theme = useTheme3();
|
|
6550
4778
|
const { waveHeight } = usePlaylistInfo2();
|
|
6551
4779
|
const { isPlaying, currentTimeRef } = useMediaElementAnimation();
|
|
6552
4780
|
const { samplesPerPixel, sampleRate } = useMediaElementData();
|
|
6553
4781
|
const progressColor = (theme == null ? void 0 : theme.waveProgressColor) || "rgba(0, 0, 0, 0.1)";
|
|
6554
|
-
|
|
4782
|
+
useEffect11(() => {
|
|
6555
4783
|
const updateProgress = () => {
|
|
6556
4784
|
var _a2;
|
|
6557
4785
|
if (progressRef.current) {
|
|
@@ -6593,7 +4821,7 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6593
4821
|
smartChannelProps.length,
|
|
6594
4822
|
currentTimeRef
|
|
6595
4823
|
]);
|
|
6596
|
-
|
|
4824
|
+
useEffect11(() => {
|
|
6597
4825
|
var _a2;
|
|
6598
4826
|
if (!isPlaying && progressRef.current) {
|
|
6599
4827
|
const currentTime = (_a2 = currentTimeRef.current) != null ? _a2 : 0;
|
|
@@ -6620,7 +4848,7 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6620
4848
|
}
|
|
6621
4849
|
const backgroundCss = waveformColorToCss3(backgroundColor);
|
|
6622
4850
|
return /* @__PURE__ */ jsxs4(ChannelWrapper2, { children: [
|
|
6623
|
-
/* @__PURE__ */
|
|
4851
|
+
/* @__PURE__ */ jsx13(
|
|
6624
4852
|
Background2,
|
|
6625
4853
|
{
|
|
6626
4854
|
$color: backgroundCss,
|
|
@@ -6629,7 +4857,7 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6629
4857
|
$width: smartChannelProps.length
|
|
6630
4858
|
}
|
|
6631
4859
|
),
|
|
6632
|
-
/* @__PURE__ */
|
|
4860
|
+
/* @__PURE__ */ jsx13(
|
|
6633
4861
|
ProgressOverlay2,
|
|
6634
4862
|
{
|
|
6635
4863
|
ref: progressRef,
|
|
@@ -6638,12 +4866,12 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6638
4866
|
$top: smartChannelProps.index * waveHeight
|
|
6639
4867
|
}
|
|
6640
4868
|
),
|
|
6641
|
-
/* @__PURE__ */
|
|
4869
|
+
/* @__PURE__ */ jsx13(ChannelContainer2, { children: /* @__PURE__ */ jsx13(SmartChannel2, __spreadProps(__spreadValues({}, smartChannelProps), { isSelected: true, transparentBackground: true })) })
|
|
6642
4870
|
] });
|
|
6643
4871
|
};
|
|
6644
4872
|
|
|
6645
4873
|
// src/components/MediaElementPlaylist.tsx
|
|
6646
|
-
import { Fragment as Fragment4, jsx as
|
|
4874
|
+
import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
6647
4875
|
var ZERO_REF = { current: 0 };
|
|
6648
4876
|
var CustomMediaElementPlayhead = ({ renderPlayhead, color, samplesPerPixel, sampleRate }) => {
|
|
6649
4877
|
var _a;
|
|
@@ -6688,11 +4916,11 @@ var MediaElementPlaylist = ({
|
|
|
6688
4916
|
fadeIn,
|
|
6689
4917
|
fadeOut
|
|
6690
4918
|
} = useMediaElementData();
|
|
6691
|
-
const [selectionStart, setSelectionStart] =
|
|
6692
|
-
const [selectionEnd, setSelectionEnd] =
|
|
6693
|
-
const [isSelecting, setIsSelecting] =
|
|
6694
|
-
const scrollContainerRef =
|
|
6695
|
-
const handleScrollContainerRef =
|
|
4919
|
+
const [selectionStart, setSelectionStart] = useState12(0);
|
|
4920
|
+
const [selectionEnd, setSelectionEnd] = useState12(0);
|
|
4921
|
+
const [isSelecting, setIsSelecting] = useState12(false);
|
|
4922
|
+
const scrollContainerRef = useRef17(null);
|
|
4923
|
+
const handleScrollContainerRef = useCallback18(
|
|
6696
4924
|
(el) => {
|
|
6697
4925
|
scrollContainerRef.current = el;
|
|
6698
4926
|
setScrollContainer(el);
|
|
@@ -6700,7 +4928,7 @@ var MediaElementPlaylist = ({
|
|
|
6700
4928
|
[setScrollContainer]
|
|
6701
4929
|
);
|
|
6702
4930
|
const tracksFullWidth = Math.floor(duration * sampleRate / samplesPerPixel);
|
|
6703
|
-
const handleAnnotationClick =
|
|
4931
|
+
const handleAnnotationClick = useCallback18(
|
|
6704
4932
|
(annotation) => __async(null, null, function* () {
|
|
6705
4933
|
setActiveAnnotationId(annotation.id);
|
|
6706
4934
|
try {
|
|
@@ -6715,7 +4943,7 @@ var MediaElementPlaylist = ({
|
|
|
6715
4943
|
}),
|
|
6716
4944
|
[setActiveAnnotationId, play]
|
|
6717
4945
|
);
|
|
6718
|
-
const handleAnnotationUpdate =
|
|
4946
|
+
const handleAnnotationUpdate = useCallback18(
|
|
6719
4947
|
(updatedAnnotations) => {
|
|
6720
4948
|
setAnnotations(updatedAnnotations);
|
|
6721
4949
|
onAnnotationUpdate == null ? void 0 : onAnnotationUpdate(updatedAnnotations);
|
|
@@ -6729,8 +4957,8 @@ var MediaElementPlaylist = ({
|
|
|
6729
4957
|
duration,
|
|
6730
4958
|
linkEndpoints: linkEndpointsProp
|
|
6731
4959
|
});
|
|
6732
|
-
const mouseDownTimeRef =
|
|
6733
|
-
const handleMouseDown =
|
|
4960
|
+
const mouseDownTimeRef = useRef17(0);
|
|
4961
|
+
const handleMouseDown = useCallback18(
|
|
6734
4962
|
(e) => {
|
|
6735
4963
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
6736
4964
|
const x = e.clientX - rect.left;
|
|
@@ -6742,7 +4970,7 @@ var MediaElementPlaylist = ({
|
|
|
6742
4970
|
},
|
|
6743
4971
|
[samplesPerPixel, sampleRate]
|
|
6744
4972
|
);
|
|
6745
|
-
const handleMouseMove =
|
|
4973
|
+
const handleMouseMove = useCallback18(
|
|
6746
4974
|
(e) => {
|
|
6747
4975
|
if (!isSelecting) return;
|
|
6748
4976
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
@@ -6752,7 +4980,7 @@ var MediaElementPlaylist = ({
|
|
|
6752
4980
|
},
|
|
6753
4981
|
[isSelecting, samplesPerPixel, sampleRate]
|
|
6754
4982
|
);
|
|
6755
|
-
const handleMouseUp =
|
|
4983
|
+
const handleMouseUp = useCallback18(
|
|
6756
4984
|
(e) => {
|
|
6757
4985
|
if (!isSelecting) return;
|
|
6758
4986
|
setIsSelecting(false);
|
|
@@ -6782,9 +5010,9 @@ var MediaElementPlaylist = ({
|
|
|
6782
5010
|
[isSelecting, selectionStart, samplesPerPixel, sampleRate, seekTo, isPlaying, playoutRef, play]
|
|
6783
5011
|
);
|
|
6784
5012
|
if (peaksDataArray.length === 0) {
|
|
6785
|
-
return /* @__PURE__ */
|
|
5013
|
+
return /* @__PURE__ */ jsx14("div", { className, children: "Loading waveform..." });
|
|
6786
5014
|
}
|
|
6787
|
-
return /* @__PURE__ */
|
|
5015
|
+
return /* @__PURE__ */ jsx14(DevicePixelRatioProvider2, { children: /* @__PURE__ */ jsx14(
|
|
6788
5016
|
PlaylistInfoContext2.Provider,
|
|
6789
5017
|
{
|
|
6790
5018
|
value: {
|
|
@@ -6798,7 +5026,7 @@ var MediaElementPlaylist = ({
|
|
|
6798
5026
|
barWidth,
|
|
6799
5027
|
barGap
|
|
6800
5028
|
},
|
|
6801
|
-
children: /* @__PURE__ */
|
|
5029
|
+
children: /* @__PURE__ */ jsx14(
|
|
6802
5030
|
Playlist2,
|
|
6803
5031
|
{
|
|
6804
5032
|
theme,
|
|
@@ -6812,11 +5040,11 @@ var MediaElementPlaylist = ({
|
|
|
6812
5040
|
onTracksMouseUp: handleMouseUp,
|
|
6813
5041
|
scrollContainerRef: handleScrollContainerRef,
|
|
6814
5042
|
isSelecting,
|
|
6815
|
-
timescale: timeScaleHeight > 0 ? /* @__PURE__ */
|
|
5043
|
+
timescale: timeScaleHeight > 0 ? /* @__PURE__ */ jsx14(SmartScale2, {}) : void 0,
|
|
6816
5044
|
children: /* @__PURE__ */ jsxs5(Fragment4, { children: [
|
|
6817
5045
|
peaksDataArray.map((trackClipPeaks, trackIndex) => {
|
|
6818
5046
|
const maxChannels = trackClipPeaks.length > 0 ? Math.max(...trackClipPeaks.map((clip) => clip.peaks.data.length)) : 1;
|
|
6819
|
-
return /* @__PURE__ */
|
|
5047
|
+
return /* @__PURE__ */ jsx14(
|
|
6820
5048
|
TrackComponent2,
|
|
6821
5049
|
{
|
|
6822
5050
|
numChannels: maxChannels,
|
|
@@ -6844,7 +5072,7 @@ var MediaElementPlaylist = ({
|
|
|
6844
5072
|
isSelected: true,
|
|
6845
5073
|
trackId: `media-element-track-${trackIndex}`,
|
|
6846
5074
|
children: [
|
|
6847
|
-
peaksData.data.map((channelPeaks, channelIndex) => /* @__PURE__ */
|
|
5075
|
+
peaksData.data.map((channelPeaks, channelIndex) => /* @__PURE__ */ jsx14(
|
|
6848
5076
|
ChannelWithMediaElementProgress,
|
|
6849
5077
|
{
|
|
6850
5078
|
index: channelIndex,
|
|
@@ -6856,7 +5084,7 @@ var MediaElementPlaylist = ({
|
|
|
6856
5084
|
},
|
|
6857
5085
|
`${trackIndex}-${clipIndex}-${channelIndex}`
|
|
6858
5086
|
)),
|
|
6859
|
-
showFades && fadeIn && fadeIn.duration > 0 && /* @__PURE__ */
|
|
5087
|
+
showFades && fadeIn && fadeIn.duration > 0 && /* @__PURE__ */ jsx14(
|
|
6860
5088
|
FadeOverlay,
|
|
6861
5089
|
{
|
|
6862
5090
|
left: 0,
|
|
@@ -6865,7 +5093,7 @@ var MediaElementPlaylist = ({
|
|
|
6865
5093
|
curveType: fadeIn.type
|
|
6866
5094
|
}
|
|
6867
5095
|
),
|
|
6868
|
-
showFades && fadeOut && fadeOut.duration > 0 && /* @__PURE__ */
|
|
5096
|
+
showFades && fadeOut && fadeOut.duration > 0 && /* @__PURE__ */ jsx14(
|
|
6869
5097
|
FadeOverlay,
|
|
6870
5098
|
{
|
|
6871
5099
|
left: width - Math.floor(fadeOut.duration * sampleRate / samplesPerPixel),
|
|
@@ -6883,7 +5111,7 @@ var MediaElementPlaylist = ({
|
|
|
6883
5111
|
trackIndex
|
|
6884
5112
|
);
|
|
6885
5113
|
}),
|
|
6886
|
-
annotations.length > 0 && annotationIntegration && /* @__PURE__ */
|
|
5114
|
+
annotations.length > 0 && annotationIntegration && /* @__PURE__ */ jsx14(
|
|
6887
5115
|
DragDropProvider,
|
|
6888
5116
|
{
|
|
6889
5117
|
onDragStart,
|
|
@@ -6891,11 +5119,11 @@ var MediaElementPlaylist = ({
|
|
|
6891
5119
|
onDragEnd,
|
|
6892
5120
|
modifiers: editable ? [RestrictToHorizontalAxis] : [],
|
|
6893
5121
|
plugins: noDropAnimationPlugins,
|
|
6894
|
-
children: /* @__PURE__ */
|
|
5122
|
+
children: /* @__PURE__ */ jsx14(annotationIntegration.AnnotationBoxesWrapper, { height: 30, width: tracksFullWidth, children: annotations.map((annotation, index) => {
|
|
6895
5123
|
const startPosition = annotation.start * sampleRate / samplesPerPixel;
|
|
6896
5124
|
const endPosition = annotation.end * sampleRate / samplesPerPixel;
|
|
6897
5125
|
const label = getAnnotationBoxLabel ? getAnnotationBoxLabel(annotation, index) : annotation.id;
|
|
6898
|
-
return /* @__PURE__ */
|
|
5126
|
+
return /* @__PURE__ */ jsx14(
|
|
6899
5127
|
annotationIntegration.AnnotationBox,
|
|
6900
5128
|
{
|
|
6901
5129
|
annotationId: annotation.id,
|
|
@@ -6913,7 +5141,7 @@ var MediaElementPlaylist = ({
|
|
|
6913
5141
|
}) })
|
|
6914
5142
|
}
|
|
6915
5143
|
),
|
|
6916
|
-
selectionStart !== selectionEnd && /* @__PURE__ */
|
|
5144
|
+
selectionStart !== selectionEnd && /* @__PURE__ */ jsx14(
|
|
6917
5145
|
Selection2,
|
|
6918
5146
|
{
|
|
6919
5147
|
startPosition: Math.min(selectionStart, selectionEnd) * sampleRate / samplesPerPixel,
|
|
@@ -6921,7 +5149,7 @@ var MediaElementPlaylist = ({
|
|
|
6921
5149
|
color: theme.selectionColor
|
|
6922
5150
|
}
|
|
6923
5151
|
),
|
|
6924
|
-
renderPlayhead ? /* @__PURE__ */
|
|
5152
|
+
renderPlayhead ? /* @__PURE__ */ jsx14(
|
|
6925
5153
|
CustomMediaElementPlayhead,
|
|
6926
5154
|
{
|
|
6927
5155
|
renderPlayhead,
|
|
@@ -6929,7 +5157,7 @@ var MediaElementPlaylist = ({
|
|
|
6929
5157
|
samplesPerPixel,
|
|
6930
5158
|
sampleRate
|
|
6931
5159
|
}
|
|
6932
|
-
) : /* @__PURE__ */
|
|
5160
|
+
) : /* @__PURE__ */ jsx14(AnimatedMediaElementPlayhead, { color: theme.playheadColor })
|
|
6933
5161
|
] })
|
|
6934
5162
|
}
|
|
6935
5163
|
)
|
|
@@ -6938,8 +5166,8 @@ var MediaElementPlaylist = ({
|
|
|
6938
5166
|
};
|
|
6939
5167
|
|
|
6940
5168
|
// src/components/MediaElementAnnotationList.tsx
|
|
6941
|
-
import { useCallback as
|
|
6942
|
-
import { jsx as
|
|
5169
|
+
import { useCallback as useCallback19 } from "react";
|
|
5170
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
6943
5171
|
var MediaElementAnnotationList = ({
|
|
6944
5172
|
height,
|
|
6945
5173
|
renderAnnotationItem,
|
|
@@ -6954,7 +5182,7 @@ var MediaElementAnnotationList = ({
|
|
|
6954
5182
|
const integration = useAnnotationIntegration();
|
|
6955
5183
|
const { setAnnotations } = useMediaElementControls();
|
|
6956
5184
|
const resolvedConfig = annotationListConfig != null ? annotationListConfig : { linkEndpoints: false, continuousPlay };
|
|
6957
|
-
const handleAnnotationUpdate =
|
|
5185
|
+
const handleAnnotationUpdate = useCallback19(
|
|
6958
5186
|
(updatedAnnotations) => {
|
|
6959
5187
|
setAnnotations(updatedAnnotations);
|
|
6960
5188
|
onAnnotationUpdate == null ? void 0 : onAnnotationUpdate(updatedAnnotations);
|
|
@@ -6962,7 +5190,7 @@ var MediaElementAnnotationList = ({
|
|
|
6962
5190
|
[setAnnotations, onAnnotationUpdate]
|
|
6963
5191
|
);
|
|
6964
5192
|
const { AnnotationText } = integration;
|
|
6965
|
-
return /* @__PURE__ */
|
|
5193
|
+
return /* @__PURE__ */ jsx15(
|
|
6966
5194
|
AnnotationText,
|
|
6967
5195
|
{
|
|
6968
5196
|
annotations,
|
|
@@ -6981,7 +5209,7 @@ var MediaElementAnnotationList = ({
|
|
|
6981
5209
|
};
|
|
6982
5210
|
|
|
6983
5211
|
// src/components/MediaElementWaveform.tsx
|
|
6984
|
-
import { Fragment as Fragment5, jsx as
|
|
5212
|
+
import { Fragment as Fragment5, jsx as jsx16, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
6985
5213
|
var MediaElementWaveform = ({
|
|
6986
5214
|
annotationTextHeight,
|
|
6987
5215
|
getAnnotationBoxLabel,
|
|
@@ -6997,7 +5225,7 @@ var MediaElementWaveform = ({
|
|
|
6997
5225
|
}) => {
|
|
6998
5226
|
const { annotations } = useMediaElementState();
|
|
6999
5227
|
return /* @__PURE__ */ jsxs6(Fragment5, { children: [
|
|
7000
|
-
/* @__PURE__ */
|
|
5228
|
+
/* @__PURE__ */ jsx16(
|
|
7001
5229
|
MediaElementPlaylist,
|
|
7002
5230
|
{
|
|
7003
5231
|
getAnnotationBoxLabel,
|
|
@@ -7009,7 +5237,7 @@ var MediaElementWaveform = ({
|
|
|
7009
5237
|
className
|
|
7010
5238
|
}
|
|
7011
5239
|
),
|
|
7012
|
-
annotations.length > 0 && /* @__PURE__ */
|
|
5240
|
+
annotations.length > 0 && /* @__PURE__ */ jsx16(
|
|
7013
5241
|
MediaElementAnnotationList,
|
|
7014
5242
|
{
|
|
7015
5243
|
height: annotationTextHeight,
|
|
@@ -7084,7 +5312,7 @@ var KeyboardShortcuts = ({
|
|
|
7084
5312
|
};
|
|
7085
5313
|
|
|
7086
5314
|
// src/components/ClipInteractionProvider.tsx
|
|
7087
|
-
import React16, { useEffect as
|
|
5315
|
+
import React16, { useEffect as useEffect12, useMemo as useMemo6 } from "react";
|
|
7088
5316
|
import { DragDropProvider as DragDropProvider2 } from "@dnd-kit/react";
|
|
7089
5317
|
import { RestrictToHorizontalAxis as RestrictToHorizontalAxis2 } from "@dnd-kit/abstract/modifiers";
|
|
7090
5318
|
import {
|
|
@@ -7174,7 +5402,7 @@ _SnapToGridModifier.configure = configurator2(_SnapToGridModifier);
|
|
|
7174
5402
|
var SnapToGridModifier = _SnapToGridModifier;
|
|
7175
5403
|
|
|
7176
5404
|
// src/components/ClipInteractionProvider.tsx
|
|
7177
|
-
import { jsx as
|
|
5405
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
7178
5406
|
var NOOP_TRACKS_CHANGE = () => {
|
|
7179
5407
|
};
|
|
7180
5408
|
var ClipInteractionProvider = ({
|
|
@@ -7187,14 +5415,14 @@ var ClipInteractionProvider = ({
|
|
|
7187
5415
|
const beatsAndBars = useBeatsAndBars();
|
|
7188
5416
|
const useBeatsSnap = snap && beatsAndBars != null && beatsAndBars.scaleMode === "beats" && beatsAndBars.snapTo !== "off";
|
|
7189
5417
|
const useTimescaleSnap = snap && !useBeatsSnap;
|
|
7190
|
-
|
|
5418
|
+
useEffect12(() => {
|
|
7191
5419
|
if (onTracksChange == null) {
|
|
7192
5420
|
console.warn(
|
|
7193
5421
|
"[waveform-playlist] ClipInteractionProvider: onTracksChange is not set on WaveformPlaylistProvider. Drag and trim edits will not be persisted."
|
|
7194
5422
|
);
|
|
7195
5423
|
}
|
|
7196
5424
|
}, [onTracksChange]);
|
|
7197
|
-
const snapSamplePosition =
|
|
5425
|
+
const snapSamplePosition = useMemo6(() => {
|
|
7198
5426
|
if (useBeatsSnap && beatsAndBars) {
|
|
7199
5427
|
const { bpm, timeSignature, snapTo } = beatsAndBars;
|
|
7200
5428
|
const gridTicks = snapTo === "bar" ? ticksPerBar2(timeSignature) : ticksPerBeat2(timeSignature);
|
|
@@ -7234,7 +5462,7 @@ var ClipInteractionProvider = ({
|
|
|
7234
5462
|
},
|
|
7235
5463
|
[handleDragStart, tracks, setSelectedTrackId]
|
|
7236
5464
|
);
|
|
7237
|
-
const modifiers =
|
|
5465
|
+
const modifiers = useMemo6(() => {
|
|
7238
5466
|
const mods = [RestrictToHorizontalAxis2];
|
|
7239
5467
|
if (useBeatsSnap && beatsAndBars) {
|
|
7240
5468
|
mods.push(
|
|
@@ -7259,7 +5487,7 @@ var ClipInteractionProvider = ({
|
|
|
7259
5487
|
mods.push(ClipCollisionModifier.configure({ tracks, samplesPerPixel }));
|
|
7260
5488
|
return mods;
|
|
7261
5489
|
}, [useBeatsSnap, useTimescaleSnap, beatsAndBars, tracks, samplesPerPixel, sampleRate]);
|
|
7262
|
-
return /* @__PURE__ */
|
|
5490
|
+
return /* @__PURE__ */ jsx17(ClipInteractionContextProvider, { value: true, children: /* @__PURE__ */ jsx17(
|
|
7263
5491
|
DragDropProvider2,
|
|
7264
5492
|
{
|
|
7265
5493
|
sensors,
|
|
@@ -7282,7 +5510,6 @@ export {
|
|
|
7282
5510
|
ContinuousPlayCheckbox,
|
|
7283
5511
|
DownloadAnnotationsButton,
|
|
7284
5512
|
EditableCheckbox,
|
|
7285
|
-
ExportWavButton,
|
|
7286
5513
|
FastForwardButton,
|
|
7287
5514
|
KeyboardShortcuts,
|
|
7288
5515
|
LinkEndpointsCheckbox,
|
|
@@ -7305,17 +5532,10 @@ export {
|
|
|
7305
5532
|
SpectrogramIntegrationProvider,
|
|
7306
5533
|
StopButton,
|
|
7307
5534
|
TimeFormatSelect,
|
|
7308
|
-
Tone2 as Tone,
|
|
7309
5535
|
Waveform,
|
|
7310
5536
|
WaveformPlaylistProvider,
|
|
7311
5537
|
ZoomInButton,
|
|
7312
5538
|
ZoomOutButton,
|
|
7313
|
-
createEffectChain,
|
|
7314
|
-
createEffectInstance,
|
|
7315
|
-
effectCategories,
|
|
7316
|
-
effectDefinitions,
|
|
7317
|
-
getEffectDefinition,
|
|
7318
|
-
getEffectsByCategory,
|
|
7319
5539
|
getShortcutLabel,
|
|
7320
5540
|
getWaveformDataMetadata,
|
|
7321
5541
|
loadPeaksFromWaveformData,
|
|
@@ -7324,22 +5544,16 @@ export {
|
|
|
7324
5544
|
useAnnotationDragHandlers,
|
|
7325
5545
|
useAnnotationIntegration,
|
|
7326
5546
|
useAnnotationKeyboardControls,
|
|
7327
|
-
useAudioTracks,
|
|
7328
5547
|
useClipDragHandlers,
|
|
7329
5548
|
useClipInteractionEnabled,
|
|
7330
5549
|
useClipSplitting,
|
|
7331
5550
|
useDragSensors,
|
|
7332
|
-
useDynamicEffects,
|
|
7333
|
-
useDynamicTracks,
|
|
7334
|
-
useExportWav,
|
|
7335
5551
|
useKeyboardShortcuts,
|
|
7336
|
-
useMasterAnalyser,
|
|
7337
5552
|
useMasterVolume,
|
|
7338
5553
|
useMediaElementAnimation,
|
|
7339
5554
|
useMediaElementControls,
|
|
7340
5555
|
useMediaElementData,
|
|
7341
5556
|
useMediaElementState,
|
|
7342
|
-
useOutputMeter,
|
|
7343
5557
|
usePlaybackAnimation,
|
|
7344
5558
|
usePlaybackShortcuts,
|
|
7345
5559
|
usePlaylistControls,
|
|
@@ -7348,7 +5562,6 @@ export {
|
|
|
7348
5562
|
usePlaylistState,
|
|
7349
5563
|
useSpectrogramIntegration,
|
|
7350
5564
|
useTimeFormat,
|
|
7351
|
-
useTrackDynamicEffects,
|
|
7352
5565
|
useZoomControls,
|
|
7353
5566
|
waveformDataToPeaks
|
|
7354
5567
|
};
|