@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.js
CHANGED
|
@@ -88,7 +88,6 @@ __export(index_exports, {
|
|
|
88
88
|
ContinuousPlayCheckbox: () => ContinuousPlayCheckbox,
|
|
89
89
|
DownloadAnnotationsButton: () => DownloadAnnotationsButton,
|
|
90
90
|
EditableCheckbox: () => EditableCheckbox,
|
|
91
|
-
ExportWavButton: () => ExportWavButton,
|
|
92
91
|
FastForwardButton: () => FastForwardButton,
|
|
93
92
|
KeyboardShortcuts: () => KeyboardShortcuts,
|
|
94
93
|
LinkEndpointsCheckbox: () => LinkEndpointsCheckbox,
|
|
@@ -111,18 +110,11 @@ __export(index_exports, {
|
|
|
111
110
|
SpectrogramIntegrationProvider: () => SpectrogramIntegrationProvider,
|
|
112
111
|
StopButton: () => StopButton,
|
|
113
112
|
TimeFormatSelect: () => TimeFormatSelect,
|
|
114
|
-
Tone: () => Tone2,
|
|
115
113
|
Waveform: () => Waveform,
|
|
116
114
|
WaveformPlaylistProvider: () => WaveformPlaylistProvider,
|
|
117
115
|
ZoomInButton: () => ZoomInButton,
|
|
118
116
|
ZoomOutButton: () => ZoomOutButton,
|
|
119
|
-
|
|
120
|
-
createEffectInstance: () => createEffectInstance,
|
|
121
|
-
effectCategories: () => effectCategories,
|
|
122
|
-
effectDefinitions: () => effectDefinitions,
|
|
123
|
-
getEffectDefinition: () => getEffectDefinition,
|
|
124
|
-
getEffectsByCategory: () => getEffectsByCategory,
|
|
125
|
-
getShortcutLabel: () => import_core3.getShortcutLabel,
|
|
117
|
+
getShortcutLabel: () => import_core2.getShortcutLabel,
|
|
126
118
|
getWaveformDataMetadata: () => getWaveformDataMetadata,
|
|
127
119
|
loadPeaksFromWaveformData: () => loadPeaksFromWaveformData,
|
|
128
120
|
loadWaveformData: () => loadWaveformData,
|
|
@@ -130,22 +122,16 @@ __export(index_exports, {
|
|
|
130
122
|
useAnnotationDragHandlers: () => useAnnotationDragHandlers,
|
|
131
123
|
useAnnotationIntegration: () => useAnnotationIntegration,
|
|
132
124
|
useAnnotationKeyboardControls: () => useAnnotationKeyboardControls,
|
|
133
|
-
useAudioTracks: () => useAudioTracks,
|
|
134
125
|
useClipDragHandlers: () => useClipDragHandlers,
|
|
135
126
|
useClipInteractionEnabled: () => useClipInteractionEnabled,
|
|
136
127
|
useClipSplitting: () => useClipSplitting,
|
|
137
128
|
useDragSensors: () => useDragSensors,
|
|
138
|
-
useDynamicEffects: () => useDynamicEffects,
|
|
139
|
-
useDynamicTracks: () => useDynamicTracks,
|
|
140
|
-
useExportWav: () => useExportWav,
|
|
141
129
|
useKeyboardShortcuts: () => useKeyboardShortcuts,
|
|
142
|
-
useMasterAnalyser: () => useMasterAnalyser,
|
|
143
130
|
useMasterVolume: () => useMasterVolume,
|
|
144
131
|
useMediaElementAnimation: () => useMediaElementAnimation,
|
|
145
132
|
useMediaElementControls: () => useMediaElementControls,
|
|
146
133
|
useMediaElementData: () => useMediaElementData,
|
|
147
134
|
useMediaElementState: () => useMediaElementState,
|
|
148
|
-
useOutputMeter: () => useOutputMeter,
|
|
149
135
|
usePlaybackAnimation: () => usePlaybackAnimation,
|
|
150
136
|
usePlaybackShortcuts: () => usePlaybackShortcuts,
|
|
151
137
|
usePlaylistControls: () => usePlaylistControls,
|
|
@@ -154,20 +140,47 @@ __export(index_exports, {
|
|
|
154
140
|
usePlaylistState: () => usePlaylistState,
|
|
155
141
|
useSpectrogramIntegration: () => useSpectrogramIntegration,
|
|
156
142
|
useTimeFormat: () => useTimeFormat,
|
|
157
|
-
useTrackDynamicEffects: () => useTrackDynamicEffects,
|
|
158
143
|
useZoomControls: () => useZoomControls,
|
|
159
144
|
waveformDataToPeaks: () => waveformDataToPeaks
|
|
160
145
|
});
|
|
161
146
|
module.exports = __toCommonJS(index_exports);
|
|
162
|
-
var Tone2 = __toESM(require("tone"));
|
|
163
147
|
|
|
164
148
|
// src/WaveformPlaylistContext.tsx
|
|
165
|
-
var
|
|
149
|
+
var import_react17 = require("react");
|
|
166
150
|
var import_styled_components = require("styled-components");
|
|
167
|
-
|
|
151
|
+
|
|
152
|
+
// src/playout/resolvePlayoutAdapter.ts
|
|
153
|
+
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`.";
|
|
154
|
+
function resolvePlayoutAdapter(opts) {
|
|
155
|
+
return __async(this, null, function* () {
|
|
156
|
+
if (opts.createAdapter) {
|
|
157
|
+
return opts.createAdapter();
|
|
158
|
+
}
|
|
159
|
+
let mod;
|
|
160
|
+
try {
|
|
161
|
+
mod = yield import("@waveform-playlist/playout");
|
|
162
|
+
} catch (originalErr) {
|
|
163
|
+
console.warn(
|
|
164
|
+
"[waveform-playlist] @waveform-playlist/playout dynamic import failed: " + String(originalErr)
|
|
165
|
+
);
|
|
166
|
+
throw new Error(INSTALL_HINT);
|
|
167
|
+
}
|
|
168
|
+
if (opts.sampleRate !== void 0) {
|
|
169
|
+
try {
|
|
170
|
+
mod.configureGlobalContext({ sampleRate: opts.sampleRate });
|
|
171
|
+
} catch (ctxErr) {
|
|
172
|
+
console.warn(
|
|
173
|
+
"[waveform-playlist] configureGlobalContext failed (continuing with default rate): " + String(ctxErr)
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return mod.createToneAdapter({ effects: opts.effects, soundFontCache: opts.soundFontCache });
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// src/WaveformPlaylistContext.tsx
|
|
168
182
|
var import_engine3 = require("@waveform-playlist/engine");
|
|
169
183
|
var import_ui_components2 = require("@waveform-playlist/ui-components");
|
|
170
|
-
var import_tone4 = require("tone");
|
|
171
184
|
|
|
172
185
|
// src/waveformDataLoader.ts
|
|
173
186
|
var import_waveform_data = __toESM(require("waveform-data"));
|
|
@@ -333,9 +346,11 @@ function extractPeaksFromWaveformDataFull(waveformData, samplesPerPixel, isMono,
|
|
|
333
346
|
}
|
|
334
347
|
|
|
335
348
|
// src/soundFontSync.ts
|
|
336
|
-
|
|
349
|
+
function supportsSoundFont(adapter) {
|
|
350
|
+
return adapter != null && typeof adapter.setSoundFontCache === "function";
|
|
351
|
+
}
|
|
337
352
|
function syncSoundFontCacheToAdapter(adapter, cache) {
|
|
338
|
-
if (!(
|
|
353
|
+
if (!supportsSoundFont(adapter)) return;
|
|
339
354
|
adapter.setSoundFontCache(cache);
|
|
340
355
|
}
|
|
341
356
|
|
|
@@ -592,223 +607,8 @@ function useUndoState({ engineRef }) {
|
|
|
592
607
|
};
|
|
593
608
|
}
|
|
594
609
|
|
|
595
|
-
// src/hooks/useAudioEffects.ts
|
|
596
|
-
var import_react8 = require("react");
|
|
597
|
-
var import_tone = require("tone");
|
|
598
|
-
var useMasterAnalyser = (fftSize = 256) => {
|
|
599
|
-
const analyserRef = (0, import_react8.useRef)(null);
|
|
600
|
-
const masterEffects = (0, import_react8.useCallback)(
|
|
601
|
-
(masterGainNode, destination, _isOffline) => {
|
|
602
|
-
const analyserNode = new import_tone.Analyser("fft", fftSize);
|
|
603
|
-
masterGainNode.connect(analyserNode);
|
|
604
|
-
masterGainNode.connect(destination);
|
|
605
|
-
analyserRef.current = analyserNode;
|
|
606
|
-
return function cleanup() {
|
|
607
|
-
analyserNode.dispose();
|
|
608
|
-
analyserRef.current = null;
|
|
609
|
-
};
|
|
610
|
-
},
|
|
611
|
-
[fftSize]
|
|
612
|
-
);
|
|
613
|
-
return { analyserRef, masterEffects };
|
|
614
|
-
};
|
|
615
|
-
|
|
616
|
-
// src/hooks/useAudioTracks.ts
|
|
617
|
-
var import_react9 = require("react");
|
|
618
|
-
var import_core = require("@waveform-playlist/core");
|
|
619
|
-
var Tone = __toESM(require("tone"));
|
|
620
|
-
function buildTrackFromConfig(config, index, audioBuffer, stableIds, contextSampleRate = 48e3) {
|
|
621
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
|
|
622
|
-
const buffer = audioBuffer != null ? audioBuffer : config.audioBuffer;
|
|
623
|
-
const sampleRate = (_c = (_b = buffer == null ? void 0 : buffer.sampleRate) != null ? _b : (_a = config.waveformData) == null ? void 0 : _a.sample_rate) != null ? _c : contextSampleRate;
|
|
624
|
-
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;
|
|
625
|
-
if (sourceDuration === void 0) {
|
|
626
|
-
console.warn(
|
|
627
|
-
`[waveform-playlist] Track ${index + 1} ("${(_h = config.name) != null ? _h : "unnamed"}"): Cannot create track \u2014 provide duration, audioBuffer, or waveformData with duration.`
|
|
628
|
-
);
|
|
629
|
-
return null;
|
|
630
|
-
}
|
|
631
|
-
const clip = (0, import_core.createClipFromSeconds)({
|
|
632
|
-
audioBuffer: buffer,
|
|
633
|
-
sampleRate,
|
|
634
|
-
sourceDuration,
|
|
635
|
-
startTime: (_i = config.startTime) != null ? _i : 0,
|
|
636
|
-
duration: (_j = config.duration) != null ? _j : sourceDuration,
|
|
637
|
-
offset: (_k = config.offset) != null ? _k : 0,
|
|
638
|
-
name: config.name || `Track ${index + 1}`,
|
|
639
|
-
fadeIn: config.fadeIn,
|
|
640
|
-
fadeOut: config.fadeOut,
|
|
641
|
-
waveformData: config.waveformData
|
|
642
|
-
});
|
|
643
|
-
if (isNaN(clip.startSample) || isNaN(clip.durationSamples) || isNaN(clip.offsetSamples)) {
|
|
644
|
-
console.error(
|
|
645
|
-
`[waveform-playlist] Invalid clip values for track ${index + 1} ("${(_l = config.name) != null ? _l : "unnamed"}"): startSample=${clip.startSample}, durationSamples=${clip.durationSamples}, offsetSamples=${clip.offsetSamples}`
|
|
646
|
-
);
|
|
647
|
-
return null;
|
|
648
|
-
}
|
|
649
|
-
const track = __spreadProps(__spreadValues({}, (0, import_core.createTrack)({
|
|
650
|
-
name: config.name || `Track ${index + 1}`,
|
|
651
|
-
clips: [clip],
|
|
652
|
-
muted: (_m = config.muted) != null ? _m : false,
|
|
653
|
-
soloed: (_n = config.soloed) != null ? _n : false,
|
|
654
|
-
volume: (_o = config.volume) != null ? _o : 1,
|
|
655
|
-
pan: (_p = config.pan) != null ? _p : 0,
|
|
656
|
-
color: config.color
|
|
657
|
-
})), {
|
|
658
|
-
effects: config.effects,
|
|
659
|
-
renderMode: config.renderMode,
|
|
660
|
-
spectrogramConfig: config.spectrogramConfig,
|
|
661
|
-
spectrogramColorMap: config.spectrogramColorMap
|
|
662
|
-
});
|
|
663
|
-
const existingIds = stableIds.get(index);
|
|
664
|
-
if (existingIds) {
|
|
665
|
-
track.id = existingIds.trackId;
|
|
666
|
-
track.clips[0] = __spreadProps(__spreadValues({}, track.clips[0]), { id: existingIds.clipId });
|
|
667
|
-
} else {
|
|
668
|
-
stableIds.set(index, { trackId: track.id, clipId: track.clips[0].id });
|
|
669
|
-
}
|
|
670
|
-
return track;
|
|
671
|
-
}
|
|
672
|
-
function useAudioTracks(configs, options = {}) {
|
|
673
|
-
const { immediate = false, progressive = false } = options;
|
|
674
|
-
const isImmediate = immediate || progressive;
|
|
675
|
-
const [loading, setLoading] = (0, import_react9.useState)(true);
|
|
676
|
-
const [error, setError] = (0, import_react9.useState)(null);
|
|
677
|
-
const [loadedCount, setLoadedCount] = (0, import_react9.useState)(0);
|
|
678
|
-
const totalCount = configs.length;
|
|
679
|
-
const [loadedBuffers, setLoadedBuffers] = (0, import_react9.useState)(/* @__PURE__ */ new Map());
|
|
680
|
-
const stableIdsRef = (0, import_react9.useRef)(/* @__PURE__ */ new Map());
|
|
681
|
-
const contextSampleRateRef = (0, import_react9.useRef)(48e3);
|
|
682
|
-
const derivedTracks = (0, import_react9.useMemo)(() => {
|
|
683
|
-
if (!isImmediate) return null;
|
|
684
|
-
const result = [];
|
|
685
|
-
for (let i = 0; i < configs.length; i++) {
|
|
686
|
-
const track = buildTrackFromConfig(
|
|
687
|
-
configs[i],
|
|
688
|
-
i,
|
|
689
|
-
loadedBuffers.get(i),
|
|
690
|
-
stableIdsRef.current,
|
|
691
|
-
contextSampleRateRef.current
|
|
692
|
-
);
|
|
693
|
-
if (track) result.push(track);
|
|
694
|
-
}
|
|
695
|
-
return result;
|
|
696
|
-
}, [isImmediate, configs, loadedBuffers]);
|
|
697
|
-
const [tracks, setTracks] = (0, import_react9.useState)(derivedTracks != null ? derivedTracks : []);
|
|
698
|
-
const prevDerivedRef = (0, import_react9.useRef)(derivedTracks);
|
|
699
|
-
if (derivedTracks !== prevDerivedRef.current) {
|
|
700
|
-
prevDerivedRef.current = derivedTracks;
|
|
701
|
-
if (derivedTracks) setTracks(derivedTracks);
|
|
702
|
-
}
|
|
703
|
-
(0, import_react9.useEffect)(() => {
|
|
704
|
-
if (configs.length === 0) {
|
|
705
|
-
setTracks([]);
|
|
706
|
-
setLoading(false);
|
|
707
|
-
setLoadedCount(0);
|
|
708
|
-
return;
|
|
709
|
-
}
|
|
710
|
-
let cancelled = false;
|
|
711
|
-
const abortController = new AbortController();
|
|
712
|
-
const loadTracks = () => __async(null, null, function* () {
|
|
713
|
-
try {
|
|
714
|
-
setLoading(true);
|
|
715
|
-
setError(null);
|
|
716
|
-
setLoadedCount(0);
|
|
717
|
-
if (isImmediate) {
|
|
718
|
-
setLoadedBuffers(/* @__PURE__ */ new Map());
|
|
719
|
-
}
|
|
720
|
-
const audioContext = Tone.getContext().rawContext;
|
|
721
|
-
contextSampleRateRef.current = audioContext.sampleRate;
|
|
722
|
-
const loadPromises = configs.map((config, index) => __async(null, null, function* () {
|
|
723
|
-
if (config.audioBuffer) {
|
|
724
|
-
if (isImmediate && !cancelled) {
|
|
725
|
-
setLoadedBuffers((prev) => {
|
|
726
|
-
const next = new Map(prev);
|
|
727
|
-
next.set(index, config.audioBuffer);
|
|
728
|
-
return next;
|
|
729
|
-
});
|
|
730
|
-
setLoadedCount((prev) => prev + 1);
|
|
731
|
-
return;
|
|
732
|
-
}
|
|
733
|
-
return buildTrackFromConfig(
|
|
734
|
-
config,
|
|
735
|
-
index,
|
|
736
|
-
config.audioBuffer,
|
|
737
|
-
stableIdsRef.current,
|
|
738
|
-
audioContext.sampleRate
|
|
739
|
-
);
|
|
740
|
-
}
|
|
741
|
-
if (!config.src && config.waveformData) {
|
|
742
|
-
if (isImmediate && !cancelled) {
|
|
743
|
-
setLoadedCount((prev) => prev + 1);
|
|
744
|
-
return;
|
|
745
|
-
}
|
|
746
|
-
return buildTrackFromConfig(
|
|
747
|
-
config,
|
|
748
|
-
index,
|
|
749
|
-
void 0,
|
|
750
|
-
stableIdsRef.current,
|
|
751
|
-
audioContext.sampleRate
|
|
752
|
-
);
|
|
753
|
-
}
|
|
754
|
-
if (!config.src) {
|
|
755
|
-
throw new Error(`Track ${index + 1}: Must provide src, audioBuffer, or waveformData`);
|
|
756
|
-
}
|
|
757
|
-
const response = yield fetch(config.src, { signal: abortController.signal });
|
|
758
|
-
if (!response.ok) {
|
|
759
|
-
throw new Error(`Failed to fetch ${config.src}: ${response.statusText}`);
|
|
760
|
-
}
|
|
761
|
-
const arrayBuffer = yield response.arrayBuffer();
|
|
762
|
-
const audioBuffer = yield audioContext.decodeAudioData(arrayBuffer);
|
|
763
|
-
if (!audioBuffer || !audioBuffer.sampleRate || !audioBuffer.duration) {
|
|
764
|
-
throw new Error(`Invalid audio buffer for ${config.src}`);
|
|
765
|
-
}
|
|
766
|
-
if (isImmediate && !cancelled) {
|
|
767
|
-
setLoadedBuffers((prev) => {
|
|
768
|
-
const next = new Map(prev);
|
|
769
|
-
next.set(index, audioBuffer);
|
|
770
|
-
return next;
|
|
771
|
-
});
|
|
772
|
-
setLoadedCount((prev) => prev + 1);
|
|
773
|
-
return;
|
|
774
|
-
}
|
|
775
|
-
return buildTrackFromConfig(
|
|
776
|
-
config,
|
|
777
|
-
index,
|
|
778
|
-
audioBuffer,
|
|
779
|
-
stableIdsRef.current,
|
|
780
|
-
audioContext.sampleRate
|
|
781
|
-
);
|
|
782
|
-
}));
|
|
783
|
-
const loadedTracks = yield Promise.all(loadPromises);
|
|
784
|
-
if (!cancelled) {
|
|
785
|
-
if (!isImmediate) {
|
|
786
|
-
const validTracks = loadedTracks.filter((t) => t != null);
|
|
787
|
-
setTracks(validTracks);
|
|
788
|
-
setLoadedCount(validTracks.length);
|
|
789
|
-
}
|
|
790
|
-
setLoading(false);
|
|
791
|
-
}
|
|
792
|
-
} catch (err) {
|
|
793
|
-
if (!cancelled) {
|
|
794
|
-
const errorMessage = err instanceof Error ? err.message : "Unknown error loading audio";
|
|
795
|
-
setError(errorMessage);
|
|
796
|
-
setLoading(false);
|
|
797
|
-
console.error(`[waveform-playlist] Error loading audio tracks: ${errorMessage}`);
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
});
|
|
801
|
-
loadTracks();
|
|
802
|
-
return () => {
|
|
803
|
-
cancelled = true;
|
|
804
|
-
abortController.abort();
|
|
805
|
-
};
|
|
806
|
-
}, [configs, isImmediate]);
|
|
807
|
-
return { tracks, loading, error, loadedCount, totalCount };
|
|
808
|
-
}
|
|
809
|
-
|
|
810
610
|
// src/hooks/useClipDragHandlers.ts
|
|
811
|
-
var
|
|
611
|
+
var import_react8 = __toESM(require("react"));
|
|
812
612
|
|
|
813
613
|
// src/utils/boundaryTrim.ts
|
|
814
614
|
var import_engine = require("@waveform-playlist/engine");
|
|
@@ -862,11 +662,11 @@ function useClipDragHandlers({
|
|
|
862
662
|
snapSamplePosition
|
|
863
663
|
}) {
|
|
864
664
|
const { sampleRate } = usePlaylistData();
|
|
865
|
-
const snapSamplePositionRef =
|
|
665
|
+
const snapSamplePositionRef = import_react8.default.useRef(snapSamplePosition);
|
|
866
666
|
snapSamplePositionRef.current = snapSamplePosition;
|
|
867
|
-
const originalClipStateRef =
|
|
868
|
-
const lastBoundaryDeltaRef =
|
|
869
|
-
const onDragStart =
|
|
667
|
+
const originalClipStateRef = import_react8.default.useRef(null);
|
|
668
|
+
const lastBoundaryDeltaRef = import_react8.default.useRef(0);
|
|
669
|
+
const onDragStart = import_react8.default.useCallback(
|
|
870
670
|
(event) => {
|
|
871
671
|
var _a;
|
|
872
672
|
const data = (_a = event.operation.source) == null ? void 0 : _a.data;
|
|
@@ -902,7 +702,7 @@ function useClipDragHandlers({
|
|
|
902
702
|
},
|
|
903
703
|
[tracks, isDraggingRef, engineRef]
|
|
904
704
|
);
|
|
905
|
-
const onDragMove =
|
|
705
|
+
const onDragMove = import_react8.default.useCallback(
|
|
906
706
|
(event) => {
|
|
907
707
|
var _a, _b, _c;
|
|
908
708
|
const data = (_a = event.operation.source) == null ? void 0 : _a.data;
|
|
@@ -964,7 +764,7 @@ function useClipDragHandlers({
|
|
|
964
764
|
},
|
|
965
765
|
[tracks, onTracksChange, samplesPerPixel, sampleRate]
|
|
966
766
|
);
|
|
967
|
-
const onDragEnd =
|
|
767
|
+
const onDragEnd = import_react8.default.useCallback(
|
|
968
768
|
(event) => {
|
|
969
769
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
970
770
|
if (event.canceled) {
|
|
@@ -1042,19 +842,19 @@ function useClipDragHandlers({
|
|
|
1042
842
|
}
|
|
1043
843
|
|
|
1044
844
|
// src/hooks/useAnnotationDragHandlers.ts
|
|
1045
|
-
var
|
|
1046
|
-
var import_playout2 = require("@waveform-playlist/playout");
|
|
845
|
+
var import_react9 = __toESM(require("react"));
|
|
1047
846
|
var LINK_THRESHOLD = 0.01;
|
|
1048
847
|
function useAnnotationDragHandlers({
|
|
1049
848
|
annotations,
|
|
1050
849
|
onAnnotationsChange,
|
|
1051
850
|
samplesPerPixel,
|
|
1052
|
-
|
|
851
|
+
// Default mirrors the engine default; the providers always pass the real rate from context (#510).
|
|
852
|
+
sampleRate = 48e3,
|
|
1053
853
|
duration,
|
|
1054
854
|
linkEndpoints
|
|
1055
855
|
}) {
|
|
1056
|
-
const originalAnnotationStateRef =
|
|
1057
|
-
const onDragStart =
|
|
856
|
+
const originalAnnotationStateRef = import_react9.default.useRef(null);
|
|
857
|
+
const onDragStart = import_react9.default.useCallback(
|
|
1058
858
|
(event) => {
|
|
1059
859
|
var _a;
|
|
1060
860
|
const data = (_a = event.operation.source) == null ? void 0 : _a.data;
|
|
@@ -1073,7 +873,7 @@ function useAnnotationDragHandlers({
|
|
|
1073
873
|
},
|
|
1074
874
|
[annotations]
|
|
1075
875
|
);
|
|
1076
|
-
const onDragMove =
|
|
876
|
+
const onDragMove = import_react9.default.useCallback(
|
|
1077
877
|
(event) => {
|
|
1078
878
|
var _a, _b, _c;
|
|
1079
879
|
if (!originalAnnotationStateRef.current) {
|
|
@@ -1099,7 +899,7 @@ function useAnnotationDragHandlers({
|
|
|
1099
899
|
},
|
|
1100
900
|
[annotations, onAnnotationsChange, samplesPerPixel, sampleRate, duration, linkEndpoints]
|
|
1101
901
|
);
|
|
1102
|
-
const onDragEnd =
|
|
902
|
+
const onDragEnd = import_react9.default.useCallback(
|
|
1103
903
|
(event) => {
|
|
1104
904
|
if (event.canceled && originalAnnotationStateRef.current) {
|
|
1105
905
|
const { annotationIndex, start, end } = originalAnnotationStateRef.current;
|
|
@@ -1207,7 +1007,7 @@ function updateAnnotationBoundaries({
|
|
|
1207
1007
|
}
|
|
1208
1008
|
|
|
1209
1009
|
// src/hooks/useDragSensors.ts
|
|
1210
|
-
var
|
|
1010
|
+
var import_react10 = require("react");
|
|
1211
1011
|
var import_dom = require("@dnd-kit/dom");
|
|
1212
1012
|
function useDragSensors(options = {}) {
|
|
1213
1013
|
const {
|
|
@@ -1216,7 +1016,7 @@ function useDragSensors(options = {}) {
|
|
|
1216
1016
|
touchTolerance = 5,
|
|
1217
1017
|
mouseDistance = 1
|
|
1218
1018
|
} = options;
|
|
1219
|
-
return (0,
|
|
1019
|
+
return (0, import_react10.useMemo)(() => {
|
|
1220
1020
|
if (touchOptimized) {
|
|
1221
1021
|
return [
|
|
1222
1022
|
import_dom.PointerSensor.configure({
|
|
@@ -1245,14 +1045,14 @@ function useDragSensors(options = {}) {
|
|
|
1245
1045
|
}
|
|
1246
1046
|
|
|
1247
1047
|
// src/hooks/useClipSplitting.ts
|
|
1248
|
-
var
|
|
1048
|
+
var import_react11 = require("react");
|
|
1249
1049
|
var import_engine2 = require("@waveform-playlist/engine");
|
|
1250
1050
|
var useClipSplitting = (options) => {
|
|
1251
1051
|
const { tracks, engineRef } = options;
|
|
1252
1052
|
const { sampleRate } = usePlaylistData();
|
|
1253
1053
|
const { currentTimeRef } = usePlaybackAnimation();
|
|
1254
1054
|
const { selectedTrackId } = usePlaylistState();
|
|
1255
|
-
const splitClipAt = (0,
|
|
1055
|
+
const splitClipAt = (0, import_react11.useCallback)(
|
|
1256
1056
|
(trackIndex, clipIndex, splitTime) => {
|
|
1257
1057
|
const { samplesPerPixel } = options;
|
|
1258
1058
|
const track = tracks[trackIndex];
|
|
@@ -1276,7 +1076,7 @@ var useClipSplitting = (options) => {
|
|
|
1276
1076
|
},
|
|
1277
1077
|
[tracks, options, engineRef, sampleRate]
|
|
1278
1078
|
);
|
|
1279
|
-
const splitClipAtPlayhead = (0,
|
|
1079
|
+
const splitClipAtPlayhead = (0, import_react11.useCallback)(() => {
|
|
1280
1080
|
var _a;
|
|
1281
1081
|
if (!selectedTrackId) {
|
|
1282
1082
|
console.warn("[waveform-playlist] No track selected \u2014 click a clip to select a track first");
|
|
@@ -1307,16 +1107,16 @@ var useClipSplitting = (options) => {
|
|
|
1307
1107
|
};
|
|
1308
1108
|
|
|
1309
1109
|
// src/hooks/useKeyboardShortcuts.ts
|
|
1310
|
-
var
|
|
1110
|
+
var import_react12 = require("react");
|
|
1111
|
+
var import_core = require("@waveform-playlist/core");
|
|
1311
1112
|
var import_core2 = require("@waveform-playlist/core");
|
|
1312
|
-
var import_core3 = require("@waveform-playlist/core");
|
|
1313
1113
|
var useKeyboardShortcuts = (options) => {
|
|
1314
1114
|
const { shortcuts, enabled = true } = options;
|
|
1315
|
-
const handleKeyDown = (0,
|
|
1316
|
-
(event) => (0,
|
|
1115
|
+
const handleKeyDown = (0, import_react12.useCallback)(
|
|
1116
|
+
(event) => (0, import_core.handleKeyboardEvent)(event, shortcuts, enabled),
|
|
1317
1117
|
[shortcuts, enabled]
|
|
1318
1118
|
);
|
|
1319
|
-
(0,
|
|
1119
|
+
(0, import_react12.useEffect)(() => {
|
|
1320
1120
|
if (!enabled) return;
|
|
1321
1121
|
window.addEventListener("keydown", handleKeyDown);
|
|
1322
1122
|
return () => {
|
|
@@ -1326,22 +1126,22 @@ var useKeyboardShortcuts = (options) => {
|
|
|
1326
1126
|
};
|
|
1327
1127
|
|
|
1328
1128
|
// src/hooks/usePlaybackShortcuts.ts
|
|
1329
|
-
var
|
|
1129
|
+
var import_react13 = require("react");
|
|
1330
1130
|
var usePlaybackShortcuts = (options = {}) => {
|
|
1331
1131
|
const { enabled = true, additionalShortcuts = [], shortcuts: overrideShortcuts } = options;
|
|
1332
1132
|
const { isPlaying } = usePlaybackAnimation();
|
|
1333
1133
|
const { setCurrentTime, play, pause, stop } = usePlaylistControls();
|
|
1334
|
-
const togglePlayPause = (0,
|
|
1134
|
+
const togglePlayPause = (0, import_react13.useCallback)(() => {
|
|
1335
1135
|
if (isPlaying) {
|
|
1336
1136
|
pause();
|
|
1337
1137
|
} else {
|
|
1338
1138
|
play();
|
|
1339
1139
|
}
|
|
1340
1140
|
}, [isPlaying, play, pause]);
|
|
1341
|
-
const stopPlayback = (0,
|
|
1141
|
+
const stopPlayback = (0, import_react13.useCallback)(() => {
|
|
1342
1142
|
stop();
|
|
1343
1143
|
}, [stop]);
|
|
1344
|
-
const rewindToStart = (0,
|
|
1144
|
+
const rewindToStart = (0, import_react13.useCallback)(() => {
|
|
1345
1145
|
setCurrentTime(0);
|
|
1346
1146
|
if (isPlaying) {
|
|
1347
1147
|
play(0);
|
|
@@ -1381,7 +1181,7 @@ var usePlaybackShortcuts = (options = {}) => {
|
|
|
1381
1181
|
};
|
|
1382
1182
|
|
|
1383
1183
|
// src/hooks/useAnnotationKeyboardControls.ts
|
|
1384
|
-
var
|
|
1184
|
+
var import_react14 = require("react");
|
|
1385
1185
|
var LINK_THRESHOLD2 = 0.01;
|
|
1386
1186
|
var TIME_DELTA = 0.01;
|
|
1387
1187
|
function useAnnotationKeyboardControls({
|
|
@@ -1401,11 +1201,11 @@ function useAnnotationKeyboardControls({
|
|
|
1401
1201
|
const playlistData = usePlaylistDataOptional();
|
|
1402
1202
|
const samplesPerPixel = samplesPerPixelProp != null ? samplesPerPixelProp : playlistData == null ? void 0 : playlistData.samplesPerPixel;
|
|
1403
1203
|
const sampleRate = sampleRateProp != null ? sampleRateProp : playlistData == null ? void 0 : playlistData.sampleRate;
|
|
1404
|
-
const activeIndex = (0,
|
|
1204
|
+
const activeIndex = (0, import_react14.useMemo)(() => {
|
|
1405
1205
|
if (!activeAnnotationId) return -1;
|
|
1406
1206
|
return annotations.findIndex((a) => a.id === activeAnnotationId);
|
|
1407
1207
|
}, [annotations, activeAnnotationId]);
|
|
1408
|
-
const scrollToAnnotation = (0,
|
|
1208
|
+
const scrollToAnnotation = (0, import_react14.useCallback)(
|
|
1409
1209
|
(annotationId) => {
|
|
1410
1210
|
if (!(scrollContainerRef == null ? void 0 : scrollContainerRef.current) || !samplesPerPixel || !sampleRate) return;
|
|
1411
1211
|
const annotation = annotations.find((a) => a.id === annotationId);
|
|
@@ -1428,12 +1228,12 @@ function useAnnotationKeyboardControls({
|
|
|
1428
1228
|
},
|
|
1429
1229
|
[annotations, scrollContainerRef, samplesPerPixel, sampleRate]
|
|
1430
1230
|
);
|
|
1431
|
-
(0,
|
|
1231
|
+
(0, import_react14.useEffect)(() => {
|
|
1432
1232
|
if (activeAnnotationId && (scrollContainerRef == null ? void 0 : scrollContainerRef.current) && samplesPerPixel && sampleRate) {
|
|
1433
1233
|
scrollToAnnotation(activeAnnotationId);
|
|
1434
1234
|
}
|
|
1435
1235
|
}, [activeAnnotationId, scrollToAnnotation, scrollContainerRef, samplesPerPixel, sampleRate]);
|
|
1436
|
-
const moveStartBoundary = (0,
|
|
1236
|
+
const moveStartBoundary = (0, import_react14.useCallback)(
|
|
1437
1237
|
(delta) => {
|
|
1438
1238
|
if (activeIndex < 0) return;
|
|
1439
1239
|
const annotation = annotations[activeIndex];
|
|
@@ -1462,7 +1262,7 @@ function useAnnotationKeyboardControls({
|
|
|
1462
1262
|
},
|
|
1463
1263
|
[annotations, activeIndex, linkEndpoints, onAnnotationsChange]
|
|
1464
1264
|
);
|
|
1465
|
-
const moveEndBoundary = (0,
|
|
1265
|
+
const moveEndBoundary = (0, import_react14.useCallback)(
|
|
1466
1266
|
(delta) => {
|
|
1467
1267
|
if (activeIndex < 0) return;
|
|
1468
1268
|
const annotation = annotations[activeIndex];
|
|
@@ -1522,7 +1322,7 @@ function useAnnotationKeyboardControls({
|
|
|
1522
1322
|
},
|
|
1523
1323
|
[annotations, activeIndex, duration, linkEndpoints, onAnnotationsChange]
|
|
1524
1324
|
);
|
|
1525
|
-
const selectPrevious = (0,
|
|
1325
|
+
const selectPrevious = (0, import_react14.useCallback)(() => {
|
|
1526
1326
|
if (!onActiveAnnotationChange || annotations.length === 0) return;
|
|
1527
1327
|
if (activeIndex <= 0) {
|
|
1528
1328
|
onActiveAnnotationChange(annotations[annotations.length - 1].id);
|
|
@@ -1530,7 +1330,7 @@ function useAnnotationKeyboardControls({
|
|
|
1530
1330
|
onActiveAnnotationChange(annotations[activeIndex - 1].id);
|
|
1531
1331
|
}
|
|
1532
1332
|
}, [annotations, activeIndex, onActiveAnnotationChange]);
|
|
1533
|
-
const selectNext = (0,
|
|
1333
|
+
const selectNext = (0, import_react14.useCallback)(() => {
|
|
1534
1334
|
if (!onActiveAnnotationChange || annotations.length === 0) return;
|
|
1535
1335
|
if (activeIndex < 0 || activeIndex >= annotations.length - 1) {
|
|
1536
1336
|
onActiveAnnotationChange(annotations[0].id);
|
|
@@ -1538,25 +1338,25 @@ function useAnnotationKeyboardControls({
|
|
|
1538
1338
|
onActiveAnnotationChange(annotations[activeIndex + 1].id);
|
|
1539
1339
|
}
|
|
1540
1340
|
}, [annotations, activeIndex, onActiveAnnotationChange]);
|
|
1541
|
-
const selectFirst = (0,
|
|
1341
|
+
const selectFirst = (0, import_react14.useCallback)(() => {
|
|
1542
1342
|
if (!onActiveAnnotationChange || annotations.length === 0) return;
|
|
1543
1343
|
onActiveAnnotationChange(annotations[0].id);
|
|
1544
1344
|
}, [annotations, onActiveAnnotationChange]);
|
|
1545
|
-
const selectLast = (0,
|
|
1345
|
+
const selectLast = (0, import_react14.useCallback)(() => {
|
|
1546
1346
|
if (!onActiveAnnotationChange || annotations.length === 0) return;
|
|
1547
1347
|
onActiveAnnotationChange(annotations[annotations.length - 1].id);
|
|
1548
1348
|
}, [annotations, onActiveAnnotationChange]);
|
|
1549
|
-
const clearSelection = (0,
|
|
1349
|
+
const clearSelection = (0, import_react14.useCallback)(() => {
|
|
1550
1350
|
if (!onActiveAnnotationChange) return;
|
|
1551
1351
|
onActiveAnnotationChange(null);
|
|
1552
1352
|
}, [onActiveAnnotationChange]);
|
|
1553
|
-
const playActiveAnnotation = (0,
|
|
1353
|
+
const playActiveAnnotation = (0, import_react14.useCallback)(() => {
|
|
1554
1354
|
if (activeIndex < 0 || !onPlay) return;
|
|
1555
1355
|
const annotation = annotations[activeIndex];
|
|
1556
1356
|
const playDuration = !continuousPlay ? annotation.end - annotation.start : void 0;
|
|
1557
1357
|
onPlay(annotation.start, playDuration);
|
|
1558
1358
|
}, [annotations, activeIndex, continuousPlay, onPlay]);
|
|
1559
|
-
const activeAnnotationShortcuts = (0,
|
|
1359
|
+
const activeAnnotationShortcuts = (0, import_react14.useMemo)(
|
|
1560
1360
|
() => [
|
|
1561
1361
|
{
|
|
1562
1362
|
key: "[",
|
|
@@ -1593,7 +1393,7 @@ function useAnnotationKeyboardControls({
|
|
|
1593
1393
|
],
|
|
1594
1394
|
[moveStartBoundary, moveEndBoundary, playActiveAnnotation]
|
|
1595
1395
|
);
|
|
1596
|
-
const navigationShortcuts = (0,
|
|
1396
|
+
const navigationShortcuts = (0, import_react14.useMemo)(
|
|
1597
1397
|
() => [
|
|
1598
1398
|
{
|
|
1599
1399
|
key: "ArrowUp",
|
|
@@ -1646,1397 +1446,39 @@ function useAnnotationKeyboardControls({
|
|
|
1646
1446
|
});
|
|
1647
1447
|
useKeyboardShortcuts({
|
|
1648
1448
|
shortcuts: navigationShortcuts,
|
|
1649
|
-
enabled: enabled && annotations.length > 0 && !!onActiveAnnotationChange
|
|
1650
|
-
});
|
|
1651
|
-
return {
|
|
1652
|
-
moveStartBoundary,
|
|
1653
|
-
moveEndBoundary,
|
|
1654
|
-
selectPrevious,
|
|
1655
|
-
selectNext,
|
|
1656
|
-
selectFirst,
|
|
1657
|
-
selectLast,
|
|
1658
|
-
clearSelection,
|
|
1659
|
-
scrollToAnnotation,
|
|
1660
|
-
playActiveAnnotation
|
|
1661
|
-
};
|
|
1662
|
-
}
|
|
1663
|
-
|
|
1664
|
-
// src/hooks/useDynamicEffects.ts
|
|
1665
|
-
var import_react17 = require("react");
|
|
1666
|
-
|
|
1667
|
-
// src/effects/effectDefinitions.ts
|
|
1668
|
-
var effectDefinitions = [
|
|
1669
|
-
// === REVERB EFFECTS ===
|
|
1670
|
-
{
|
|
1671
|
-
id: "reverb",
|
|
1672
|
-
name: "Reverb",
|
|
1673
|
-
category: "reverb",
|
|
1674
|
-
description: "Simple convolution reverb with adjustable decay time",
|
|
1675
|
-
parameters: [
|
|
1676
|
-
{
|
|
1677
|
-
name: "decay",
|
|
1678
|
-
label: "Decay",
|
|
1679
|
-
type: "number",
|
|
1680
|
-
min: 0.1,
|
|
1681
|
-
max: 10,
|
|
1682
|
-
step: 0.1,
|
|
1683
|
-
default: 1.5,
|
|
1684
|
-
unit: "s"
|
|
1685
|
-
},
|
|
1686
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1687
|
-
]
|
|
1688
|
-
},
|
|
1689
|
-
{
|
|
1690
|
-
id: "freeverb",
|
|
1691
|
-
name: "Freeverb",
|
|
1692
|
-
category: "reverb",
|
|
1693
|
-
description: "Classic Schroeder/Moorer reverb with room size and dampening",
|
|
1694
|
-
parameters: [
|
|
1695
|
-
{
|
|
1696
|
-
name: "roomSize",
|
|
1697
|
-
label: "Room Size",
|
|
1698
|
-
type: "number",
|
|
1699
|
-
min: 0,
|
|
1700
|
-
max: 1,
|
|
1701
|
-
step: 0.01,
|
|
1702
|
-
default: 0.7
|
|
1703
|
-
},
|
|
1704
|
-
{
|
|
1705
|
-
name: "dampening",
|
|
1706
|
-
label: "Dampening",
|
|
1707
|
-
type: "number",
|
|
1708
|
-
min: 0,
|
|
1709
|
-
max: 1e4,
|
|
1710
|
-
step: 100,
|
|
1711
|
-
default: 3e3,
|
|
1712
|
-
unit: "Hz"
|
|
1713
|
-
},
|
|
1714
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1715
|
-
]
|
|
1716
|
-
},
|
|
1717
|
-
{
|
|
1718
|
-
id: "jcReverb",
|
|
1719
|
-
name: "JC Reverb",
|
|
1720
|
-
category: "reverb",
|
|
1721
|
-
description: "Attempt at Roland JC-120 chorus reverb emulation",
|
|
1722
|
-
parameters: [
|
|
1723
|
-
{
|
|
1724
|
-
name: "roomSize",
|
|
1725
|
-
label: "Room Size",
|
|
1726
|
-
type: "number",
|
|
1727
|
-
min: 0,
|
|
1728
|
-
max: 1,
|
|
1729
|
-
step: 0.01,
|
|
1730
|
-
default: 0.5
|
|
1731
|
-
},
|
|
1732
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1733
|
-
]
|
|
1734
|
-
},
|
|
1735
|
-
// === DELAY EFFECTS ===
|
|
1736
|
-
{
|
|
1737
|
-
id: "feedbackDelay",
|
|
1738
|
-
name: "Feedback Delay",
|
|
1739
|
-
category: "delay",
|
|
1740
|
-
description: "Delay line with feedback for echo effects",
|
|
1741
|
-
parameters: [
|
|
1742
|
-
{
|
|
1743
|
-
name: "delayTime",
|
|
1744
|
-
label: "Delay Time",
|
|
1745
|
-
type: "number",
|
|
1746
|
-
min: 0,
|
|
1747
|
-
max: 1,
|
|
1748
|
-
step: 0.01,
|
|
1749
|
-
default: 0.25,
|
|
1750
|
-
unit: "s"
|
|
1751
|
-
},
|
|
1752
|
-
{
|
|
1753
|
-
name: "feedback",
|
|
1754
|
-
label: "Feedback",
|
|
1755
|
-
type: "number",
|
|
1756
|
-
min: 0,
|
|
1757
|
-
max: 0.95,
|
|
1758
|
-
step: 0.01,
|
|
1759
|
-
default: 0.5
|
|
1760
|
-
},
|
|
1761
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1762
|
-
]
|
|
1763
|
-
},
|
|
1764
|
-
{
|
|
1765
|
-
id: "pingPongDelay",
|
|
1766
|
-
name: "Ping Pong Delay",
|
|
1767
|
-
category: "delay",
|
|
1768
|
-
description: "Stereo delay bouncing between left and right channels",
|
|
1769
|
-
parameters: [
|
|
1770
|
-
{
|
|
1771
|
-
name: "delayTime",
|
|
1772
|
-
label: "Delay Time",
|
|
1773
|
-
type: "number",
|
|
1774
|
-
min: 0,
|
|
1775
|
-
max: 1,
|
|
1776
|
-
step: 0.01,
|
|
1777
|
-
default: 0.25,
|
|
1778
|
-
unit: "s"
|
|
1779
|
-
},
|
|
1780
|
-
{
|
|
1781
|
-
name: "feedback",
|
|
1782
|
-
label: "Feedback",
|
|
1783
|
-
type: "number",
|
|
1784
|
-
min: 0,
|
|
1785
|
-
max: 0.95,
|
|
1786
|
-
step: 0.01,
|
|
1787
|
-
default: 0.5
|
|
1788
|
-
},
|
|
1789
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1790
|
-
]
|
|
1791
|
-
},
|
|
1792
|
-
// === MODULATION EFFECTS ===
|
|
1793
|
-
{
|
|
1794
|
-
id: "chorus",
|
|
1795
|
-
name: "Chorus",
|
|
1796
|
-
category: "modulation",
|
|
1797
|
-
description: "Creates thickness by layering detuned copies of the signal",
|
|
1798
|
-
parameters: [
|
|
1799
|
-
{
|
|
1800
|
-
name: "frequency",
|
|
1801
|
-
label: "Rate",
|
|
1802
|
-
type: "number",
|
|
1803
|
-
min: 0.1,
|
|
1804
|
-
max: 10,
|
|
1805
|
-
step: 0.1,
|
|
1806
|
-
default: 1.5,
|
|
1807
|
-
unit: "Hz"
|
|
1808
|
-
},
|
|
1809
|
-
{
|
|
1810
|
-
name: "delayTime",
|
|
1811
|
-
label: "Delay",
|
|
1812
|
-
type: "number",
|
|
1813
|
-
min: 0,
|
|
1814
|
-
max: 20,
|
|
1815
|
-
step: 0.5,
|
|
1816
|
-
default: 3.5,
|
|
1817
|
-
unit: "ms"
|
|
1818
|
-
},
|
|
1819
|
-
{ name: "depth", label: "Depth", type: "number", min: 0, max: 1, step: 0.01, default: 0.7 },
|
|
1820
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1821
|
-
]
|
|
1822
|
-
},
|
|
1823
|
-
{
|
|
1824
|
-
id: "phaser",
|
|
1825
|
-
name: "Phaser",
|
|
1826
|
-
category: "modulation",
|
|
1827
|
-
description: "Classic phaser effect using allpass filters",
|
|
1828
|
-
parameters: [
|
|
1829
|
-
{
|
|
1830
|
-
name: "frequency",
|
|
1831
|
-
label: "Rate",
|
|
1832
|
-
type: "number",
|
|
1833
|
-
min: 0.1,
|
|
1834
|
-
max: 10,
|
|
1835
|
-
step: 0.1,
|
|
1836
|
-
default: 0.5,
|
|
1837
|
-
unit: "Hz"
|
|
1838
|
-
},
|
|
1839
|
-
{ name: "octaves", label: "Octaves", type: "number", min: 1, max: 6, step: 1, default: 3 },
|
|
1840
|
-
{
|
|
1841
|
-
name: "baseFrequency",
|
|
1842
|
-
label: "Base Freq",
|
|
1843
|
-
type: "number",
|
|
1844
|
-
min: 100,
|
|
1845
|
-
max: 2e3,
|
|
1846
|
-
step: 10,
|
|
1847
|
-
default: 350,
|
|
1848
|
-
unit: "Hz"
|
|
1849
|
-
},
|
|
1850
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1851
|
-
]
|
|
1852
|
-
},
|
|
1853
|
-
{
|
|
1854
|
-
id: "tremolo",
|
|
1855
|
-
name: "Tremolo",
|
|
1856
|
-
category: "modulation",
|
|
1857
|
-
description: "Rhythmic volume modulation",
|
|
1858
|
-
parameters: [
|
|
1859
|
-
{
|
|
1860
|
-
name: "frequency",
|
|
1861
|
-
label: "Rate",
|
|
1862
|
-
type: "number",
|
|
1863
|
-
min: 0.1,
|
|
1864
|
-
max: 20,
|
|
1865
|
-
step: 0.1,
|
|
1866
|
-
default: 4,
|
|
1867
|
-
unit: "Hz"
|
|
1868
|
-
},
|
|
1869
|
-
{ name: "depth", label: "Depth", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 },
|
|
1870
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1871
|
-
]
|
|
1872
|
-
},
|
|
1873
|
-
{
|
|
1874
|
-
id: "vibrato",
|
|
1875
|
-
name: "Vibrato",
|
|
1876
|
-
category: "modulation",
|
|
1877
|
-
description: "Pitch modulation effect",
|
|
1878
|
-
parameters: [
|
|
1879
|
-
{
|
|
1880
|
-
name: "frequency",
|
|
1881
|
-
label: "Rate",
|
|
1882
|
-
type: "number",
|
|
1883
|
-
min: 0.1,
|
|
1884
|
-
max: 20,
|
|
1885
|
-
step: 0.1,
|
|
1886
|
-
default: 5,
|
|
1887
|
-
unit: "Hz"
|
|
1888
|
-
},
|
|
1889
|
-
{ name: "depth", label: "Depth", type: "number", min: 0, max: 1, step: 0.01, default: 0.1 },
|
|
1890
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1891
|
-
]
|
|
1892
|
-
},
|
|
1893
|
-
{
|
|
1894
|
-
id: "autoPanner",
|
|
1895
|
-
name: "Auto Panner",
|
|
1896
|
-
category: "modulation",
|
|
1897
|
-
description: "Automatic left-right panning",
|
|
1898
|
-
parameters: [
|
|
1899
|
-
{
|
|
1900
|
-
name: "frequency",
|
|
1901
|
-
label: "Rate",
|
|
1902
|
-
type: "number",
|
|
1903
|
-
min: 0.1,
|
|
1904
|
-
max: 10,
|
|
1905
|
-
step: 0.1,
|
|
1906
|
-
default: 1,
|
|
1907
|
-
unit: "Hz"
|
|
1908
|
-
},
|
|
1909
|
-
{ name: "depth", label: "Depth", type: "number", min: 0, max: 1, step: 0.01, default: 1 },
|
|
1910
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1911
|
-
]
|
|
1912
|
-
},
|
|
1913
|
-
// === FILTER EFFECTS ===
|
|
1914
|
-
{
|
|
1915
|
-
id: "autoFilter",
|
|
1916
|
-
name: "Auto Filter",
|
|
1917
|
-
category: "filter",
|
|
1918
|
-
description: "Automated filter sweep with LFO",
|
|
1919
|
-
parameters: [
|
|
1920
|
-
{
|
|
1921
|
-
name: "frequency",
|
|
1922
|
-
label: "Rate",
|
|
1923
|
-
type: "number",
|
|
1924
|
-
min: 0.1,
|
|
1925
|
-
max: 10,
|
|
1926
|
-
step: 0.1,
|
|
1927
|
-
default: 1,
|
|
1928
|
-
unit: "Hz"
|
|
1929
|
-
},
|
|
1930
|
-
{
|
|
1931
|
-
name: "baseFrequency",
|
|
1932
|
-
label: "Base Freq",
|
|
1933
|
-
type: "number",
|
|
1934
|
-
min: 20,
|
|
1935
|
-
max: 2e3,
|
|
1936
|
-
step: 10,
|
|
1937
|
-
default: 200,
|
|
1938
|
-
unit: "Hz"
|
|
1939
|
-
},
|
|
1940
|
-
{
|
|
1941
|
-
name: "octaves",
|
|
1942
|
-
label: "Octaves",
|
|
1943
|
-
type: "number",
|
|
1944
|
-
min: 0.5,
|
|
1945
|
-
max: 8,
|
|
1946
|
-
step: 0.5,
|
|
1947
|
-
default: 2.6
|
|
1948
|
-
},
|
|
1949
|
-
{ name: "depth", label: "Depth", type: "number", min: 0, max: 1, step: 0.01, default: 1 },
|
|
1950
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1951
|
-
]
|
|
1952
|
-
},
|
|
1953
|
-
{
|
|
1954
|
-
id: "autoWah",
|
|
1955
|
-
name: "Auto Wah",
|
|
1956
|
-
category: "filter",
|
|
1957
|
-
description: "Envelope follower filter effect",
|
|
1958
|
-
parameters: [
|
|
1959
|
-
{
|
|
1960
|
-
name: "baseFrequency",
|
|
1961
|
-
label: "Base Freq",
|
|
1962
|
-
type: "number",
|
|
1963
|
-
min: 20,
|
|
1964
|
-
max: 500,
|
|
1965
|
-
step: 10,
|
|
1966
|
-
default: 100,
|
|
1967
|
-
unit: "Hz"
|
|
1968
|
-
},
|
|
1969
|
-
{ name: "octaves", label: "Octaves", type: "number", min: 1, max: 8, step: 1, default: 6 },
|
|
1970
|
-
{
|
|
1971
|
-
name: "sensitivity",
|
|
1972
|
-
label: "Sensitivity",
|
|
1973
|
-
type: "number",
|
|
1974
|
-
min: -40,
|
|
1975
|
-
max: 0,
|
|
1976
|
-
step: 1,
|
|
1977
|
-
default: 0,
|
|
1978
|
-
unit: "dB"
|
|
1979
|
-
},
|
|
1980
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1981
|
-
]
|
|
1982
|
-
},
|
|
1983
|
-
{
|
|
1984
|
-
id: "eq3",
|
|
1985
|
-
name: "3-Band EQ",
|
|
1986
|
-
category: "filter",
|
|
1987
|
-
description: "Three band equalizer with low, mid, and high controls",
|
|
1988
|
-
parameters: [
|
|
1989
|
-
{
|
|
1990
|
-
name: "low",
|
|
1991
|
-
label: "Low",
|
|
1992
|
-
type: "number",
|
|
1993
|
-
min: -24,
|
|
1994
|
-
max: 24,
|
|
1995
|
-
step: 0.5,
|
|
1996
|
-
default: 0,
|
|
1997
|
-
unit: "dB"
|
|
1998
|
-
},
|
|
1999
|
-
{
|
|
2000
|
-
name: "mid",
|
|
2001
|
-
label: "Mid",
|
|
2002
|
-
type: "number",
|
|
2003
|
-
min: -24,
|
|
2004
|
-
max: 24,
|
|
2005
|
-
step: 0.5,
|
|
2006
|
-
default: 0,
|
|
2007
|
-
unit: "dB"
|
|
2008
|
-
},
|
|
2009
|
-
{
|
|
2010
|
-
name: "high",
|
|
2011
|
-
label: "High",
|
|
2012
|
-
type: "number",
|
|
2013
|
-
min: -24,
|
|
2014
|
-
max: 24,
|
|
2015
|
-
step: 0.5,
|
|
2016
|
-
default: 0,
|
|
2017
|
-
unit: "dB"
|
|
2018
|
-
},
|
|
2019
|
-
{
|
|
2020
|
-
name: "lowFrequency",
|
|
2021
|
-
label: "Low Freq",
|
|
2022
|
-
type: "number",
|
|
2023
|
-
min: 20,
|
|
2024
|
-
max: 500,
|
|
2025
|
-
step: 10,
|
|
2026
|
-
default: 400,
|
|
2027
|
-
unit: "Hz"
|
|
2028
|
-
},
|
|
2029
|
-
{
|
|
2030
|
-
name: "highFrequency",
|
|
2031
|
-
label: "High Freq",
|
|
2032
|
-
type: "number",
|
|
2033
|
-
min: 1e3,
|
|
2034
|
-
max: 1e4,
|
|
2035
|
-
step: 100,
|
|
2036
|
-
default: 2500,
|
|
2037
|
-
unit: "Hz"
|
|
2038
|
-
}
|
|
2039
|
-
]
|
|
2040
|
-
},
|
|
2041
|
-
// === DISTORTION EFFECTS ===
|
|
2042
|
-
{
|
|
2043
|
-
id: "distortion",
|
|
2044
|
-
name: "Distortion",
|
|
2045
|
-
category: "distortion",
|
|
2046
|
-
description: "Wave shaping distortion effect",
|
|
2047
|
-
parameters: [
|
|
2048
|
-
{
|
|
2049
|
-
name: "distortion",
|
|
2050
|
-
label: "Drive",
|
|
2051
|
-
type: "number",
|
|
2052
|
-
min: 0,
|
|
2053
|
-
max: 1,
|
|
2054
|
-
step: 0.01,
|
|
2055
|
-
default: 0.4
|
|
2056
|
-
},
|
|
2057
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
2058
|
-
]
|
|
2059
|
-
},
|
|
2060
|
-
{
|
|
2061
|
-
id: "bitCrusher",
|
|
2062
|
-
name: "Bit Crusher",
|
|
2063
|
-
category: "distortion",
|
|
2064
|
-
description: "Reduces bit depth for lo-fi digital texture",
|
|
2065
|
-
parameters: [
|
|
2066
|
-
{ name: "bits", label: "Bits", type: "number", min: 1, max: 16, step: 1, default: 4 },
|
|
2067
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
2068
|
-
]
|
|
2069
|
-
},
|
|
2070
|
-
{
|
|
2071
|
-
id: "chebyshev",
|
|
2072
|
-
name: "Chebyshev",
|
|
2073
|
-
category: "distortion",
|
|
2074
|
-
description: "Waveshaping distortion using Chebyshev polynomials",
|
|
2075
|
-
parameters: [
|
|
2076
|
-
{ name: "order", label: "Order", type: "number", min: 1, max: 100, step: 1, default: 50 },
|
|
2077
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
2078
|
-
]
|
|
2079
|
-
},
|
|
2080
|
-
// === DYNAMICS EFFECTS ===
|
|
2081
|
-
{
|
|
2082
|
-
id: "compressor",
|
|
2083
|
-
name: "Compressor",
|
|
2084
|
-
category: "dynamics",
|
|
2085
|
-
description: "Dynamic range compressor",
|
|
2086
|
-
parameters: [
|
|
2087
|
-
{
|
|
2088
|
-
name: "threshold",
|
|
2089
|
-
label: "Threshold",
|
|
2090
|
-
type: "number",
|
|
2091
|
-
min: -60,
|
|
2092
|
-
max: 0,
|
|
2093
|
-
step: 1,
|
|
2094
|
-
default: -24,
|
|
2095
|
-
unit: "dB"
|
|
2096
|
-
},
|
|
2097
|
-
{ name: "ratio", label: "Ratio", type: "number", min: 1, max: 20, step: 0.5, default: 4 },
|
|
2098
|
-
{
|
|
2099
|
-
name: "attack",
|
|
2100
|
-
label: "Attack",
|
|
2101
|
-
type: "number",
|
|
2102
|
-
min: 0,
|
|
2103
|
-
max: 1,
|
|
2104
|
-
step: 1e-3,
|
|
2105
|
-
default: 3e-3,
|
|
2106
|
-
unit: "s"
|
|
2107
|
-
},
|
|
2108
|
-
{
|
|
2109
|
-
name: "release",
|
|
2110
|
-
label: "Release",
|
|
2111
|
-
type: "number",
|
|
2112
|
-
min: 0,
|
|
2113
|
-
max: 1,
|
|
2114
|
-
step: 0.01,
|
|
2115
|
-
default: 0.25,
|
|
2116
|
-
unit: "s"
|
|
2117
|
-
},
|
|
2118
|
-
{
|
|
2119
|
-
name: "knee",
|
|
2120
|
-
label: "Knee",
|
|
2121
|
-
type: "number",
|
|
2122
|
-
min: 0,
|
|
2123
|
-
max: 40,
|
|
2124
|
-
step: 1,
|
|
2125
|
-
default: 30,
|
|
2126
|
-
unit: "dB"
|
|
2127
|
-
}
|
|
2128
|
-
]
|
|
2129
|
-
},
|
|
2130
|
-
{
|
|
2131
|
-
id: "limiter",
|
|
2132
|
-
name: "Limiter",
|
|
2133
|
-
category: "dynamics",
|
|
2134
|
-
description: "Hard limiter to prevent clipping",
|
|
2135
|
-
parameters: [
|
|
2136
|
-
{
|
|
2137
|
-
name: "threshold",
|
|
2138
|
-
label: "Threshold",
|
|
2139
|
-
type: "number",
|
|
2140
|
-
min: -12,
|
|
2141
|
-
max: 0,
|
|
2142
|
-
step: 0.5,
|
|
2143
|
-
default: -6,
|
|
2144
|
-
unit: "dB"
|
|
2145
|
-
}
|
|
2146
|
-
]
|
|
2147
|
-
},
|
|
2148
|
-
{
|
|
2149
|
-
id: "gate",
|
|
2150
|
-
name: "Gate",
|
|
2151
|
-
category: "dynamics",
|
|
2152
|
-
description: "Noise gate to silence signal below threshold",
|
|
2153
|
-
parameters: [
|
|
2154
|
-
{
|
|
2155
|
-
name: "threshold",
|
|
2156
|
-
label: "Threshold",
|
|
2157
|
-
type: "number",
|
|
2158
|
-
min: -100,
|
|
2159
|
-
max: 0,
|
|
2160
|
-
step: 1,
|
|
2161
|
-
default: -40,
|
|
2162
|
-
unit: "dB"
|
|
2163
|
-
},
|
|
2164
|
-
{
|
|
2165
|
-
name: "attack",
|
|
2166
|
-
label: "Attack",
|
|
2167
|
-
type: "number",
|
|
2168
|
-
min: 0,
|
|
2169
|
-
max: 0.3,
|
|
2170
|
-
step: 1e-3,
|
|
2171
|
-
default: 1e-3,
|
|
2172
|
-
unit: "s"
|
|
2173
|
-
},
|
|
2174
|
-
{
|
|
2175
|
-
name: "release",
|
|
2176
|
-
label: "Release",
|
|
2177
|
-
type: "number",
|
|
2178
|
-
min: 0,
|
|
2179
|
-
max: 0.5,
|
|
2180
|
-
step: 0.01,
|
|
2181
|
-
default: 0.1,
|
|
2182
|
-
unit: "s"
|
|
2183
|
-
}
|
|
2184
|
-
]
|
|
2185
|
-
},
|
|
2186
|
-
// === SPATIAL EFFECTS ===
|
|
2187
|
-
{
|
|
2188
|
-
id: "stereoWidener",
|
|
2189
|
-
name: "Stereo Widener",
|
|
2190
|
-
category: "spatial",
|
|
2191
|
-
description: "Expands or narrows the stereo image",
|
|
2192
|
-
parameters: [
|
|
2193
|
-
{ name: "width", label: "Width", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
2194
|
-
]
|
|
2195
|
-
}
|
|
2196
|
-
];
|
|
2197
|
-
var getEffectDefinition = (id) => {
|
|
2198
|
-
return effectDefinitions.find((def) => def.id === id);
|
|
2199
|
-
};
|
|
2200
|
-
var getEffectsByCategory = (category) => {
|
|
2201
|
-
return effectDefinitions.filter((def) => def.category === category);
|
|
2202
|
-
};
|
|
2203
|
-
var effectCategories = [
|
|
2204
|
-
{ id: "reverb", name: "Reverb" },
|
|
2205
|
-
{ id: "delay", name: "Delay" },
|
|
2206
|
-
{ id: "modulation", name: "Modulation" },
|
|
2207
|
-
{ id: "filter", name: "Filter" },
|
|
2208
|
-
{ id: "distortion", name: "Distortion" },
|
|
2209
|
-
{ id: "dynamics", name: "Dynamics" },
|
|
2210
|
-
{ id: "spatial", name: "Spatial" }
|
|
2211
|
-
];
|
|
2212
|
-
|
|
2213
|
-
// src/effects/effectFactory.ts
|
|
2214
|
-
var import_tone2 = require("tone");
|
|
2215
|
-
function asEffectConstructor(ctor) {
|
|
2216
|
-
return ctor;
|
|
2217
|
-
}
|
|
2218
|
-
var effectConstructors = {
|
|
2219
|
-
reverb: asEffectConstructor(import_tone2.Reverb),
|
|
2220
|
-
freeverb: asEffectConstructor(import_tone2.Freeverb),
|
|
2221
|
-
jcReverb: asEffectConstructor(import_tone2.JCReverb),
|
|
2222
|
-
feedbackDelay: asEffectConstructor(import_tone2.FeedbackDelay),
|
|
2223
|
-
pingPongDelay: asEffectConstructor(import_tone2.PingPongDelay),
|
|
2224
|
-
chorus: asEffectConstructor(import_tone2.Chorus),
|
|
2225
|
-
phaser: asEffectConstructor(import_tone2.Phaser),
|
|
2226
|
-
tremolo: asEffectConstructor(import_tone2.Tremolo),
|
|
2227
|
-
vibrato: asEffectConstructor(import_tone2.Vibrato),
|
|
2228
|
-
autoPanner: asEffectConstructor(import_tone2.AutoPanner),
|
|
2229
|
-
autoFilter: asEffectConstructor(import_tone2.AutoFilter),
|
|
2230
|
-
autoWah: asEffectConstructor(import_tone2.AutoWah),
|
|
2231
|
-
eq3: asEffectConstructor(import_tone2.EQ3),
|
|
2232
|
-
distortion: asEffectConstructor(import_tone2.Distortion),
|
|
2233
|
-
bitCrusher: asEffectConstructor(import_tone2.BitCrusher),
|
|
2234
|
-
chebyshev: asEffectConstructor(import_tone2.Chebyshev),
|
|
2235
|
-
compressor: asEffectConstructor(import_tone2.Compressor),
|
|
2236
|
-
limiter: asEffectConstructor(import_tone2.Limiter),
|
|
2237
|
-
gate: asEffectConstructor(import_tone2.Gate),
|
|
2238
|
-
stereoWidener: asEffectConstructor(import_tone2.StereoWidener)
|
|
2239
|
-
};
|
|
2240
|
-
var instanceCounter = 0;
|
|
2241
|
-
var generateInstanceId = () => {
|
|
2242
|
-
return `effect_${Date.now()}_${++instanceCounter}`;
|
|
2243
|
-
};
|
|
2244
|
-
function createEffectInstance(definition, initialParams) {
|
|
2245
|
-
const Constructor = effectConstructors[definition.id];
|
|
2246
|
-
if (!Constructor) {
|
|
2247
|
-
throw new Error(`Unknown effect type: ${definition.id}`);
|
|
2248
|
-
}
|
|
2249
|
-
const options = {};
|
|
2250
|
-
definition.parameters.forEach((param) => {
|
|
2251
|
-
var _a;
|
|
2252
|
-
const value = (_a = initialParams == null ? void 0 : initialParams[param.name]) != null ? _a : param.default;
|
|
2253
|
-
options[param.name] = value;
|
|
2254
|
-
});
|
|
2255
|
-
const effect = new Constructor(options);
|
|
2256
|
-
const instanceId = generateInstanceId();
|
|
2257
|
-
const effectRecord = effect;
|
|
2258
|
-
return {
|
|
2259
|
-
effect,
|
|
2260
|
-
id: definition.id,
|
|
2261
|
-
instanceId,
|
|
2262
|
-
dispose() {
|
|
2263
|
-
try {
|
|
2264
|
-
effect.disconnect();
|
|
2265
|
-
effect.dispose();
|
|
2266
|
-
} catch (e) {
|
|
2267
|
-
console.warn(
|
|
2268
|
-
`[waveform-playlist] Error disposing effect "${definition.id}" (${instanceId}):`,
|
|
2269
|
-
e
|
|
2270
|
-
);
|
|
2271
|
-
}
|
|
2272
|
-
},
|
|
2273
|
-
setParameter(name, value) {
|
|
2274
|
-
const prop = effectRecord[name];
|
|
2275
|
-
if (name === "wet") {
|
|
2276
|
-
const wetProp = effectRecord["wet"];
|
|
2277
|
-
if (wetProp && typeof wetProp === "object" && "value" in wetProp) {
|
|
2278
|
-
wetProp.value = value;
|
|
2279
|
-
return;
|
|
2280
|
-
}
|
|
2281
|
-
}
|
|
2282
|
-
if (prop !== void 0) {
|
|
2283
|
-
if (prop && typeof prop === "object" && "value" in prop) {
|
|
2284
|
-
prop.value = value;
|
|
2285
|
-
} else {
|
|
2286
|
-
effectRecord[name] = value;
|
|
2287
|
-
}
|
|
2288
|
-
}
|
|
2289
|
-
},
|
|
2290
|
-
getParameter(name) {
|
|
2291
|
-
if (name === "wet") {
|
|
2292
|
-
const wetProp = effectRecord["wet"];
|
|
2293
|
-
if (wetProp && typeof wetProp === "object" && "value" in wetProp) {
|
|
2294
|
-
return wetProp.value;
|
|
2295
|
-
}
|
|
2296
|
-
}
|
|
2297
|
-
const prop = effectRecord[name];
|
|
2298
|
-
if (prop !== void 0) {
|
|
2299
|
-
if (prop && typeof prop === "object" && "value" in prop) {
|
|
2300
|
-
return prop.value;
|
|
2301
|
-
}
|
|
2302
|
-
return prop;
|
|
2303
|
-
}
|
|
2304
|
-
return void 0;
|
|
2305
|
-
},
|
|
2306
|
-
connect(destination) {
|
|
2307
|
-
effect.connect(destination);
|
|
2308
|
-
},
|
|
2309
|
-
disconnect() {
|
|
2310
|
-
try {
|
|
2311
|
-
effect.disconnect();
|
|
2312
|
-
} catch (e) {
|
|
2313
|
-
console.warn(
|
|
2314
|
-
`[waveform-playlist] Error disconnecting effect "${definition.id}" (${instanceId}):`,
|
|
2315
|
-
e
|
|
2316
|
-
);
|
|
2317
|
-
}
|
|
2318
|
-
}
|
|
2319
|
-
};
|
|
2320
|
-
}
|
|
2321
|
-
function createEffectChain(effects) {
|
|
2322
|
-
if (effects.length === 0) {
|
|
2323
|
-
throw new Error("Cannot create effect chain with no effects");
|
|
2324
|
-
}
|
|
2325
|
-
for (let i = 0; i < effects.length - 1; i++) {
|
|
2326
|
-
effects[i].effect.connect(effects[i + 1].effect);
|
|
2327
|
-
}
|
|
2328
|
-
return {
|
|
2329
|
-
input: effects[0].effect,
|
|
2330
|
-
output: effects[effects.length - 1].effect,
|
|
2331
|
-
dispose() {
|
|
2332
|
-
effects.forEach((e) => e.dispose());
|
|
2333
|
-
}
|
|
2334
|
-
};
|
|
2335
|
-
}
|
|
2336
|
-
|
|
2337
|
-
// src/hooks/useDynamicEffects.ts
|
|
2338
|
-
var import_tone3 = require("tone");
|
|
2339
|
-
function useDynamicEffects(fftSize = 256) {
|
|
2340
|
-
const [activeEffects, setActiveEffects] = (0, import_react17.useState)([]);
|
|
2341
|
-
const activeEffectsRef = (0, import_react17.useRef)(activeEffects);
|
|
2342
|
-
activeEffectsRef.current = activeEffects;
|
|
2343
|
-
const effectInstancesRef = (0, import_react17.useRef)(/* @__PURE__ */ new Map());
|
|
2344
|
-
const analyserRef = (0, import_react17.useRef)(null);
|
|
2345
|
-
const graphNodesRef = (0, import_react17.useRef)(null);
|
|
2346
|
-
const rebuildChain = (0, import_react17.useCallback)((effects) => {
|
|
2347
|
-
const nodes = graphNodesRef.current;
|
|
2348
|
-
if (!nodes) return;
|
|
2349
|
-
const { masterGainNode, destination, analyserNode } = nodes;
|
|
2350
|
-
try {
|
|
2351
|
-
masterGainNode.disconnect();
|
|
2352
|
-
} catch (e) {
|
|
2353
|
-
console.warn("[waveform-playlist] Error disconnecting master effects chain:", e);
|
|
2354
|
-
}
|
|
2355
|
-
const instances = effects.map((ae) => effectInstancesRef.current.get(ae.instanceId)).filter((inst) => inst !== void 0);
|
|
2356
|
-
if (instances.length === 0) {
|
|
2357
|
-
masterGainNode.connect(analyserNode);
|
|
2358
|
-
analyserNode.connect(destination);
|
|
2359
|
-
} else {
|
|
2360
|
-
let currentNode = masterGainNode;
|
|
2361
|
-
instances.forEach((inst) => {
|
|
2362
|
-
try {
|
|
2363
|
-
inst.disconnect();
|
|
2364
|
-
} catch (e) {
|
|
2365
|
-
console.warn(`[waveform-playlist] Error disconnecting effect "${inst.id}":`, e);
|
|
2366
|
-
}
|
|
2367
|
-
currentNode.connect(inst.effect);
|
|
2368
|
-
currentNode = inst.effect;
|
|
2369
|
-
});
|
|
2370
|
-
currentNode.connect(analyserNode);
|
|
2371
|
-
analyserNode.connect(destination);
|
|
2372
|
-
}
|
|
2373
|
-
}, []);
|
|
2374
|
-
const addEffect = (0, import_react17.useCallback)((effectId) => {
|
|
2375
|
-
const definition = getEffectDefinition(effectId);
|
|
2376
|
-
if (!definition) {
|
|
2377
|
-
console.error(`Unknown effect: ${effectId}`);
|
|
2378
|
-
return;
|
|
2379
|
-
}
|
|
2380
|
-
const params = {};
|
|
2381
|
-
definition.parameters.forEach((p) => {
|
|
2382
|
-
params[p.name] = p.default;
|
|
2383
|
-
});
|
|
2384
|
-
const instance = createEffectInstance(definition, params);
|
|
2385
|
-
effectInstancesRef.current.set(instance.instanceId, instance);
|
|
2386
|
-
const newActiveEffect = {
|
|
2387
|
-
instanceId: instance.instanceId,
|
|
2388
|
-
effectId: definition.id,
|
|
2389
|
-
definition,
|
|
2390
|
-
params,
|
|
2391
|
-
bypassed: false
|
|
2392
|
-
};
|
|
2393
|
-
setActiveEffects((prev) => [...prev, newActiveEffect]);
|
|
2394
|
-
}, []);
|
|
2395
|
-
const removeEffect = (0, import_react17.useCallback)((instanceId) => {
|
|
2396
|
-
const instance = effectInstancesRef.current.get(instanceId);
|
|
2397
|
-
if (instance) {
|
|
2398
|
-
instance.dispose();
|
|
2399
|
-
effectInstancesRef.current.delete(instanceId);
|
|
2400
|
-
}
|
|
2401
|
-
setActiveEffects((prev) => prev.filter((e) => e.instanceId !== instanceId));
|
|
2402
|
-
}, []);
|
|
2403
|
-
const updateParameter = (0, import_react17.useCallback)(
|
|
2404
|
-
(instanceId, paramName, value) => {
|
|
2405
|
-
const instance = effectInstancesRef.current.get(instanceId);
|
|
2406
|
-
if (instance) {
|
|
2407
|
-
instance.setParameter(paramName, value);
|
|
2408
|
-
}
|
|
2409
|
-
setActiveEffects(
|
|
2410
|
-
(prev) => prev.map(
|
|
2411
|
-
(e) => e.instanceId === instanceId ? __spreadProps(__spreadValues({}, e), { params: __spreadProps(__spreadValues({}, e.params), { [paramName]: value }) }) : e
|
|
2412
|
-
)
|
|
2413
|
-
);
|
|
2414
|
-
},
|
|
2415
|
-
[]
|
|
2416
|
-
);
|
|
2417
|
-
const toggleBypass = (0, import_react17.useCallback)((instanceId) => {
|
|
2418
|
-
var _a;
|
|
2419
|
-
const effect = activeEffectsRef.current.find((e) => e.instanceId === instanceId);
|
|
2420
|
-
if (!effect) return;
|
|
2421
|
-
const newBypassed = !effect.bypassed;
|
|
2422
|
-
const instance = effectInstancesRef.current.get(instanceId);
|
|
2423
|
-
if (instance) {
|
|
2424
|
-
const originalWet = (_a = effect.params.wet) != null ? _a : 1;
|
|
2425
|
-
instance.setParameter("wet", newBypassed ? 0 : originalWet);
|
|
2426
|
-
}
|
|
2427
|
-
setActiveEffects(
|
|
2428
|
-
(prev) => prev.map((e) => e.instanceId === instanceId ? __spreadProps(__spreadValues({}, e), { bypassed: newBypassed }) : e)
|
|
2429
|
-
);
|
|
2430
|
-
}, []);
|
|
2431
|
-
const reorderEffects = (0, import_react17.useCallback)((fromIndex, toIndex) => {
|
|
2432
|
-
setActiveEffects((prev) => {
|
|
2433
|
-
const newEffects = [...prev];
|
|
2434
|
-
const [removed] = newEffects.splice(fromIndex, 1);
|
|
2435
|
-
newEffects.splice(toIndex, 0, removed);
|
|
2436
|
-
return newEffects;
|
|
2437
|
-
});
|
|
2438
|
-
}, []);
|
|
2439
|
-
const clearAllEffects = (0, import_react17.useCallback)(() => {
|
|
2440
|
-
effectInstancesRef.current.forEach((inst) => inst.dispose());
|
|
2441
|
-
effectInstancesRef.current.clear();
|
|
2442
|
-
setActiveEffects([]);
|
|
2443
|
-
}, []);
|
|
2444
|
-
(0, import_react17.useEffect)(() => {
|
|
2445
|
-
rebuildChain(activeEffects);
|
|
2446
|
-
}, [activeEffects, rebuildChain]);
|
|
2447
|
-
const masterEffects = (0, import_react17.useCallback)(
|
|
2448
|
-
(masterGainNode, destination, _isOffline) => {
|
|
2449
|
-
const analyserNode = new import_tone3.Analyser("fft", fftSize);
|
|
2450
|
-
analyserRef.current = analyserNode;
|
|
2451
|
-
graphNodesRef.current = {
|
|
2452
|
-
masterGainNode,
|
|
2453
|
-
destination,
|
|
2454
|
-
analyserNode
|
|
2455
|
-
};
|
|
2456
|
-
const effects = activeEffectsRef.current;
|
|
2457
|
-
const instances = effects.map((ae) => effectInstancesRef.current.get(ae.instanceId)).filter((inst) => inst !== void 0);
|
|
2458
|
-
if (instances.length === 0) {
|
|
2459
|
-
masterGainNode.connect(analyserNode);
|
|
2460
|
-
analyserNode.connect(destination);
|
|
2461
|
-
} else {
|
|
2462
|
-
let currentNode = masterGainNode;
|
|
2463
|
-
instances.forEach((inst) => {
|
|
2464
|
-
currentNode.connect(inst.effect);
|
|
2465
|
-
currentNode = inst.effect;
|
|
2466
|
-
});
|
|
2467
|
-
currentNode.connect(analyserNode);
|
|
2468
|
-
analyserNode.connect(destination);
|
|
2469
|
-
}
|
|
2470
|
-
return function cleanup() {
|
|
2471
|
-
analyserNode.dispose();
|
|
2472
|
-
analyserRef.current = null;
|
|
2473
|
-
graphNodesRef.current = null;
|
|
2474
|
-
};
|
|
2475
|
-
},
|
|
2476
|
-
[fftSize]
|
|
2477
|
-
// Only fftSize - reads effects from ref
|
|
2478
|
-
);
|
|
2479
|
-
(0, import_react17.useEffect)(() => {
|
|
2480
|
-
const effectInstances = effectInstancesRef.current;
|
|
2481
|
-
return () => {
|
|
2482
|
-
effectInstances.forEach((inst) => inst.dispose());
|
|
2483
|
-
effectInstances.clear();
|
|
2484
|
-
};
|
|
2485
|
-
}, []);
|
|
2486
|
-
const createOfflineEffectsFunction = (0, import_react17.useCallback)(() => {
|
|
2487
|
-
const nonBypassedEffects = activeEffects.filter((e) => !e.bypassed);
|
|
2488
|
-
if (nonBypassedEffects.length === 0) {
|
|
2489
|
-
return void 0;
|
|
2490
|
-
}
|
|
2491
|
-
return (masterGainNode, destination, _isOffline) => {
|
|
2492
|
-
const offlineInstances = [];
|
|
2493
|
-
for (const activeEffect of nonBypassedEffects) {
|
|
2494
|
-
const instance = createEffectInstance(activeEffect.definition, activeEffect.params);
|
|
2495
|
-
offlineInstances.push(instance);
|
|
2496
|
-
}
|
|
2497
|
-
if (offlineInstances.length === 0) {
|
|
2498
|
-
masterGainNode.connect(destination);
|
|
2499
|
-
} else {
|
|
2500
|
-
let currentNode = masterGainNode;
|
|
2501
|
-
offlineInstances.forEach((inst) => {
|
|
2502
|
-
currentNode.connect(inst.effect);
|
|
2503
|
-
currentNode = inst.effect;
|
|
2504
|
-
});
|
|
2505
|
-
currentNode.connect(destination);
|
|
2506
|
-
}
|
|
2507
|
-
return function cleanup() {
|
|
2508
|
-
offlineInstances.forEach((inst) => inst.dispose());
|
|
2509
|
-
};
|
|
2510
|
-
};
|
|
2511
|
-
}, [activeEffects]);
|
|
2512
|
-
return {
|
|
2513
|
-
activeEffects,
|
|
2514
|
-
availableEffects: effectDefinitions,
|
|
2515
|
-
addEffect,
|
|
2516
|
-
removeEffect,
|
|
2517
|
-
updateParameter,
|
|
2518
|
-
toggleBypass,
|
|
2519
|
-
reorderEffects,
|
|
2520
|
-
clearAllEffects,
|
|
2521
|
-
masterEffects,
|
|
2522
|
-
createOfflineEffectsFunction,
|
|
2523
|
-
analyserRef
|
|
2524
|
-
};
|
|
2525
|
-
}
|
|
2526
|
-
|
|
2527
|
-
// src/hooks/useTrackDynamicEffects.ts
|
|
2528
|
-
var import_react18 = require("react");
|
|
2529
|
-
function useTrackDynamicEffects() {
|
|
2530
|
-
const [trackEffectsState, setTrackEffectsState] = (0, import_react18.useState)(
|
|
2531
|
-
/* @__PURE__ */ new Map()
|
|
2532
|
-
);
|
|
2533
|
-
const trackEffectInstancesRef = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
|
|
2534
|
-
const trackGraphNodesRef = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
|
|
2535
|
-
const rebuildTrackChain = (0, import_react18.useCallback)((trackId, trackEffects) => {
|
|
2536
|
-
const nodes = trackGraphNodesRef.current.get(trackId);
|
|
2537
|
-
if (!nodes) return;
|
|
2538
|
-
const { graphEnd, masterGainNode } = nodes;
|
|
2539
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2540
|
-
try {
|
|
2541
|
-
graphEnd.disconnect();
|
|
2542
|
-
} catch (e) {
|
|
2543
|
-
console.warn(`[waveform-playlist] Error disconnecting track "${trackId}" effect chain:`, e);
|
|
2544
|
-
}
|
|
2545
|
-
const instances = trackEffects.map((ae) => instancesMap == null ? void 0 : instancesMap.get(ae.instanceId)).filter((inst) => inst !== void 0);
|
|
2546
|
-
if (instances.length === 0) {
|
|
2547
|
-
graphEnd.connect(masterGainNode);
|
|
2548
|
-
} else {
|
|
2549
|
-
let currentNode = graphEnd;
|
|
2550
|
-
instances.forEach((inst) => {
|
|
2551
|
-
try {
|
|
2552
|
-
inst.disconnect();
|
|
2553
|
-
} catch (e) {
|
|
2554
|
-
console.warn(
|
|
2555
|
-
`[waveform-playlist] Error disconnecting effect "${inst.id}" on track "${trackId}":`,
|
|
2556
|
-
e
|
|
2557
|
-
);
|
|
2558
|
-
}
|
|
2559
|
-
currentNode.connect(inst.effect);
|
|
2560
|
-
currentNode = inst.effect;
|
|
2561
|
-
});
|
|
2562
|
-
currentNode.connect(masterGainNode);
|
|
2563
|
-
}
|
|
2564
|
-
}, []);
|
|
2565
|
-
const addEffectToTrack = (0, import_react18.useCallback)((trackId, effectId) => {
|
|
2566
|
-
const definition = getEffectDefinition(effectId);
|
|
2567
|
-
if (!definition) {
|
|
2568
|
-
console.error(`Unknown effect: ${effectId}`);
|
|
2569
|
-
return;
|
|
2570
|
-
}
|
|
2571
|
-
const params = {};
|
|
2572
|
-
definition.parameters.forEach((p) => {
|
|
2573
|
-
params[p.name] = p.default;
|
|
2574
|
-
});
|
|
2575
|
-
const instance = createEffectInstance(definition, params);
|
|
2576
|
-
if (!trackEffectInstancesRef.current.has(trackId)) {
|
|
2577
|
-
trackEffectInstancesRef.current.set(trackId, /* @__PURE__ */ new Map());
|
|
2578
|
-
}
|
|
2579
|
-
trackEffectInstancesRef.current.get(trackId).set(instance.instanceId, instance);
|
|
2580
|
-
const newActiveEffect = {
|
|
2581
|
-
instanceId: instance.instanceId,
|
|
2582
|
-
effectId: definition.id,
|
|
2583
|
-
definition,
|
|
2584
|
-
params,
|
|
2585
|
-
bypassed: false
|
|
2586
|
-
};
|
|
2587
|
-
setTrackEffectsState((prev) => {
|
|
2588
|
-
const newState = new Map(prev);
|
|
2589
|
-
const existing = newState.get(trackId) || [];
|
|
2590
|
-
newState.set(trackId, [...existing, newActiveEffect]);
|
|
2591
|
-
return newState;
|
|
2592
|
-
});
|
|
2593
|
-
}, []);
|
|
2594
|
-
const removeEffectFromTrack = (0, import_react18.useCallback)((trackId, instanceId) => {
|
|
2595
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2596
|
-
const instance = instancesMap == null ? void 0 : instancesMap.get(instanceId);
|
|
2597
|
-
if (instance) {
|
|
2598
|
-
instance.dispose();
|
|
2599
|
-
instancesMap == null ? void 0 : instancesMap.delete(instanceId);
|
|
2600
|
-
}
|
|
2601
|
-
setTrackEffectsState((prev) => {
|
|
2602
|
-
const newState = new Map(prev);
|
|
2603
|
-
const existing = newState.get(trackId) || [];
|
|
2604
|
-
newState.set(
|
|
2605
|
-
trackId,
|
|
2606
|
-
existing.filter((e) => e.instanceId !== instanceId)
|
|
2607
|
-
);
|
|
2608
|
-
return newState;
|
|
2609
|
-
});
|
|
2610
|
-
}, []);
|
|
2611
|
-
const updateTrackEffectParameter = (0, import_react18.useCallback)(
|
|
2612
|
-
(trackId, instanceId, paramName, value) => {
|
|
2613
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2614
|
-
const instance = instancesMap == null ? void 0 : instancesMap.get(instanceId);
|
|
2615
|
-
if (instance) {
|
|
2616
|
-
instance.setParameter(paramName, value);
|
|
2617
|
-
}
|
|
2618
|
-
setTrackEffectsState((prev) => {
|
|
2619
|
-
const newState = new Map(prev);
|
|
2620
|
-
const existing = newState.get(trackId) || [];
|
|
2621
|
-
newState.set(
|
|
2622
|
-
trackId,
|
|
2623
|
-
existing.map(
|
|
2624
|
-
(e) => e.instanceId === instanceId ? __spreadProps(__spreadValues({}, e), { params: __spreadProps(__spreadValues({}, e.params), { [paramName]: value }) }) : e
|
|
2625
|
-
)
|
|
2626
|
-
);
|
|
2627
|
-
return newState;
|
|
2628
|
-
});
|
|
2629
|
-
},
|
|
2630
|
-
[]
|
|
2631
|
-
);
|
|
2632
|
-
const toggleBypass = (0, import_react18.useCallback)((trackId, instanceId) => {
|
|
2633
|
-
var _a;
|
|
2634
|
-
const trackEffects = trackEffectsStateRef.current.get(trackId) || [];
|
|
2635
|
-
const effect = trackEffects.find((e) => e.instanceId === instanceId);
|
|
2636
|
-
if (!effect) return;
|
|
2637
|
-
const newBypassed = !effect.bypassed;
|
|
2638
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2639
|
-
const instance = instancesMap == null ? void 0 : instancesMap.get(instanceId);
|
|
2640
|
-
if (instance) {
|
|
2641
|
-
const originalWet = (_a = effect.params.wet) != null ? _a : 1;
|
|
2642
|
-
instance.setParameter("wet", newBypassed ? 0 : originalWet);
|
|
2643
|
-
}
|
|
2644
|
-
setTrackEffectsState((prev) => {
|
|
2645
|
-
const newState = new Map(prev);
|
|
2646
|
-
const existing = newState.get(trackId) || [];
|
|
2647
|
-
newState.set(
|
|
2648
|
-
trackId,
|
|
2649
|
-
existing.map((e) => e.instanceId === instanceId ? __spreadProps(__spreadValues({}, e), { bypassed: newBypassed }) : e)
|
|
2650
|
-
);
|
|
2651
|
-
return newState;
|
|
2652
|
-
});
|
|
2653
|
-
}, []);
|
|
2654
|
-
const clearTrackEffects = (0, import_react18.useCallback)((trackId) => {
|
|
2655
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2656
|
-
if (instancesMap) {
|
|
2657
|
-
instancesMap.forEach((inst) => inst.dispose());
|
|
2658
|
-
instancesMap.clear();
|
|
2659
|
-
}
|
|
2660
|
-
setTrackEffectsState((prev) => {
|
|
2661
|
-
const newState = new Map(prev);
|
|
2662
|
-
newState.set(trackId, []);
|
|
2663
|
-
return newState;
|
|
2664
|
-
});
|
|
2665
|
-
}, []);
|
|
2666
|
-
const trackEffectsStateRef = (0, import_react18.useRef)(trackEffectsState);
|
|
2667
|
-
trackEffectsStateRef.current = trackEffectsState;
|
|
2668
|
-
const getTrackEffectsFunction = (0, import_react18.useCallback)(
|
|
2669
|
-
(trackId) => {
|
|
2670
|
-
return (graphEnd, masterGainNode, _isOffline) => {
|
|
2671
|
-
trackGraphNodesRef.current.set(trackId, {
|
|
2672
|
-
graphEnd,
|
|
2673
|
-
masterGainNode
|
|
2674
|
-
});
|
|
2675
|
-
const trackEffects = trackEffectsStateRef.current.get(trackId) || [];
|
|
2676
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2677
|
-
const instances = trackEffects.map((ae) => instancesMap == null ? void 0 : instancesMap.get(ae.instanceId)).filter((inst) => inst !== void 0);
|
|
2678
|
-
if (instances.length === 0) {
|
|
2679
|
-
graphEnd.connect(masterGainNode);
|
|
2680
|
-
} else {
|
|
2681
|
-
let currentNode = graphEnd;
|
|
2682
|
-
instances.forEach((inst) => {
|
|
2683
|
-
currentNode.connect(inst.effect);
|
|
2684
|
-
currentNode = inst.effect;
|
|
2685
|
-
});
|
|
2686
|
-
currentNode.connect(masterGainNode);
|
|
2687
|
-
}
|
|
2688
|
-
return function cleanup() {
|
|
2689
|
-
trackGraphNodesRef.current.delete(trackId);
|
|
2690
|
-
};
|
|
2691
|
-
};
|
|
2692
|
-
},
|
|
2693
|
-
[]
|
|
2694
|
-
// No dependencies - stable function that reads from refs
|
|
2695
|
-
);
|
|
2696
|
-
(0, import_react18.useEffect)(() => {
|
|
2697
|
-
trackEffectsState.forEach((effects, trackId) => {
|
|
2698
|
-
rebuildTrackChain(trackId, effects);
|
|
2699
|
-
});
|
|
2700
|
-
}, [trackEffectsState, rebuildTrackChain]);
|
|
2701
|
-
(0, import_react18.useEffect)(() => {
|
|
2702
|
-
const trackEffectInstances = trackEffectInstancesRef.current;
|
|
2703
|
-
return () => {
|
|
2704
|
-
trackEffectInstances.forEach((instancesMap) => {
|
|
2705
|
-
instancesMap.forEach((inst) => inst.dispose());
|
|
2706
|
-
instancesMap.clear();
|
|
2707
|
-
});
|
|
2708
|
-
trackEffectInstances.clear();
|
|
2709
|
-
};
|
|
2710
|
-
}, []);
|
|
2711
|
-
const createOfflineTrackEffectsFunction = (0, import_react18.useCallback)(
|
|
2712
|
-
(trackId) => {
|
|
2713
|
-
const trackEffects = trackEffectsState.get(trackId) || [];
|
|
2714
|
-
const nonBypassedEffects = trackEffects.filter((e) => !e.bypassed);
|
|
2715
|
-
if (nonBypassedEffects.length === 0) {
|
|
2716
|
-
return void 0;
|
|
2717
|
-
}
|
|
2718
|
-
return (graphEnd, masterGainNode, _isOffline) => {
|
|
2719
|
-
const offlineInstances = [];
|
|
2720
|
-
for (const activeEffect of nonBypassedEffects) {
|
|
2721
|
-
const instance = createEffectInstance(activeEffect.definition, activeEffect.params);
|
|
2722
|
-
offlineInstances.push(instance);
|
|
2723
|
-
}
|
|
2724
|
-
if (offlineInstances.length === 0) {
|
|
2725
|
-
graphEnd.connect(masterGainNode);
|
|
2726
|
-
} else {
|
|
2727
|
-
let currentNode = graphEnd;
|
|
2728
|
-
offlineInstances.forEach((inst) => {
|
|
2729
|
-
currentNode.connect(inst.effect);
|
|
2730
|
-
currentNode = inst.effect;
|
|
2731
|
-
});
|
|
2732
|
-
currentNode.connect(masterGainNode);
|
|
2733
|
-
}
|
|
2734
|
-
return function cleanup() {
|
|
2735
|
-
offlineInstances.forEach((inst) => inst.dispose());
|
|
2736
|
-
};
|
|
2737
|
-
};
|
|
2738
|
-
},
|
|
2739
|
-
[trackEffectsState]
|
|
2740
|
-
);
|
|
2741
|
-
return {
|
|
2742
|
-
trackEffectsState,
|
|
2743
|
-
addEffectToTrack,
|
|
2744
|
-
removeEffectFromTrack,
|
|
2745
|
-
updateTrackEffectParameter,
|
|
2746
|
-
toggleBypass,
|
|
2747
|
-
clearTrackEffects,
|
|
2748
|
-
getTrackEffectsFunction,
|
|
2749
|
-
createOfflineTrackEffectsFunction,
|
|
2750
|
-
availableEffects: effectDefinitions
|
|
2751
|
-
};
|
|
2752
|
-
}
|
|
2753
|
-
|
|
2754
|
-
// src/hooks/useExportWav.ts
|
|
2755
|
-
var import_react19 = require("react");
|
|
2756
|
-
var import_core4 = require("@waveform-playlist/core");
|
|
2757
|
-
var import_playout3 = require("@waveform-playlist/playout");
|
|
2758
|
-
|
|
2759
|
-
// src/utils/wavEncoder.ts
|
|
2760
|
-
function encodeWav(audioBuffer, options = {}) {
|
|
2761
|
-
const { bitDepth = 16 } = options;
|
|
2762
|
-
const numChannels = audioBuffer.numberOfChannels;
|
|
2763
|
-
const sampleRate = audioBuffer.sampleRate;
|
|
2764
|
-
const numSamples = audioBuffer.length;
|
|
2765
|
-
const bytesPerSample = bitDepth / 8;
|
|
2766
|
-
const blockAlign = numChannels * bytesPerSample;
|
|
2767
|
-
const byteRate = sampleRate * blockAlign;
|
|
2768
|
-
const dataSize = numSamples * blockAlign;
|
|
2769
|
-
const headerSize = 44;
|
|
2770
|
-
const totalSize = headerSize + dataSize;
|
|
2771
|
-
const buffer = new ArrayBuffer(totalSize);
|
|
2772
|
-
const view = new DataView(buffer);
|
|
2773
|
-
writeString(view, 0, "RIFF");
|
|
2774
|
-
view.setUint32(4, totalSize - 8, true);
|
|
2775
|
-
writeString(view, 8, "WAVE");
|
|
2776
|
-
writeString(view, 12, "fmt ");
|
|
2777
|
-
view.setUint32(16, 16, true);
|
|
2778
|
-
view.setUint16(20, bitDepth === 32 ? 3 : 1, true);
|
|
2779
|
-
view.setUint16(22, numChannels, true);
|
|
2780
|
-
view.setUint32(24, sampleRate, true);
|
|
2781
|
-
view.setUint32(28, byteRate, true);
|
|
2782
|
-
view.setUint16(32, blockAlign, true);
|
|
2783
|
-
view.setUint16(34, bitDepth, true);
|
|
2784
|
-
writeString(view, 36, "data");
|
|
2785
|
-
view.setUint32(40, dataSize, true);
|
|
2786
|
-
const channelData = [];
|
|
2787
|
-
for (let ch = 0; ch < numChannels; ch++) {
|
|
2788
|
-
channelData.push(audioBuffer.getChannelData(ch));
|
|
2789
|
-
}
|
|
2790
|
-
let offset = headerSize;
|
|
2791
|
-
if (bitDepth === 16) {
|
|
2792
|
-
for (let i = 0; i < numSamples; i++) {
|
|
2793
|
-
for (let ch = 0; ch < numChannels; ch++) {
|
|
2794
|
-
const sample = channelData[ch][i];
|
|
2795
|
-
const clampedSample = Math.max(-1, Math.min(1, sample));
|
|
2796
|
-
const intSample = clampedSample < 0 ? clampedSample * 32768 : clampedSample * 32767;
|
|
2797
|
-
view.setInt16(offset, intSample, true);
|
|
2798
|
-
offset += 2;
|
|
2799
|
-
}
|
|
2800
|
-
}
|
|
2801
|
-
} else {
|
|
2802
|
-
for (let i = 0; i < numSamples; i++) {
|
|
2803
|
-
for (let ch = 0; ch < numChannels; ch++) {
|
|
2804
|
-
view.setFloat32(offset, channelData[ch][i], true);
|
|
2805
|
-
offset += 4;
|
|
2806
|
-
}
|
|
2807
|
-
}
|
|
2808
|
-
}
|
|
2809
|
-
return new Blob([buffer], { type: "audio/wav" });
|
|
2810
|
-
}
|
|
2811
|
-
function writeString(view, offset, str) {
|
|
2812
|
-
for (let i = 0; i < str.length; i++) {
|
|
2813
|
-
view.setUint8(offset + i, str.charCodeAt(i));
|
|
2814
|
-
}
|
|
2815
|
-
}
|
|
2816
|
-
function downloadBlob(blob, filename) {
|
|
2817
|
-
const url = URL.createObjectURL(blob);
|
|
2818
|
-
const a = document.createElement("a");
|
|
2819
|
-
a.href = url;
|
|
2820
|
-
a.download = filename;
|
|
2821
|
-
a.style.display = "none";
|
|
2822
|
-
document.body.appendChild(a);
|
|
2823
|
-
a.click();
|
|
2824
|
-
document.body.removeChild(a);
|
|
2825
|
-
URL.revokeObjectURL(url);
|
|
2826
|
-
}
|
|
2827
|
-
|
|
2828
|
-
// src/hooks/useExportWav.ts
|
|
2829
|
-
function useExportWav() {
|
|
2830
|
-
const [isExporting, setIsExporting] = (0, import_react19.useState)(false);
|
|
2831
|
-
const [progress, setProgress] = (0, import_react19.useState)(0);
|
|
2832
|
-
const [error, setError] = (0, import_react19.useState)(null);
|
|
2833
|
-
const exportWav = (0, import_react19.useCallback)(
|
|
2834
|
-
(_0, _1, ..._2) => __async(null, [_0, _1, ..._2], function* (tracks, trackStates, options = {}) {
|
|
2835
|
-
const {
|
|
2836
|
-
filename = "export",
|
|
2837
|
-
mode = "master",
|
|
2838
|
-
trackIndex,
|
|
2839
|
-
autoDownload = true,
|
|
2840
|
-
applyEffects = true,
|
|
2841
|
-
effectsFunction,
|
|
2842
|
-
createOfflineTrackEffects,
|
|
2843
|
-
bitDepth = 16,
|
|
2844
|
-
onProgress
|
|
2845
|
-
} = options;
|
|
2846
|
-
setIsExporting(true);
|
|
2847
|
-
setProgress(0);
|
|
2848
|
-
setError(null);
|
|
2849
|
-
try {
|
|
2850
|
-
if (tracks.length === 0) {
|
|
2851
|
-
throw new Error("No tracks to export");
|
|
2852
|
-
}
|
|
2853
|
-
if (mode === "individual" && (trackIndex === void 0 || trackIndex < 0 || trackIndex >= tracks.length)) {
|
|
2854
|
-
throw new Error("Invalid track index for individual export");
|
|
2855
|
-
}
|
|
2856
|
-
const sampleRate = (0, import_playout3.getGlobalAudioContext)().sampleRate;
|
|
2857
|
-
let totalDurationSamples = 0;
|
|
2858
|
-
for (const track of tracks) {
|
|
2859
|
-
for (const clip of track.clips) {
|
|
2860
|
-
const clipEndSample = clip.startSample + clip.durationSamples;
|
|
2861
|
-
totalDurationSamples = Math.max(totalDurationSamples, clipEndSample);
|
|
2862
|
-
}
|
|
2863
|
-
}
|
|
2864
|
-
totalDurationSamples += Math.round(sampleRate * 0.1);
|
|
2865
|
-
const duration = totalDurationSamples / sampleRate;
|
|
2866
|
-
const tracksToRender = mode === "individual" ? [{ track: tracks[trackIndex], state: trackStates[trackIndex], index: trackIndex }] : tracks.map((track, index) => ({ track, state: trackStates[index], index }));
|
|
2867
|
-
const hasSolo = mode === "master" && trackStates.some((state) => state.soloed);
|
|
2868
|
-
const reportProgress = (p) => {
|
|
2869
|
-
setProgress(p);
|
|
2870
|
-
onProgress == null ? void 0 : onProgress(p);
|
|
2871
|
-
};
|
|
2872
|
-
const renderedBuffer = yield renderOffline(
|
|
2873
|
-
tracksToRender,
|
|
2874
|
-
hasSolo,
|
|
2875
|
-
duration,
|
|
2876
|
-
sampleRate,
|
|
2877
|
-
applyEffects,
|
|
2878
|
-
effectsFunction,
|
|
2879
|
-
createOfflineTrackEffects,
|
|
2880
|
-
reportProgress
|
|
2881
|
-
);
|
|
2882
|
-
reportProgress(0.9);
|
|
2883
|
-
const blob = encodeWav(renderedBuffer, { bitDepth });
|
|
2884
|
-
reportProgress(1);
|
|
2885
|
-
if (autoDownload) {
|
|
2886
|
-
const exportFilename = mode === "individual" ? `${filename}_${tracks[trackIndex].name}` : filename;
|
|
2887
|
-
downloadBlob(blob, `${exportFilename}.wav`);
|
|
2888
|
-
}
|
|
2889
|
-
return {
|
|
2890
|
-
audioBuffer: renderedBuffer,
|
|
2891
|
-
blob,
|
|
2892
|
-
duration
|
|
2893
|
-
};
|
|
2894
|
-
} catch (err) {
|
|
2895
|
-
const message = err instanceof Error ? err.message : "Export failed";
|
|
2896
|
-
setError(message);
|
|
2897
|
-
throw err;
|
|
2898
|
-
} finally {
|
|
2899
|
-
setIsExporting(false);
|
|
2900
|
-
}
|
|
2901
|
-
}),
|
|
2902
|
-
[]
|
|
2903
|
-
);
|
|
2904
|
-
return {
|
|
2905
|
-
exportWav,
|
|
2906
|
-
isExporting,
|
|
2907
|
-
progress,
|
|
2908
|
-
error
|
|
2909
|
-
};
|
|
2910
|
-
}
|
|
2911
|
-
function renderOffline(tracksToRender, hasSolo, duration, sampleRate, applyEffects, effectsFunction, createOfflineTrackEffects, onProgress) {
|
|
2912
|
-
return __async(this, null, function* () {
|
|
2913
|
-
const { Offline, Volume: Volume2, Gain, Panner, Player, ToneAudioBuffer } = yield import("tone");
|
|
2914
|
-
onProgress(0.1);
|
|
2915
|
-
const audibleTracks = tracksToRender.filter(({ state }) => {
|
|
2916
|
-
if (state.muted && !state.soloed) return false;
|
|
2917
|
-
if (hasSolo && !state.soloed) return false;
|
|
2918
|
-
return true;
|
|
2919
|
-
});
|
|
2920
|
-
const outputChannels = audibleTracks.reduce(
|
|
2921
|
-
(max, { track }) => Math.max(max, (0, import_core4.trackChannelCount)(track)),
|
|
2922
|
-
1
|
|
2923
|
-
);
|
|
2924
|
-
let buffer;
|
|
2925
|
-
try {
|
|
2926
|
-
buffer = yield Offline(
|
|
2927
|
-
(_0) => __async(null, [_0], function* ({ transport, destination }) {
|
|
2928
|
-
const masterVolume = new Volume2(0);
|
|
2929
|
-
if (effectsFunction && applyEffects) {
|
|
2930
|
-
effectsFunction(masterVolume, destination, true);
|
|
2931
|
-
} else {
|
|
2932
|
-
masterVolume.connect(destination);
|
|
2933
|
-
}
|
|
2934
|
-
for (const { track, state } of audibleTracks) {
|
|
2935
|
-
const trackVolume = new Volume2((0, import_core4.gainToDb)(state.volume));
|
|
2936
|
-
const trackPan = new Panner({ pan: state.pan, channelCount: (0, import_core4.trackChannelCount)(track) });
|
|
2937
|
-
const trackMute = new Gain(state.muted ? 0 : 1);
|
|
2938
|
-
const trackEffects = createOfflineTrackEffects == null ? void 0 : createOfflineTrackEffects(track.id);
|
|
2939
|
-
if (trackEffects && applyEffects) {
|
|
2940
|
-
trackEffects(trackMute, masterVolume, true);
|
|
2941
|
-
} else {
|
|
2942
|
-
trackMute.connect(masterVolume);
|
|
2943
|
-
}
|
|
2944
|
-
trackPan.connect(trackMute);
|
|
2945
|
-
trackVolume.connect(trackPan);
|
|
2946
|
-
for (const clip of track.clips) {
|
|
2947
|
-
const {
|
|
2948
|
-
audioBuffer,
|
|
2949
|
-
startSample,
|
|
2950
|
-
durationSamples,
|
|
2951
|
-
offsetSamples,
|
|
2952
|
-
gain: clipGain,
|
|
2953
|
-
fadeIn,
|
|
2954
|
-
fadeOut
|
|
2955
|
-
} = clip;
|
|
2956
|
-
if (!audioBuffer) {
|
|
2957
|
-
console.warn(
|
|
2958
|
-
'[waveform-playlist] Skipping clip "' + (clip.name || clip.id) + '" - no audioBuffer for export'
|
|
2959
|
-
);
|
|
2960
|
-
continue;
|
|
2961
|
-
}
|
|
2962
|
-
const startTime = startSample / sampleRate;
|
|
2963
|
-
const clipDuration = durationSamples / sampleRate;
|
|
2964
|
-
const offset = offsetSamples / sampleRate;
|
|
2965
|
-
const toneBuffer = new ToneAudioBuffer(audioBuffer);
|
|
2966
|
-
const player = new Player(toneBuffer);
|
|
2967
|
-
const fadeGain = new Gain(clipGain);
|
|
2968
|
-
player.connect(fadeGain);
|
|
2969
|
-
fadeGain.connect(trackVolume);
|
|
2970
|
-
if (applyEffects) {
|
|
2971
|
-
const audioParam = (0, import_playout3.getUnderlyingAudioParam)(fadeGain.gain);
|
|
2972
|
-
if (audioParam) {
|
|
2973
|
-
applyClipFades(audioParam, clipGain, startTime, clipDuration, fadeIn, fadeOut);
|
|
2974
|
-
} else if (fadeIn || fadeOut) {
|
|
2975
|
-
console.warn(
|
|
2976
|
-
'[waveform-playlist] Cannot apply fades for clip "' + (clip.name || clip.id) + '" - AudioParam not accessible'
|
|
2977
|
-
);
|
|
2978
|
-
}
|
|
2979
|
-
}
|
|
2980
|
-
player.start(startTime, offset, clipDuration);
|
|
2981
|
-
}
|
|
2982
|
-
}
|
|
2983
|
-
transport.start(0);
|
|
2984
|
-
}),
|
|
2985
|
-
duration,
|
|
2986
|
-
outputChannels,
|
|
2987
|
-
sampleRate
|
|
2988
|
-
);
|
|
2989
|
-
} catch (err) {
|
|
2990
|
-
if (err instanceof Error) {
|
|
2991
|
-
throw err;
|
|
2992
|
-
} else {
|
|
2993
|
-
throw new Error("Tone.Offline rendering failed: " + String(err));
|
|
2994
|
-
}
|
|
2995
|
-
}
|
|
2996
|
-
onProgress(0.9);
|
|
2997
|
-
const result = buffer.get();
|
|
2998
|
-
if (!result) {
|
|
2999
|
-
throw new Error("Offline rendering produced no audio buffer");
|
|
3000
|
-
}
|
|
3001
|
-
return result;
|
|
1449
|
+
enabled: enabled && annotations.length > 0 && !!onActiveAnnotationChange
|
|
3002
1450
|
});
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
const fadeOutStart = startTime + clipDuration - fadeOut.duration;
|
|
3015
|
-
if (!fadeIn || fadeIn.duration < clipDuration - fadeOut.duration) {
|
|
3016
|
-
gainParam.setValueAtTime(clipGain, fadeOutStart);
|
|
3017
|
-
}
|
|
3018
|
-
(0, import_core4.applyFadeOut)(gainParam, fadeOutStart, fadeOut.duration, fadeOut.type || "linear", clipGain, 0);
|
|
3019
|
-
}
|
|
1451
|
+
return {
|
|
1452
|
+
moveStartBoundary,
|
|
1453
|
+
moveEndBoundary,
|
|
1454
|
+
selectPrevious,
|
|
1455
|
+
selectNext,
|
|
1456
|
+
selectFirst,
|
|
1457
|
+
selectLast,
|
|
1458
|
+
clearSelection,
|
|
1459
|
+
scrollToAnnotation,
|
|
1460
|
+
playActiveAnnotation
|
|
1461
|
+
};
|
|
3020
1462
|
}
|
|
3021
1463
|
|
|
3022
1464
|
// src/hooks/useAnimationFrameLoop.ts
|
|
3023
|
-
var
|
|
1465
|
+
var import_react15 = require("react");
|
|
3024
1466
|
var useAnimationFrameLoop = () => {
|
|
3025
|
-
const animationFrameRef = (0,
|
|
3026
|
-
const stopAnimationFrameLoop = (0,
|
|
1467
|
+
const animationFrameRef = (0, import_react15.useRef)(null);
|
|
1468
|
+
const stopAnimationFrameLoop = (0, import_react15.useCallback)(() => {
|
|
3027
1469
|
if (animationFrameRef.current !== null) {
|
|
3028
1470
|
cancelAnimationFrame(animationFrameRef.current);
|
|
3029
1471
|
animationFrameRef.current = null;
|
|
3030
1472
|
}
|
|
3031
1473
|
}, []);
|
|
3032
|
-
const startAnimationFrameLoop = (0,
|
|
1474
|
+
const startAnimationFrameLoop = (0, import_react15.useCallback)(
|
|
3033
1475
|
(callback) => {
|
|
3034
1476
|
stopAnimationFrameLoop();
|
|
3035
1477
|
animationFrameRef.current = requestAnimationFrame(callback);
|
|
3036
1478
|
},
|
|
3037
1479
|
[stopAnimationFrameLoop]
|
|
3038
1480
|
);
|
|
3039
|
-
(0,
|
|
1481
|
+
(0, import_react15.useEffect)(() => {
|
|
3040
1482
|
return () => {
|
|
3041
1483
|
stopAnimationFrameLoop();
|
|
3042
1484
|
};
|
|
@@ -3049,7 +1491,7 @@ var useAnimationFrameLoop = () => {
|
|
|
3049
1491
|
};
|
|
3050
1492
|
|
|
3051
1493
|
// src/hooks/useWaveformDataCache.ts
|
|
3052
|
-
var
|
|
1494
|
+
var import_react16 = require("react");
|
|
3053
1495
|
|
|
3054
1496
|
// src/workers/peaksWorker.ts
|
|
3055
1497
|
var import_waveform_data2 = __toESM(require("waveform-data"));
|
|
@@ -3281,20 +1723,20 @@ function createPeaksWorker() {
|
|
|
3281
1723
|
|
|
3282
1724
|
// src/hooks/useWaveformDataCache.ts
|
|
3283
1725
|
function useWaveformDataCache(tracks, baseScale) {
|
|
3284
|
-
const [cache, setCache] = (0,
|
|
3285
|
-
const [isGenerating, setIsGenerating] = (0,
|
|
3286
|
-
const workerRef = (0,
|
|
3287
|
-
const generatedByBufferRef = (0,
|
|
3288
|
-
const inflightByBufferRef = (0,
|
|
3289
|
-
const subscribersByBufferRef = (0,
|
|
3290
|
-
const pendingCountRef = (0,
|
|
3291
|
-
const getWorker = (0,
|
|
1726
|
+
const [cache, setCache] = (0, import_react16.useState)(() => /* @__PURE__ */ new Map());
|
|
1727
|
+
const [isGenerating, setIsGenerating] = (0, import_react16.useState)(false);
|
|
1728
|
+
const workerRef = (0, import_react16.useRef)(null);
|
|
1729
|
+
const generatedByBufferRef = (0, import_react16.useRef)(/* @__PURE__ */ new WeakMap());
|
|
1730
|
+
const inflightByBufferRef = (0, import_react16.useRef)(/* @__PURE__ */ new WeakMap());
|
|
1731
|
+
const subscribersByBufferRef = (0, import_react16.useRef)(/* @__PURE__ */ new WeakMap());
|
|
1732
|
+
const pendingCountRef = (0, import_react16.useRef)(0);
|
|
1733
|
+
const getWorker = (0, import_react16.useCallback)(() => {
|
|
3292
1734
|
if (!workerRef.current) {
|
|
3293
1735
|
workerRef.current = createPeaksWorker();
|
|
3294
1736
|
}
|
|
3295
1737
|
return workerRef.current;
|
|
3296
1738
|
}, []);
|
|
3297
|
-
(0,
|
|
1739
|
+
(0, import_react16.useEffect)(() => {
|
|
3298
1740
|
let cancelled = false;
|
|
3299
1741
|
const generatedByBuffer = generatedByBufferRef.current;
|
|
3300
1742
|
const inflightByBuffer = inflightByBufferRef.current;
|
|
@@ -3399,7 +1841,7 @@ function useWaveformDataCache(tracks, baseScale) {
|
|
|
3399
1841
|
setIsGenerating(false);
|
|
3400
1842
|
};
|
|
3401
1843
|
}, [tracks, baseScale, getWorker]);
|
|
3402
|
-
(0,
|
|
1844
|
+
(0, import_react16.useEffect)(() => {
|
|
3403
1845
|
return () => {
|
|
3404
1846
|
var _a;
|
|
3405
1847
|
(_a = workerRef.current) == null ? void 0 : _a.terminate();
|
|
@@ -3409,232 +1851,12 @@ function useWaveformDataCache(tracks, baseScale) {
|
|
|
3409
1851
|
return { cache, isGenerating };
|
|
3410
1852
|
}
|
|
3411
1853
|
|
|
3412
|
-
// src/hooks/useDynamicTracks.ts
|
|
3413
|
-
var import_react22 = require("react");
|
|
3414
|
-
var import_core5 = require("@waveform-playlist/core");
|
|
3415
|
-
var import_playout4 = require("@waveform-playlist/playout");
|
|
3416
|
-
function getSourceName(source) {
|
|
3417
|
-
var _a, _b, _c, _d, _e;
|
|
3418
|
-
if (source instanceof File) {
|
|
3419
|
-
return source.name.replace(/\.[^/.]+$/, "");
|
|
3420
|
-
}
|
|
3421
|
-
if (source instanceof Blob) {
|
|
3422
|
-
return "Untitled";
|
|
3423
|
-
}
|
|
3424
|
-
if (typeof source === "string") {
|
|
3425
|
-
return (_b = (_a = source.split("/").pop()) == null ? void 0 : _a.replace(/\.[^/.]+$/, "")) != null ? _b : "Untitled";
|
|
3426
|
-
}
|
|
3427
|
-
return (_e = (_d = source.name) != null ? _d : (_c = source.src.split("/").pop()) == null ? void 0 : _c.replace(/\.[^/.]+$/, "")) != null ? _e : "Untitled";
|
|
3428
|
-
}
|
|
3429
|
-
function decodeSource(source, audioContext, signal) {
|
|
3430
|
-
return __async(this, null, function* () {
|
|
3431
|
-
const name = getSourceName(source);
|
|
3432
|
-
if (source instanceof Blob) {
|
|
3433
|
-
const arrayBuffer2 = yield source.arrayBuffer();
|
|
3434
|
-
signal == null ? void 0 : signal.throwIfAborted();
|
|
3435
|
-
const audioBuffer2 = yield audioContext.decodeAudioData(arrayBuffer2);
|
|
3436
|
-
return { audioBuffer: audioBuffer2, name };
|
|
3437
|
-
}
|
|
3438
|
-
const url = typeof source === "string" ? source : source.src;
|
|
3439
|
-
const response = yield fetch(url, { signal });
|
|
3440
|
-
if (!response.ok) throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
|
|
3441
|
-
const arrayBuffer = yield response.arrayBuffer();
|
|
3442
|
-
signal == null ? void 0 : signal.throwIfAborted();
|
|
3443
|
-
const audioBuffer = yield audioContext.decodeAudioData(arrayBuffer);
|
|
3444
|
-
return { audioBuffer, name };
|
|
3445
|
-
});
|
|
3446
|
-
}
|
|
3447
|
-
function useDynamicTracks() {
|
|
3448
|
-
const [tracks, setTracks] = (0, import_react22.useState)([]);
|
|
3449
|
-
const [loadingCount, setLoadingCount] = (0, import_react22.useState)(0);
|
|
3450
|
-
const [errors, setErrors] = (0, import_react22.useState)([]);
|
|
3451
|
-
const cancelledRef = (0, import_react22.useRef)(false);
|
|
3452
|
-
const loadingIdsRef = (0, import_react22.useRef)(/* @__PURE__ */ new Set());
|
|
3453
|
-
const abortControllersRef = (0, import_react22.useRef)(/* @__PURE__ */ new Map());
|
|
3454
|
-
(0, import_react22.useEffect)(() => {
|
|
3455
|
-
const controllers = abortControllersRef.current;
|
|
3456
|
-
return () => {
|
|
3457
|
-
cancelledRef.current = true;
|
|
3458
|
-
for (const controller of controllers.values()) {
|
|
3459
|
-
controller.abort();
|
|
3460
|
-
}
|
|
3461
|
-
controllers.clear();
|
|
3462
|
-
};
|
|
3463
|
-
}, []);
|
|
3464
|
-
const addTracks = (0, import_react22.useCallback)((sources) => {
|
|
3465
|
-
if (sources.length === 0) return;
|
|
3466
|
-
const audioContext = (0, import_playout4.getGlobalAudioContext)();
|
|
3467
|
-
const placeholders = sources.map((source) => ({
|
|
3468
|
-
track: (0, import_core5.createTrack)({ name: `${getSourceName(source)} (loading...)`, clips: [] }),
|
|
3469
|
-
source
|
|
3470
|
-
}));
|
|
3471
|
-
setTracks((prev) => [...prev, ...placeholders.map((p) => p.track)]);
|
|
3472
|
-
setLoadingCount((prev) => prev + sources.length);
|
|
3473
|
-
for (const { track, source } of placeholders) {
|
|
3474
|
-
loadingIdsRef.current.add(track.id);
|
|
3475
|
-
const controller = new AbortController();
|
|
3476
|
-
abortControllersRef.current.set(track.id, controller);
|
|
3477
|
-
(() => __async(null, null, function* () {
|
|
3478
|
-
try {
|
|
3479
|
-
const { audioBuffer, name } = yield decodeSource(source, audioContext, controller.signal);
|
|
3480
|
-
const clip = (0, import_core5.createClipFromSeconds)({
|
|
3481
|
-
audioBuffer,
|
|
3482
|
-
startTime: 0,
|
|
3483
|
-
duration: audioBuffer.duration,
|
|
3484
|
-
offset: 0,
|
|
3485
|
-
name
|
|
3486
|
-
});
|
|
3487
|
-
if (!cancelledRef.current && loadingIdsRef.current.has(track.id)) {
|
|
3488
|
-
setTracks(
|
|
3489
|
-
(prev) => prev.map((t) => t.id === track.id ? __spreadProps(__spreadValues({}, t), { name, clips: [clip] }) : t)
|
|
3490
|
-
);
|
|
3491
|
-
}
|
|
3492
|
-
} catch (error) {
|
|
3493
|
-
if (error instanceof DOMException && error.name === "AbortError") return;
|
|
3494
|
-
console.warn("[waveform-playlist] Error loading audio:", error);
|
|
3495
|
-
if (!cancelledRef.current && loadingIdsRef.current.has(track.id)) {
|
|
3496
|
-
setTracks((prev) => prev.filter((t) => t.id !== track.id));
|
|
3497
|
-
setErrors((prev) => [
|
|
3498
|
-
...prev,
|
|
3499
|
-
{
|
|
3500
|
-
name: getSourceName(source),
|
|
3501
|
-
error: error instanceof Error ? error : new Error(String(error))
|
|
3502
|
-
}
|
|
3503
|
-
]);
|
|
3504
|
-
}
|
|
3505
|
-
} finally {
|
|
3506
|
-
abortControllersRef.current.delete(track.id);
|
|
3507
|
-
if (!cancelledRef.current && loadingIdsRef.current.delete(track.id)) {
|
|
3508
|
-
setLoadingCount((prev) => prev - 1);
|
|
3509
|
-
}
|
|
3510
|
-
}
|
|
3511
|
-
}))();
|
|
3512
|
-
}
|
|
3513
|
-
}, []);
|
|
3514
|
-
const removeTrack = (0, import_react22.useCallback)((trackId) => {
|
|
3515
|
-
setTracks((prev) => prev.filter((t) => t.id !== trackId));
|
|
3516
|
-
const controller = abortControllersRef.current.get(trackId);
|
|
3517
|
-
if (controller) {
|
|
3518
|
-
controller.abort();
|
|
3519
|
-
abortControllersRef.current.delete(trackId);
|
|
3520
|
-
}
|
|
3521
|
-
if (loadingIdsRef.current.delete(trackId)) {
|
|
3522
|
-
setLoadingCount((prev) => prev - 1);
|
|
3523
|
-
}
|
|
3524
|
-
}, []);
|
|
3525
|
-
return {
|
|
3526
|
-
tracks,
|
|
3527
|
-
addTracks,
|
|
3528
|
-
removeTrack,
|
|
3529
|
-
loadingCount,
|
|
3530
|
-
isLoading: loadingCount > 0,
|
|
3531
|
-
errors
|
|
3532
|
-
};
|
|
3533
|
-
}
|
|
3534
|
-
|
|
3535
|
-
// src/hooks/useOutputMeter.ts
|
|
3536
|
-
var import_react23 = require("react");
|
|
3537
|
-
var import_playout5 = require("@waveform-playlist/playout");
|
|
3538
|
-
var import_core6 = require("@waveform-playlist/core");
|
|
3539
|
-
var import_worklets = require("@waveform-playlist/worklets");
|
|
3540
|
-
var PEAK_DECAY = 0.98;
|
|
3541
|
-
function useOutputMeter(options = {}) {
|
|
3542
|
-
const { channelCount = 2, updateRate = 60, isPlaying = false } = options;
|
|
3543
|
-
const [levels, setLevels] = (0, import_react23.useState)(() => new Array(channelCount).fill(0));
|
|
3544
|
-
const [peakLevels, setPeakLevels] = (0, import_react23.useState)(() => new Array(channelCount).fill(0));
|
|
3545
|
-
const [rmsLevels, setRmsLevels] = (0, import_react23.useState)(() => new Array(channelCount).fill(0));
|
|
3546
|
-
const workletNodeRef = (0, import_react23.useRef)(null);
|
|
3547
|
-
const smoothedPeakRef = (0, import_react23.useRef)(new Array(channelCount).fill(0));
|
|
3548
|
-
const [meterError, setMeterError] = (0, import_react23.useState)(null);
|
|
3549
|
-
const resetPeak = (0, import_react23.useCallback)(
|
|
3550
|
-
() => setPeakLevels(new Array(channelCount).fill(0)),
|
|
3551
|
-
[channelCount]
|
|
3552
|
-
);
|
|
3553
|
-
(0, import_react23.useEffect)(() => {
|
|
3554
|
-
if (!isPlaying) {
|
|
3555
|
-
const zeros = new Array(channelCount).fill(0);
|
|
3556
|
-
smoothedPeakRef.current = new Array(channelCount).fill(0);
|
|
3557
|
-
setLevels(zeros);
|
|
3558
|
-
setRmsLevels(zeros);
|
|
3559
|
-
setPeakLevels(zeros);
|
|
3560
|
-
}
|
|
3561
|
-
}, [isPlaying, channelCount]);
|
|
3562
|
-
(0, import_react23.useEffect)(() => {
|
|
3563
|
-
let isMounted = true;
|
|
3564
|
-
const setup = () => __async(null, null, function* () {
|
|
3565
|
-
const context = (0, import_playout5.getGlobalContext)();
|
|
3566
|
-
const rawCtx = context.rawContext;
|
|
3567
|
-
yield rawCtx.audioWorklet.addModule(import_worklets.meterProcessorUrl);
|
|
3568
|
-
if (!isMounted) return;
|
|
3569
|
-
const workletNode = context.createAudioWorkletNode("meter-processor", {
|
|
3570
|
-
channelCount,
|
|
3571
|
-
channelCountMode: "explicit",
|
|
3572
|
-
processorOptions: {
|
|
3573
|
-
numberOfChannels: channelCount,
|
|
3574
|
-
updateRate
|
|
3575
|
-
}
|
|
3576
|
-
});
|
|
3577
|
-
workletNodeRef.current = workletNode;
|
|
3578
|
-
workletNode.onprocessorerror = (event) => {
|
|
3579
|
-
console.warn("[waveform-playlist] Output meter worklet processor error:", String(event));
|
|
3580
|
-
};
|
|
3581
|
-
const destination = context.destination;
|
|
3582
|
-
destination.chain(workletNode);
|
|
3583
|
-
smoothedPeakRef.current = new Array(channelCount).fill(0);
|
|
3584
|
-
workletNode.port.onmessage = (event) => {
|
|
3585
|
-
var _a;
|
|
3586
|
-
if (!isMounted) return;
|
|
3587
|
-
const { peak, rms } = event.data;
|
|
3588
|
-
const smoothed = smoothedPeakRef.current;
|
|
3589
|
-
const peakValues = [];
|
|
3590
|
-
const rmsValues = [];
|
|
3591
|
-
for (let ch = 0; ch < peak.length; ch++) {
|
|
3592
|
-
smoothed[ch] = Math.max(peak[ch], ((_a = smoothed[ch]) != null ? _a : 0) * PEAK_DECAY);
|
|
3593
|
-
peakValues.push((0, import_core6.gainToNormalized)(smoothed[ch]));
|
|
3594
|
-
rmsValues.push((0, import_core6.gainToNormalized)(rms[ch]));
|
|
3595
|
-
}
|
|
3596
|
-
setLevels(peakValues);
|
|
3597
|
-
setRmsLevels(rmsValues);
|
|
3598
|
-
setPeakLevels((prev) => peakValues.map((val, i) => {
|
|
3599
|
-
var _a2;
|
|
3600
|
-
return Math.max((_a2 = prev[i]) != null ? _a2 : 0, val);
|
|
3601
|
-
}));
|
|
3602
|
-
};
|
|
3603
|
-
});
|
|
3604
|
-
setup().catch((err) => {
|
|
3605
|
-
console.warn("[waveform-playlist] Failed to set up output meter:", String(err));
|
|
3606
|
-
if (isMounted) {
|
|
3607
|
-
setMeterError(err instanceof Error ? err : new Error(String(err)));
|
|
3608
|
-
}
|
|
3609
|
-
});
|
|
3610
|
-
return () => {
|
|
3611
|
-
isMounted = false;
|
|
3612
|
-
if (workletNodeRef.current) {
|
|
3613
|
-
try {
|
|
3614
|
-
const context = (0, import_playout5.getGlobalContext)();
|
|
3615
|
-
context.destination.chain();
|
|
3616
|
-
} catch (err) {
|
|
3617
|
-
console.warn("[waveform-playlist] Failed to restore destination chain:", String(err));
|
|
3618
|
-
}
|
|
3619
|
-
try {
|
|
3620
|
-
workletNodeRef.current.disconnect();
|
|
3621
|
-
workletNodeRef.current.port.close();
|
|
3622
|
-
} catch (err) {
|
|
3623
|
-
console.warn("[waveform-playlist] Output meter disconnect during cleanup:", String(err));
|
|
3624
|
-
}
|
|
3625
|
-
workletNodeRef.current = null;
|
|
3626
|
-
}
|
|
3627
|
-
};
|
|
3628
|
-
}, [channelCount, updateRate]);
|
|
3629
|
-
return { levels, peakLevels, rmsLevels, resetPeak, error: meterError };
|
|
3630
|
-
}
|
|
3631
|
-
|
|
3632
1854
|
// src/WaveformPlaylistContext.tsx
|
|
3633
1855
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
3634
|
-
var PlaybackAnimationContext = (0,
|
|
3635
|
-
var PlaylistStateContext = (0,
|
|
3636
|
-
var PlaylistControlsContext = (0,
|
|
3637
|
-
var PlaylistDataContext = (0,
|
|
1856
|
+
var PlaybackAnimationContext = (0, import_react17.createContext)(null);
|
|
1857
|
+
var PlaylistStateContext = (0, import_react17.createContext)(null);
|
|
1858
|
+
var PlaylistControlsContext = (0, import_react17.createContext)(null);
|
|
1859
|
+
var PlaylistDataContext = (0, import_react17.createContext)(null);
|
|
3638
1860
|
var WaveformPlaylistProvider = ({
|
|
3639
1861
|
tracks,
|
|
3640
1862
|
timescale = false,
|
|
@@ -3648,6 +1870,7 @@ var WaveformPlaylistProvider = ({
|
|
|
3648
1870
|
annotationList,
|
|
3649
1871
|
effects,
|
|
3650
1872
|
onReady,
|
|
1873
|
+
onError,
|
|
3651
1874
|
onAnnotationUpdate: _onAnnotationUpdate,
|
|
3652
1875
|
onAnnotationsChange,
|
|
3653
1876
|
barWidth = 1,
|
|
@@ -3658,18 +1881,19 @@ var WaveformPlaylistProvider = ({
|
|
|
3658
1881
|
deferEngineRebuild = false,
|
|
3659
1882
|
indefinitePlayback = false,
|
|
3660
1883
|
sampleRate: sampleRateProp,
|
|
1884
|
+
createAdapter,
|
|
3661
1885
|
children
|
|
3662
1886
|
}) => {
|
|
3663
1887
|
var _a, _b, _c, _d;
|
|
3664
1888
|
const progressBarWidth = progressBarWidthProp != null ? progressBarWidthProp : barWidth + barGap;
|
|
3665
|
-
const indefinitePlaybackRef = (0,
|
|
1889
|
+
const indefinitePlaybackRef = (0, import_react17.useRef)(indefinitePlayback);
|
|
3666
1890
|
indefinitePlaybackRef.current = indefinitePlayback;
|
|
3667
|
-
const stableZoomLevels = (0,
|
|
1891
|
+
const stableZoomLevels = (0, import_react17.useMemo)(
|
|
3668
1892
|
() => zoomLevels,
|
|
3669
1893
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3670
1894
|
[zoomLevels == null ? void 0 : zoomLevels.join(",")]
|
|
3671
1895
|
);
|
|
3672
|
-
const annotations = (0,
|
|
1896
|
+
const annotations = (0, import_react17.useMemo)(() => {
|
|
3673
1897
|
if (!(annotationList == null ? void 0 : annotationList.annotations)) return [];
|
|
3674
1898
|
if (process.env.NODE_ENV !== "production" && annotationList.annotations.length > 0) {
|
|
3675
1899
|
const first = annotationList.annotations[0];
|
|
@@ -3682,63 +1906,50 @@ var WaveformPlaylistProvider = ({
|
|
|
3682
1906
|
}
|
|
3683
1907
|
return annotationList.annotations;
|
|
3684
1908
|
}, [annotationList == null ? void 0 : annotationList.annotations]);
|
|
3685
|
-
const annotationsRef = (0,
|
|
1909
|
+
const annotationsRef = (0, import_react17.useRef)(annotations);
|
|
3686
1910
|
annotationsRef.current = annotations;
|
|
3687
|
-
const [activeAnnotationId, setActiveAnnotationIdState] = (0,
|
|
3688
|
-
const [isPlaying, setIsPlaying] = (0,
|
|
3689
|
-
const [currentTime, setCurrentTime] = (0,
|
|
3690
|
-
const [duration, setDuration] = (0,
|
|
3691
|
-
const [audioBuffers, setAudioBuffers] = (0,
|
|
3692
|
-
const [peaksDataArray, setPeaksDataArray] = (0,
|
|
3693
|
-
const [trackStates, setTrackStates] = (0,
|
|
3694
|
-
const [isAutomaticScroll, setIsAutomaticScroll] = (0,
|
|
3695
|
-
const [continuousPlay, setContinuousPlayState] = (0,
|
|
1911
|
+
const [activeAnnotationId, setActiveAnnotationIdState] = (0, import_react17.useState)(null);
|
|
1912
|
+
const [isPlaying, setIsPlaying] = (0, import_react17.useState)(false);
|
|
1913
|
+
const [currentTime, setCurrentTime] = (0, import_react17.useState)(0);
|
|
1914
|
+
const [duration, setDuration] = (0, import_react17.useState)(0);
|
|
1915
|
+
const [audioBuffers, setAudioBuffers] = (0, import_react17.useState)([]);
|
|
1916
|
+
const [peaksDataArray, setPeaksDataArray] = (0, import_react17.useState)([]);
|
|
1917
|
+
const [trackStates, setTrackStates] = (0, import_react17.useState)([]);
|
|
1918
|
+
const [isAutomaticScroll, setIsAutomaticScroll] = (0, import_react17.useState)(automaticScroll);
|
|
1919
|
+
const [continuousPlay, setContinuousPlayState] = (0, import_react17.useState)(
|
|
3696
1920
|
(_a = annotationList == null ? void 0 : annotationList.isContinuousPlay) != null ? _a : false
|
|
3697
1921
|
);
|
|
3698
|
-
const [linkEndpoints, setLinkEndpoints] = (0,
|
|
3699
|
-
const [annotationsEditable, setAnnotationsEditable] = (0,
|
|
3700
|
-
const [isReady, setIsReady] = (0,
|
|
3701
|
-
const engineRef = (0,
|
|
3702
|
-
const adapterRef = (0,
|
|
3703
|
-
const audioInitializedRef = (0,
|
|
3704
|
-
const isPlayingRef = (0,
|
|
1922
|
+
const [linkEndpoints, setLinkEndpoints] = (0, import_react17.useState)((_b = annotationList == null ? void 0 : annotationList.linkEndpoints) != null ? _b : false);
|
|
1923
|
+
const [annotationsEditable, setAnnotationsEditable] = (0, import_react17.useState)((_c = annotationList == null ? void 0 : annotationList.editable) != null ? _c : false);
|
|
1924
|
+
const [isReady, setIsReady] = (0, import_react17.useState)(false);
|
|
1925
|
+
const engineRef = (0, import_react17.useRef)(null);
|
|
1926
|
+
const adapterRef = (0, import_react17.useRef)(null);
|
|
1927
|
+
const audioInitializedRef = (0, import_react17.useRef)(false);
|
|
1928
|
+
const isPlayingRef = (0, import_react17.useRef)(false);
|
|
3705
1929
|
isPlayingRef.current = isPlaying;
|
|
3706
|
-
const playStartPositionRef = (0,
|
|
3707
|
-
const currentTimeRef = (0,
|
|
3708
|
-
const visualTimeRef = (0,
|
|
3709
|
-
const tracksRef = (0,
|
|
3710
|
-
const soundFontCacheRef = (0,
|
|
1930
|
+
const playStartPositionRef = (0, import_react17.useRef)(0);
|
|
1931
|
+
const currentTimeRef = (0, import_react17.useRef)(0);
|
|
1932
|
+
const visualTimeRef = (0, import_react17.useRef)(0);
|
|
1933
|
+
const tracksRef = (0, import_react17.useRef)(tracks);
|
|
1934
|
+
const soundFontCacheRef = (0, import_react17.useRef)(soundFontCache);
|
|
3711
1935
|
soundFontCacheRef.current = soundFontCache;
|
|
3712
|
-
const trackStatesRef = (0,
|
|
3713
|
-
const playbackStartTimeRef = (0,
|
|
3714
|
-
const audioStartPositionRef = (0,
|
|
3715
|
-
const playbackEndTimeRef = (0,
|
|
3716
|
-
const scrollContainerRef = (0,
|
|
3717
|
-
const isAutomaticScrollRef = (0,
|
|
3718
|
-
const frameCallbacksRef = (0,
|
|
3719
|
-
const continuousPlayRef = (0,
|
|
3720
|
-
const activeAnnotationIdRef = (0,
|
|
3721
|
-
const engineTracksRef = (0,
|
|
3722
|
-
const lastTracksVersionRef = (0,
|
|
3723
|
-
const skipEngineDisposeRef = (0,
|
|
3724
|
-
const isDraggingRef = (0,
|
|
3725
|
-
const prevTracksRef = (0,
|
|
3726
|
-
const samplesPerPixelRef = (0,
|
|
3727
|
-
const [initialSampleRate] = (0,
|
|
3728
|
-
|
|
3729
|
-
try {
|
|
3730
|
-
if (sampleRateProp !== void 0) {
|
|
3731
|
-
return (0, import_playout6.configureGlobalContext)({ sampleRate: sampleRateProp });
|
|
3732
|
-
}
|
|
3733
|
-
return (0, import_playout6.getGlobalAudioContext)().sampleRate;
|
|
3734
|
-
} catch (err) {
|
|
3735
|
-
console.warn(
|
|
3736
|
-
"[waveform-playlist] Failed to configure AudioContext: " + String(err) + " \u2014 falling back to " + (sampleRateProp != null ? sampleRateProp : 48e3) + " Hz"
|
|
3737
|
-
);
|
|
3738
|
-
return sampleRateProp != null ? sampleRateProp : 48e3;
|
|
3739
|
-
}
|
|
3740
|
-
});
|
|
3741
|
-
const sampleRateRef = (0, import_react24.useRef)(initialSampleRate);
|
|
1936
|
+
const trackStatesRef = (0, import_react17.useRef)(trackStates);
|
|
1937
|
+
const playbackStartTimeRef = (0, import_react17.useRef)(0);
|
|
1938
|
+
const audioStartPositionRef = (0, import_react17.useRef)(0);
|
|
1939
|
+
const playbackEndTimeRef = (0, import_react17.useRef)(null);
|
|
1940
|
+
const scrollContainerRef = (0, import_react17.useRef)(null);
|
|
1941
|
+
const isAutomaticScrollRef = (0, import_react17.useRef)(false);
|
|
1942
|
+
const frameCallbacksRef = (0, import_react17.useRef)(/* @__PURE__ */ new Map());
|
|
1943
|
+
const continuousPlayRef = (0, import_react17.useRef)((_d = annotationList == null ? void 0 : annotationList.isContinuousPlay) != null ? _d : false);
|
|
1944
|
+
const activeAnnotationIdRef = (0, import_react17.useRef)(null);
|
|
1945
|
+
const engineTracksRef = (0, import_react17.useRef)(null);
|
|
1946
|
+
const lastTracksVersionRef = (0, import_react17.useRef)(0);
|
|
1947
|
+
const skipEngineDisposeRef = (0, import_react17.useRef)(false);
|
|
1948
|
+
const isDraggingRef = (0, import_react17.useRef)(false);
|
|
1949
|
+
const prevTracksRef = (0, import_react17.useRef)([]);
|
|
1950
|
+
const samplesPerPixelRef = (0, import_react17.useRef)(initialSamplesPerPixel);
|
|
1951
|
+
const [initialSampleRate] = (0, import_react17.useState)(() => sampleRateProp != null ? sampleRateProp : 48e3);
|
|
1952
|
+
const sampleRateRef = (0, import_react17.useRef)(initialSampleRate);
|
|
3742
1953
|
const { timeFormat, setTimeFormat, formatTime: formatTime2 } = useTimeFormat();
|
|
3743
1954
|
const zoom = useZoomControls({ engineRef, initialSamplesPerPixel });
|
|
3744
1955
|
const { samplesPerPixel, onEngineState: onZoomEngineState } = zoom;
|
|
@@ -3783,20 +1994,20 @@ var WaveformPlaylistProvider = ({
|
|
|
3783
1994
|
onEngineState: onUndoEngineState
|
|
3784
1995
|
} = useUndoState({ engineRef });
|
|
3785
1996
|
const { animationFrameRef, startAnimationFrameLoop, stopAnimationFrameLoop } = useAnimationFrameLoop();
|
|
3786
|
-
const baseScale = (0,
|
|
1997
|
+
const baseScale = (0, import_react17.useMemo)(
|
|
3787
1998
|
() => Math.min(...stableZoomLevels != null ? stableZoomLevels : [256, 512, 1024, 2048, 4096, 8192]),
|
|
3788
1999
|
[stableZoomLevels]
|
|
3789
2000
|
);
|
|
3790
2001
|
const { cache: waveformDataCache } = useWaveformDataCache(tracks, baseScale);
|
|
3791
|
-
const setContinuousPlay = (0,
|
|
2002
|
+
const setContinuousPlay = (0, import_react17.useCallback)((value) => {
|
|
3792
2003
|
continuousPlayRef.current = value;
|
|
3793
2004
|
setContinuousPlayState(value);
|
|
3794
2005
|
}, []);
|
|
3795
|
-
const setActiveAnnotationId = (0,
|
|
2006
|
+
const setActiveAnnotationId = (0, import_react17.useCallback)((value) => {
|
|
3796
2007
|
activeAnnotationIdRef.current = value;
|
|
3797
2008
|
setActiveAnnotationIdState(value);
|
|
3798
2009
|
}, []);
|
|
3799
|
-
const setLoopRegionFromSelection = (0,
|
|
2010
|
+
const setLoopRegionFromSelection = (0, import_react17.useCallback)(() => {
|
|
3800
2011
|
var _a2, _b2;
|
|
3801
2012
|
const start = (_a2 = selectionStartRef.current) != null ? _a2 : 0;
|
|
3802
2013
|
const end = (_b2 = selectionEndRef.current) != null ? _b2 : 0;
|
|
@@ -3804,21 +2015,21 @@ var WaveformPlaylistProvider = ({
|
|
|
3804
2015
|
setLoopRegion(start, end);
|
|
3805
2016
|
}
|
|
3806
2017
|
}, [setLoopRegion, selectionStartRef, selectionEndRef]);
|
|
3807
|
-
(0,
|
|
2018
|
+
(0, import_react17.useEffect)(() => {
|
|
3808
2019
|
isAutomaticScrollRef.current = isAutomaticScroll;
|
|
3809
2020
|
}, [isAutomaticScroll]);
|
|
3810
|
-
(0,
|
|
2021
|
+
(0, import_react17.useEffect)(() => {
|
|
3811
2022
|
trackStatesRef.current = trackStates;
|
|
3812
2023
|
}, [trackStates]);
|
|
3813
2024
|
tracksRef.current = tracks;
|
|
3814
2025
|
const isEngineTracks = tracks === engineTracksRef.current;
|
|
3815
2026
|
const prevTracks = prevTracksRef.current;
|
|
3816
|
-
const isIncrementalAdd = engineRef.current !== null &&
|
|
2027
|
+
const isIncrementalAdd = engineRef.current !== null && tracks.length > prevTracks.length && prevTracks.every((pt) => {
|
|
3817
2028
|
const current = tracks.find((t) => t.id === pt.id);
|
|
3818
2029
|
return current === pt;
|
|
3819
2030
|
});
|
|
3820
2031
|
skipEngineDisposeRef.current = isEngineTracks || isDraggingRef.current || isIncrementalAdd;
|
|
3821
|
-
(0,
|
|
2032
|
+
(0, import_react17.useEffect)(() => {
|
|
3822
2033
|
if (!scrollContainerRef.current || duration === 0) return;
|
|
3823
2034
|
const container = scrollContainerRef.current;
|
|
3824
2035
|
const oldSamplesPerPixel = samplesPerPixelRef.current;
|
|
@@ -3834,8 +2045,8 @@ var WaveformPlaylistProvider = ({
|
|
|
3834
2045
|
container.scrollLeft = newScrollLeft;
|
|
3835
2046
|
samplesPerPixelRef.current = newSamplesPerPixel;
|
|
3836
2047
|
}, [samplesPerPixel, duration]);
|
|
3837
|
-
const pendingResumeRef = (0,
|
|
3838
|
-
(0,
|
|
2048
|
+
const pendingResumeRef = (0, import_react17.useRef)(null);
|
|
2049
|
+
(0, import_react17.useEffect)(() => {
|
|
3839
2050
|
var _a2, _b2, _c2, _d2;
|
|
3840
2051
|
if (isEngineTracks || isDraggingRef.current) {
|
|
3841
2052
|
if (isEngineTracks) {
|
|
@@ -3926,12 +2137,10 @@ var WaveformPlaylistProvider = ({
|
|
|
3926
2137
|
setTrackStates([]);
|
|
3927
2138
|
setPeaksDataArray([]);
|
|
3928
2139
|
if (engineRef.current) {
|
|
3929
|
-
engineRef.current.
|
|
3930
|
-
|
|
3931
|
-
|
|
2140
|
+
engineRef.current.setTracks([]);
|
|
2141
|
+
prevTracksRef.current = tracks;
|
|
2142
|
+
return;
|
|
3932
2143
|
}
|
|
3933
|
-
prevTracksRef.current = tracks;
|
|
3934
|
-
return;
|
|
3935
2144
|
}
|
|
3936
2145
|
const wasPlaying = isPlayingRef.current;
|
|
3937
2146
|
const resumePosition = currentTimeRef.current;
|
|
@@ -3940,6 +2149,7 @@ var WaveformPlaylistProvider = ({
|
|
|
3940
2149
|
stopAnimationFrameLoop();
|
|
3941
2150
|
pendingResumeRef.current = { position: resumePosition };
|
|
3942
2151
|
}
|
|
2152
|
+
let cancelled = false;
|
|
3943
2153
|
const loadAudio = () => __async(null, null, function* () {
|
|
3944
2154
|
var _a3, _b3, _c3, _d3, _e;
|
|
3945
2155
|
try {
|
|
@@ -3982,7 +2192,17 @@ var WaveformPlaylistProvider = ({
|
|
|
3982
2192
|
lastTracksVersionRef.current = 0;
|
|
3983
2193
|
engineTracksRef.current = null;
|
|
3984
2194
|
audioInitializedRef.current = false;
|
|
3985
|
-
const adapter =
|
|
2195
|
+
const adapter = yield resolvePlayoutAdapter({
|
|
2196
|
+
createAdapter,
|
|
2197
|
+
effects,
|
|
2198
|
+
soundFontCache: soundFontCacheRef.current,
|
|
2199
|
+
sampleRate: sampleRateProp
|
|
2200
|
+
});
|
|
2201
|
+
if (cancelled) {
|
|
2202
|
+
adapter.dispose();
|
|
2203
|
+
return;
|
|
2204
|
+
}
|
|
2205
|
+
sampleRateRef.current = adapter.audioContext.sampleRate;
|
|
3986
2206
|
adapterRef.current = adapter;
|
|
3987
2207
|
const engine = new import_engine3.PlaylistEngine({
|
|
3988
2208
|
adapter,
|
|
@@ -4040,11 +2260,23 @@ var WaveformPlaylistProvider = ({
|
|
|
4040
2260
|
prevTracksRef.current = tracks;
|
|
4041
2261
|
onReady == null ? void 0 : onReady();
|
|
4042
2262
|
} catch (error) {
|
|
4043
|
-
|
|
2263
|
+
if (!engineRef.current && adapterRef.current) {
|
|
2264
|
+
try {
|
|
2265
|
+
adapterRef.current.dispose();
|
|
2266
|
+
} catch (disposeErr) {
|
|
2267
|
+
console.warn(
|
|
2268
|
+
"[waveform-playlist] adapter dispose after load failure threw: " + String(disposeErr)
|
|
2269
|
+
);
|
|
2270
|
+
}
|
|
2271
|
+
adapterRef.current = null;
|
|
2272
|
+
}
|
|
2273
|
+
console.warn("[waveform-playlist] Error loading audio: " + String(error));
|
|
2274
|
+
onError == null ? void 0 : onError(error instanceof Error ? error : new Error(String(error)));
|
|
4044
2275
|
}
|
|
4045
2276
|
});
|
|
4046
2277
|
loadAudio();
|
|
4047
2278
|
return () => {
|
|
2279
|
+
cancelled = true;
|
|
4048
2280
|
if (skipEngineDisposeRef.current) {
|
|
4049
2281
|
skipEngineDisposeRef.current = false;
|
|
4050
2282
|
return;
|
|
@@ -4067,6 +2299,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4067
2299
|
// to the live adapter by the sync effect below; only adapter creation reads it
|
|
4068
2300
|
// (via soundFontCacheRef).
|
|
4069
2301
|
onReady,
|
|
2302
|
+
onError,
|
|
4070
2303
|
effects,
|
|
4071
2304
|
stopAnimationFrameLoop,
|
|
4072
2305
|
onSelectionEngineState,
|
|
@@ -4085,10 +2318,10 @@ var WaveformPlaylistProvider = ({
|
|
|
4085
2318
|
stableZoomLevels,
|
|
4086
2319
|
deferEngineRebuild
|
|
4087
2320
|
]);
|
|
4088
|
-
(0,
|
|
2321
|
+
(0, import_react17.useEffect)(() => {
|
|
4089
2322
|
syncSoundFontCacheToAdapter(adapterRef.current, soundFontCache);
|
|
4090
2323
|
}, [soundFontCache]);
|
|
4091
|
-
(0,
|
|
2324
|
+
(0, import_react17.useEffect)(() => {
|
|
4092
2325
|
if (tracks.length === 0) return;
|
|
4093
2326
|
const allTrackPeaks = tracks.map((track) => {
|
|
4094
2327
|
const clipPeaks = track.clips.map((clip) => {
|
|
@@ -4169,8 +2402,15 @@ var WaveformPlaylistProvider = ({
|
|
|
4169
2402
|
});
|
|
4170
2403
|
setPeaksDataArray(allTrackPeaks);
|
|
4171
2404
|
}, [tracks, samplesPerPixel, mono, waveformDataCache, deferEngineRebuild]);
|
|
4172
|
-
const
|
|
4173
|
-
|
|
2405
|
+
const getAudioContextTime = (0, import_react17.useCallback)(
|
|
2406
|
+
() => {
|
|
2407
|
+
var _a2, _b2;
|
|
2408
|
+
return (_b2 = (_a2 = adapterRef.current) == null ? void 0 : _a2.audioContext.currentTime) != null ? _b2 : 0;
|
|
2409
|
+
},
|
|
2410
|
+
[]
|
|
2411
|
+
);
|
|
2412
|
+
const getPlaybackTimeFallbackWarnedRef = (0, import_react17.useRef)(false);
|
|
2413
|
+
const getPlaybackTime = (0, import_react17.useCallback)(() => {
|
|
4174
2414
|
var _a2, _b2;
|
|
4175
2415
|
if (engineRef.current) {
|
|
4176
2416
|
return engineRef.current.getCurrentTime();
|
|
@@ -4181,30 +2421,35 @@ var WaveformPlaylistProvider = ({
|
|
|
4181
2421
|
"[waveform-playlist] getPlaybackTime called without engine. Falling back to manual elapsed time (loop wrapping will not work)."
|
|
4182
2422
|
);
|
|
4183
2423
|
}
|
|
4184
|
-
const elapsed = (
|
|
2424
|
+
const elapsed = getAudioContextTime() - ((_a2 = playbackStartTimeRef.current) != null ? _a2 : 0);
|
|
4185
2425
|
return ((_b2 = audioStartPositionRef.current) != null ? _b2 : 0) + elapsed;
|
|
4186
|
-
}, []);
|
|
4187
|
-
const toVisualTime = (0,
|
|
2426
|
+
}, [getAudioContextTime]);
|
|
2427
|
+
const toVisualTime = (0, import_react17.useCallback)((rawTime) => {
|
|
4188
2428
|
return Number.isFinite(rawTime) ? Math.max(0, rawTime) : 0;
|
|
4189
2429
|
}, []);
|
|
4190
|
-
const setCurrentTimeRefs = (0,
|
|
2430
|
+
const setCurrentTimeRefs = (0, import_react17.useCallback)(
|
|
4191
2431
|
(rawTime) => {
|
|
4192
2432
|
currentTimeRef.current = rawTime;
|
|
4193
2433
|
visualTimeRef.current = toVisualTime(rawTime);
|
|
4194
2434
|
},
|
|
4195
2435
|
[toVisualTime]
|
|
4196
2436
|
);
|
|
4197
|
-
const getLookAhead = (0,
|
|
2437
|
+
const getLookAhead = (0, import_react17.useCallback)(() => {
|
|
4198
2438
|
var _a2, _b2;
|
|
4199
2439
|
return (_b2 = (_a2 = engineRef.current) == null ? void 0 : _a2.lookAhead) != null ? _b2 : 0;
|
|
4200
2440
|
}, []);
|
|
4201
|
-
const
|
|
2441
|
+
const getOutputLatency = (0, import_react17.useCallback)(() => {
|
|
2442
|
+
var _a2;
|
|
2443
|
+
const audioCtx = (_a2 = adapterRef.current) == null ? void 0 : _a2.audioContext;
|
|
2444
|
+
return audioCtx && "outputLatency" in audioCtx ? audioCtx.outputLatency : 0;
|
|
2445
|
+
}, []);
|
|
2446
|
+
const registerFrameCallback = (0, import_react17.useCallback)((id, cb) => {
|
|
4202
2447
|
frameCallbacksRef.current.set(id, cb);
|
|
4203
2448
|
}, []);
|
|
4204
|
-
const unregisterFrameCallback = (0,
|
|
2449
|
+
const unregisterFrameCallback = (0, import_react17.useCallback)((id) => {
|
|
4205
2450
|
frameCallbacksRef.current.delete(id);
|
|
4206
2451
|
}, []);
|
|
4207
|
-
const startAnimationLoop = (0,
|
|
2452
|
+
const startAnimationLoop = (0, import_react17.useCallback)(() => {
|
|
4208
2453
|
const updateTime = () => {
|
|
4209
2454
|
const time = getPlaybackTime();
|
|
4210
2455
|
currentTimeRef.current = time;
|
|
@@ -4292,15 +2537,14 @@ var WaveformPlaylistProvider = ({
|
|
|
4292
2537
|
setCurrentTimeRefs
|
|
4293
2538
|
]);
|
|
4294
2539
|
const stopAnimationLoop = stopAnimationFrameLoop;
|
|
4295
|
-
(0,
|
|
2540
|
+
(0, import_react17.useEffect)(() => {
|
|
4296
2541
|
const reschedulePlayback = () => __async(null, null, function* () {
|
|
4297
2542
|
if (isPlaying && animationFrameRef.current && engineRef.current) {
|
|
4298
2543
|
if (continuousPlay) {
|
|
4299
2544
|
const currentPos = currentTimeRef.current;
|
|
4300
2545
|
engineRef.current.stop();
|
|
4301
2546
|
stopAnimationLoop();
|
|
4302
|
-
const
|
|
4303
|
-
const timeNow = context.currentTime;
|
|
2547
|
+
const timeNow = getAudioContextTime();
|
|
4304
2548
|
playbackStartTimeRef.current = timeNow;
|
|
4305
2549
|
audioStartPositionRef.current = currentPos;
|
|
4306
2550
|
engineRef.current.play(currentPos);
|
|
@@ -4316,14 +2560,20 @@ var WaveformPlaylistProvider = ({
|
|
|
4316
2560
|
setIsPlaying(false);
|
|
4317
2561
|
stopAnimationLoop();
|
|
4318
2562
|
});
|
|
4319
|
-
}, [
|
|
4320
|
-
|
|
2563
|
+
}, [
|
|
2564
|
+
continuousPlay,
|
|
2565
|
+
isPlaying,
|
|
2566
|
+
startAnimationLoop,
|
|
2567
|
+
stopAnimationLoop,
|
|
2568
|
+
animationFrameRef,
|
|
2569
|
+
getAudioContextTime
|
|
2570
|
+
]);
|
|
2571
|
+
(0, import_react17.useEffect)(() => {
|
|
4321
2572
|
const resumePlayback = () => __async(null, null, function* () {
|
|
4322
2573
|
if (pendingResumeRef.current && engineRef.current) {
|
|
4323
2574
|
const { position } = pendingResumeRef.current;
|
|
4324
2575
|
pendingResumeRef.current = null;
|
|
4325
|
-
const
|
|
4326
|
-
const timeNow = context.currentTime;
|
|
2576
|
+
const timeNow = getAudioContextTime();
|
|
4327
2577
|
playbackStartTimeRef.current = timeNow;
|
|
4328
2578
|
audioStartPositionRef.current = position;
|
|
4329
2579
|
if (!audioInitializedRef.current) {
|
|
@@ -4340,8 +2590,8 @@ var WaveformPlaylistProvider = ({
|
|
|
4340
2590
|
setIsPlaying(false);
|
|
4341
2591
|
stopAnimationLoop();
|
|
4342
2592
|
});
|
|
4343
|
-
}, [tracks, startAnimationLoop, stopAnimationLoop]);
|
|
4344
|
-
const play = (0,
|
|
2593
|
+
}, [tracks, startAnimationLoop, stopAnimationLoop, getAudioContextTime]);
|
|
2594
|
+
const play = (0, import_react17.useCallback)(
|
|
4345
2595
|
(startTime, playDuration) => __async(null, null, function* () {
|
|
4346
2596
|
if (!engineRef.current) return;
|
|
4347
2597
|
const actualStartTime = startTime != null ? startTime : currentTimeRef.current;
|
|
@@ -4350,8 +2600,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4350
2600
|
engineRef.current.stop();
|
|
4351
2601
|
engineRef.current.seek(actualStartTime);
|
|
4352
2602
|
stopAnimationLoop();
|
|
4353
|
-
const
|
|
4354
|
-
const startTimeNow = context.currentTime;
|
|
2603
|
+
const startTimeNow = getAudioContextTime();
|
|
4355
2604
|
playbackStartTimeRef.current = startTimeNow;
|
|
4356
2605
|
audioStartPositionRef.current = actualStartTime;
|
|
4357
2606
|
playbackEndTimeRef.current = playDuration !== void 0 ? actualStartTime + playDuration : null;
|
|
@@ -4370,9 +2619,9 @@ var WaveformPlaylistProvider = ({
|
|
|
4370
2619
|
setIsPlaying(true);
|
|
4371
2620
|
startAnimationLoop();
|
|
4372
2621
|
}),
|
|
4373
|
-
[startAnimationLoop, stopAnimationLoop, setCurrentTimeRefs]
|
|
2622
|
+
[startAnimationLoop, stopAnimationLoop, setCurrentTimeRefs, getAudioContextTime]
|
|
4374
2623
|
);
|
|
4375
|
-
const pause = (0,
|
|
2624
|
+
const pause = (0, import_react17.useCallback)(() => {
|
|
4376
2625
|
if (!engineRef.current) return;
|
|
4377
2626
|
const pauseTime = getPlaybackTime();
|
|
4378
2627
|
engineRef.current.pause();
|
|
@@ -4381,7 +2630,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4381
2630
|
setCurrentTimeRefs(pauseTime);
|
|
4382
2631
|
setCurrentTime(pauseTime);
|
|
4383
2632
|
}, [stopAnimationLoop, getPlaybackTime, setCurrentTimeRefs]);
|
|
4384
|
-
const stop = (0,
|
|
2633
|
+
const stop = (0, import_react17.useCallback)(() => {
|
|
4385
2634
|
if (!engineRef.current) return;
|
|
4386
2635
|
engineRef.current.stop();
|
|
4387
2636
|
setIsPlaying(false);
|
|
@@ -4390,7 +2639,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4390
2639
|
setCurrentTime(playStartPositionRef.current);
|
|
4391
2640
|
setActiveAnnotationId(null);
|
|
4392
2641
|
}, [stopAnimationLoop, setActiveAnnotationId, setCurrentTimeRefs]);
|
|
4393
|
-
const seekTo = (0,
|
|
2642
|
+
const seekTo = (0, import_react17.useCallback)(
|
|
4394
2643
|
(time) => {
|
|
4395
2644
|
const clampedTime = Math.max(0, Math.min(time, duration));
|
|
4396
2645
|
setCurrentTimeRefs(clampedTime);
|
|
@@ -4401,7 +2650,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4401
2650
|
},
|
|
4402
2651
|
[duration, isPlaying, play, setCurrentTimeRefs]
|
|
4403
2652
|
);
|
|
4404
|
-
const setTrackMute = (0,
|
|
2653
|
+
const setTrackMute = (0, import_react17.useCallback)(
|
|
4405
2654
|
(trackIndex, muted) => {
|
|
4406
2655
|
var _a2;
|
|
4407
2656
|
const trackId = (_a2 = tracksRef.current[trackIndex]) == null ? void 0 : _a2.id;
|
|
@@ -4415,7 +2664,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4415
2664
|
},
|
|
4416
2665
|
[trackStates]
|
|
4417
2666
|
);
|
|
4418
|
-
const setTrackSolo = (0,
|
|
2667
|
+
const setTrackSolo = (0, import_react17.useCallback)(
|
|
4419
2668
|
(trackIndex, soloed) => {
|
|
4420
2669
|
var _a2;
|
|
4421
2670
|
const trackId = (_a2 = tracksRef.current[trackIndex]) == null ? void 0 : _a2.id;
|
|
@@ -4429,7 +2678,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4429
2678
|
},
|
|
4430
2679
|
[trackStates]
|
|
4431
2680
|
);
|
|
4432
|
-
const setTrackVolume = (0,
|
|
2681
|
+
const setTrackVolume = (0, import_react17.useCallback)(
|
|
4433
2682
|
(trackIndex, volume2) => {
|
|
4434
2683
|
var _a2;
|
|
4435
2684
|
const trackId = (_a2 = tracksRef.current[trackIndex]) == null ? void 0 : _a2.id;
|
|
@@ -4443,7 +2692,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4443
2692
|
},
|
|
4444
2693
|
[trackStates]
|
|
4445
2694
|
);
|
|
4446
|
-
const setTrackPan = (0,
|
|
2695
|
+
const setTrackPan = (0, import_react17.useCallback)(
|
|
4447
2696
|
(trackIndex, pan) => {
|
|
4448
2697
|
var _a2;
|
|
4449
2698
|
const trackId = (_a2 = tracksRef.current[trackIndex]) == null ? void 0 : _a2.id;
|
|
@@ -4457,7 +2706,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4457
2706
|
},
|
|
4458
2707
|
[trackStates]
|
|
4459
2708
|
);
|
|
4460
|
-
const setSelection = (0,
|
|
2709
|
+
const setSelection = (0, import_react17.useCallback)(
|
|
4461
2710
|
(start, end) => {
|
|
4462
2711
|
setSelectionEngine(start, end);
|
|
4463
2712
|
setCurrentTimeRefs(start);
|
|
@@ -4470,12 +2719,12 @@ var WaveformPlaylistProvider = ({
|
|
|
4470
2719
|
},
|
|
4471
2720
|
[isPlaying, setSelectionEngine, setCurrentTimeRefs]
|
|
4472
2721
|
);
|
|
4473
|
-
const setScrollContainer = (0,
|
|
2722
|
+
const setScrollContainer = (0, import_react17.useCallback)((element) => {
|
|
4474
2723
|
scrollContainerRef.current = element;
|
|
4475
2724
|
}, []);
|
|
4476
|
-
const onAnnotationsChangeRef = (0,
|
|
2725
|
+
const onAnnotationsChangeRef = (0, import_react17.useRef)(onAnnotationsChange);
|
|
4477
2726
|
onAnnotationsChangeRef.current = onAnnotationsChange;
|
|
4478
|
-
const setAnnotations = (0,
|
|
2727
|
+
const setAnnotations = (0, import_react17.useCallback)(
|
|
4479
2728
|
(action) => {
|
|
4480
2729
|
const updated = typeof action === "function" ? action(annotationsRef.current) : action;
|
|
4481
2730
|
if (!onAnnotationsChangeRef.current) {
|
|
@@ -4493,7 +2742,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4493
2742
|
const sampleRate = sampleRateRef.current;
|
|
4494
2743
|
const timeScaleHeight = timescale ? 30 : 0;
|
|
4495
2744
|
const minimumPlaylistHeight = tracks.length * waveHeight + timeScaleHeight;
|
|
4496
|
-
const animationValue = (0,
|
|
2745
|
+
const animationValue = (0, import_react17.useMemo)(
|
|
4497
2746
|
() => ({
|
|
4498
2747
|
isPlaying,
|
|
4499
2748
|
currentTime,
|
|
@@ -4502,7 +2751,9 @@ var WaveformPlaylistProvider = ({
|
|
|
4502
2751
|
playbackStartTimeRef,
|
|
4503
2752
|
audioStartPositionRef,
|
|
4504
2753
|
getPlaybackTime,
|
|
2754
|
+
getAudioContextTime,
|
|
4505
2755
|
getLookAhead,
|
|
2756
|
+
getOutputLatency,
|
|
4506
2757
|
registerFrameCallback,
|
|
4507
2758
|
unregisterFrameCallback
|
|
4508
2759
|
}),
|
|
@@ -4514,12 +2765,14 @@ var WaveformPlaylistProvider = ({
|
|
|
4514
2765
|
playbackStartTimeRef,
|
|
4515
2766
|
audioStartPositionRef,
|
|
4516
2767
|
getPlaybackTime,
|
|
2768
|
+
getAudioContextTime,
|
|
4517
2769
|
getLookAhead,
|
|
2770
|
+
getOutputLatency,
|
|
4518
2771
|
registerFrameCallback,
|
|
4519
2772
|
unregisterFrameCallback
|
|
4520
2773
|
]
|
|
4521
2774
|
);
|
|
4522
|
-
const stateValue = (0,
|
|
2775
|
+
const stateValue = (0, import_react17.useMemo)(
|
|
4523
2776
|
() => ({
|
|
4524
2777
|
continuousPlay,
|
|
4525
2778
|
linkEndpoints,
|
|
@@ -4555,17 +2808,17 @@ var WaveformPlaylistProvider = ({
|
|
|
4555
2808
|
canRedo
|
|
4556
2809
|
]
|
|
4557
2810
|
);
|
|
4558
|
-
const setCurrentTimeControl = (0,
|
|
2811
|
+
const setCurrentTimeControl = (0, import_react17.useCallback)(
|
|
4559
2812
|
(time) => {
|
|
4560
2813
|
setCurrentTimeRefs(time);
|
|
4561
2814
|
setCurrentTime(time);
|
|
4562
2815
|
},
|
|
4563
2816
|
[setCurrentTimeRefs]
|
|
4564
2817
|
);
|
|
4565
|
-
const setAutomaticScrollControl = (0,
|
|
2818
|
+
const setAutomaticScrollControl = (0, import_react17.useCallback)((enabled) => {
|
|
4566
2819
|
setIsAutomaticScroll(enabled);
|
|
4567
2820
|
}, []);
|
|
4568
|
-
const controlsValue = (0,
|
|
2821
|
+
const controlsValue = (0, import_react17.useMemo)(
|
|
4569
2822
|
() => ({
|
|
4570
2823
|
// Playback controls
|
|
4571
2824
|
play,
|
|
@@ -4641,7 +2894,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4641
2894
|
redo
|
|
4642
2895
|
]
|
|
4643
2896
|
);
|
|
4644
|
-
const dataValue = (0,
|
|
2897
|
+
const dataValue = (0, import_react17.useMemo)(
|
|
4645
2898
|
() => ({
|
|
4646
2899
|
duration,
|
|
4647
2900
|
audioBuffers,
|
|
@@ -4697,45 +2950,69 @@ var WaveformPlaylistProvider = ({
|
|
|
4697
2950
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_styled_components.ThemeProvider, { theme: mergedTheme, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlaybackAnimationContext.Provider, { value: animationValue, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlaylistStateContext.Provider, { value: stateValue, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlaylistControlsContext.Provider, { value: controlsValue, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlaylistDataContext.Provider, { value: dataValue, children }) }) }) }) });
|
|
4698
2951
|
};
|
|
4699
2952
|
var usePlaybackAnimation = () => {
|
|
4700
|
-
const context = (0,
|
|
2953
|
+
const context = (0, import_react17.useContext)(PlaybackAnimationContext);
|
|
4701
2954
|
if (!context) {
|
|
4702
2955
|
throw new Error("usePlaybackAnimation must be used within WaveformPlaylistProvider");
|
|
4703
2956
|
}
|
|
4704
2957
|
return context;
|
|
4705
2958
|
};
|
|
4706
2959
|
var usePlaylistState = () => {
|
|
4707
|
-
const context = (0,
|
|
2960
|
+
const context = (0, import_react17.useContext)(PlaylistStateContext);
|
|
4708
2961
|
if (!context) {
|
|
4709
2962
|
throw new Error("usePlaylistState must be used within WaveformPlaylistProvider");
|
|
4710
2963
|
}
|
|
4711
2964
|
return context;
|
|
4712
2965
|
};
|
|
4713
2966
|
var usePlaylistControls = () => {
|
|
4714
|
-
const context = (0,
|
|
2967
|
+
const context = (0, import_react17.useContext)(PlaylistControlsContext);
|
|
4715
2968
|
if (!context) {
|
|
4716
2969
|
throw new Error("usePlaylistControls must be used within WaveformPlaylistProvider");
|
|
4717
2970
|
}
|
|
4718
2971
|
return context;
|
|
4719
2972
|
};
|
|
4720
2973
|
var usePlaylistData = () => {
|
|
4721
|
-
const context = (0,
|
|
2974
|
+
const context = (0, import_react17.useContext)(PlaylistDataContext);
|
|
4722
2975
|
if (!context) {
|
|
4723
2976
|
throw new Error("usePlaylistData must be used within WaveformPlaylistProvider");
|
|
4724
2977
|
}
|
|
4725
2978
|
return context;
|
|
4726
2979
|
};
|
|
4727
|
-
var usePlaylistDataOptional = () => (0,
|
|
2980
|
+
var usePlaylistDataOptional = () => (0, import_react17.useContext)(PlaylistDataContext);
|
|
4728
2981
|
|
|
4729
2982
|
// src/MediaElementPlaylistContext.tsx
|
|
4730
|
-
var
|
|
2983
|
+
var import_react18 = require("react");
|
|
4731
2984
|
var import_styled_components2 = require("styled-components");
|
|
4732
|
-
|
|
2985
|
+
|
|
2986
|
+
// src/playout/resolveMediaElementPlayout.ts
|
|
2987
|
+
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`.";
|
|
2988
|
+
function resolveMediaElementPlayout(opts) {
|
|
2989
|
+
return __async(this, null, function* () {
|
|
2990
|
+
if (opts.createPlayout) {
|
|
2991
|
+
return opts.createPlayout();
|
|
2992
|
+
}
|
|
2993
|
+
let mod;
|
|
2994
|
+
try {
|
|
2995
|
+
mod = yield import("@waveform-playlist/media-element-playout");
|
|
2996
|
+
} catch (originalErr) {
|
|
2997
|
+
console.warn(
|
|
2998
|
+
"[waveform-playlist] @waveform-playlist/media-element-playout dynamic import failed: " + String(originalErr)
|
|
2999
|
+
);
|
|
3000
|
+
throw new Error(INSTALL_HINT2);
|
|
3001
|
+
}
|
|
3002
|
+
return new mod.MediaElementPlayout({
|
|
3003
|
+
playbackRate: opts.playbackRate,
|
|
3004
|
+
preservesPitch: opts.preservesPitch
|
|
3005
|
+
});
|
|
3006
|
+
});
|
|
3007
|
+
}
|
|
3008
|
+
|
|
3009
|
+
// src/MediaElementPlaylistContext.tsx
|
|
4733
3010
|
var import_ui_components3 = require("@waveform-playlist/ui-components");
|
|
4734
3011
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
4735
|
-
var MediaElementAnimationContext = (0,
|
|
4736
|
-
var MediaElementStateContext = (0,
|
|
4737
|
-
var MediaElementControlsContext = (0,
|
|
4738
|
-
var MediaElementDataContext = (0,
|
|
3012
|
+
var MediaElementAnimationContext = (0, import_react18.createContext)(null);
|
|
3013
|
+
var MediaElementStateContext = (0, import_react18.createContext)(null);
|
|
3014
|
+
var MediaElementControlsContext = (0, import_react18.createContext)(null);
|
|
3015
|
+
var MediaElementDataContext = (0, import_react18.createContext)(null);
|
|
4739
3016
|
var MediaElementPlaylistProvider = ({
|
|
4740
3017
|
track,
|
|
4741
3018
|
samplesPerPixel: initialSamplesPerPixel = 1024,
|
|
@@ -4753,16 +3030,18 @@ var MediaElementPlaylistProvider = ({
|
|
|
4753
3030
|
audioContext,
|
|
4754
3031
|
onAnnotationsChange,
|
|
4755
3032
|
onReady,
|
|
3033
|
+
onError,
|
|
3034
|
+
createPlayout,
|
|
4756
3035
|
children
|
|
4757
3036
|
}) => {
|
|
4758
3037
|
var _a;
|
|
4759
3038
|
const progressBarWidth = progressBarWidthProp != null ? progressBarWidthProp : barWidth + barGap;
|
|
4760
|
-
const [isPlaying, setIsPlaying] = (0,
|
|
4761
|
-
const [currentTime, setCurrentTime] = (0,
|
|
4762
|
-
const [duration, setDuration] = (0,
|
|
4763
|
-
const [peaksDataArray, setPeaksDataArray] = (0,
|
|
4764
|
-
const [playbackRate, setPlaybackRateState] = (0,
|
|
4765
|
-
const annotations = (0,
|
|
3039
|
+
const [isPlaying, setIsPlaying] = (0, import_react18.useState)(false);
|
|
3040
|
+
const [currentTime, setCurrentTime] = (0, import_react18.useState)(0);
|
|
3041
|
+
const [duration, setDuration] = (0, import_react18.useState)(0);
|
|
3042
|
+
const [peaksDataArray, setPeaksDataArray] = (0, import_react18.useState)([]);
|
|
3043
|
+
const [playbackRate, setPlaybackRateState] = (0, import_react18.useState)(initialPlaybackRate);
|
|
3044
|
+
const annotations = (0, import_react18.useMemo)(() => {
|
|
4766
3045
|
if (!(annotationList == null ? void 0 : annotationList.annotations)) return [];
|
|
4767
3046
|
if (process.env.NODE_ENV !== "production" && annotationList.annotations.length > 0) {
|
|
4768
3047
|
const first = annotationList.annotations[0];
|
|
@@ -4775,73 +3054,92 @@ var MediaElementPlaylistProvider = ({
|
|
|
4775
3054
|
}
|
|
4776
3055
|
return annotationList.annotations;
|
|
4777
3056
|
}, [annotationList == null ? void 0 : annotationList.annotations]);
|
|
4778
|
-
const annotationsRef = (0,
|
|
3057
|
+
const annotationsRef = (0, import_react18.useRef)(annotations);
|
|
4779
3058
|
annotationsRef.current = annotations;
|
|
4780
|
-
const [activeAnnotationId, setActiveAnnotationIdState] = (0,
|
|
4781
|
-
const [continuousPlay, setContinuousPlayState] = (0,
|
|
3059
|
+
const [activeAnnotationId, setActiveAnnotationIdState] = (0, import_react18.useState)(null);
|
|
3060
|
+
const [continuousPlay, setContinuousPlayState] = (0, import_react18.useState)(
|
|
4782
3061
|
(_a = annotationList == null ? void 0 : annotationList.isContinuousPlay) != null ? _a : false
|
|
4783
3062
|
);
|
|
4784
|
-
const [samplesPerPixel] = (0,
|
|
4785
|
-
const [isAutomaticScroll, setIsAutomaticScroll] = (0,
|
|
4786
|
-
const playoutRef = (0,
|
|
4787
|
-
const currentTimeRef = (0,
|
|
4788
|
-
const continuousPlayRef = (0,
|
|
4789
|
-
const activeAnnotationIdRef = (0,
|
|
4790
|
-
const scrollContainerRef = (0,
|
|
4791
|
-
const isAutomaticScrollRef = (0,
|
|
4792
|
-
const samplesPerPixelRef = (0,
|
|
3063
|
+
const [samplesPerPixel] = (0, import_react18.useState)(initialSamplesPerPixel);
|
|
3064
|
+
const [isAutomaticScroll, setIsAutomaticScroll] = (0, import_react18.useState)(automaticScroll);
|
|
3065
|
+
const playoutRef = (0, import_react18.useRef)(null);
|
|
3066
|
+
const currentTimeRef = (0, import_react18.useRef)(0);
|
|
3067
|
+
const continuousPlayRef = (0, import_react18.useRef)(continuousPlay);
|
|
3068
|
+
const activeAnnotationIdRef = (0, import_react18.useRef)(null);
|
|
3069
|
+
const scrollContainerRef = (0, import_react18.useRef)(null);
|
|
3070
|
+
const isAutomaticScrollRef = (0, import_react18.useRef)(automaticScroll);
|
|
3071
|
+
const samplesPerPixelRef = (0, import_react18.useRef)(initialSamplesPerPixel);
|
|
4793
3072
|
const { startAnimationFrameLoop, stopAnimationFrameLoop } = useAnimationFrameLoop();
|
|
4794
|
-
(0,
|
|
3073
|
+
(0, import_react18.useEffect)(() => {
|
|
4795
3074
|
continuousPlayRef.current = continuousPlay;
|
|
4796
3075
|
}, [continuousPlay]);
|
|
4797
|
-
(0,
|
|
3076
|
+
(0, import_react18.useEffect)(() => {
|
|
4798
3077
|
isAutomaticScrollRef.current = isAutomaticScroll;
|
|
4799
3078
|
}, [isAutomaticScroll]);
|
|
4800
|
-
const setActiveAnnotationId = (0,
|
|
3079
|
+
const setActiveAnnotationId = (0, import_react18.useCallback)((value) => {
|
|
4801
3080
|
activeAnnotationIdRef.current = value;
|
|
4802
3081
|
setActiveAnnotationIdState(value);
|
|
4803
3082
|
}, []);
|
|
4804
|
-
const setContinuousPlay = (0,
|
|
3083
|
+
const setContinuousPlay = (0, import_react18.useCallback)((value) => {
|
|
4805
3084
|
continuousPlayRef.current = value;
|
|
4806
3085
|
setContinuousPlayState(value);
|
|
4807
3086
|
}, []);
|
|
4808
|
-
const setScrollContainer = (0,
|
|
3087
|
+
const setScrollContainer = (0, import_react18.useCallback)((element) => {
|
|
4809
3088
|
scrollContainerRef.current = element;
|
|
4810
3089
|
}, []);
|
|
4811
3090
|
const sampleRate = track.waveformData.sample_rate;
|
|
4812
|
-
(0,
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
3091
|
+
(0, import_react18.useEffect)(() => {
|
|
3092
|
+
let cancelled = false;
|
|
3093
|
+
let createdPlayout = null;
|
|
3094
|
+
(() => __async(null, null, function* () {
|
|
3095
|
+
var _a2, _b;
|
|
3096
|
+
try {
|
|
3097
|
+
const playout = yield resolveMediaElementPlayout({
|
|
3098
|
+
createPlayout,
|
|
3099
|
+
playbackRate: initialPlaybackRate,
|
|
3100
|
+
preservesPitch
|
|
3101
|
+
});
|
|
3102
|
+
if (cancelled) {
|
|
3103
|
+
playout.dispose();
|
|
3104
|
+
return;
|
|
3105
|
+
}
|
|
3106
|
+
createdPlayout = playout;
|
|
3107
|
+
playout.addTrack({
|
|
3108
|
+
source: track.source,
|
|
3109
|
+
peaks: track.waveformData,
|
|
3110
|
+
name: track.name,
|
|
3111
|
+
audioContext,
|
|
3112
|
+
fadeIn: track.fadeIn,
|
|
3113
|
+
fadeOut: track.fadeOut
|
|
3114
|
+
});
|
|
3115
|
+
const mediaTrack = playout.getTrack((_b = (_a2 = playout["track"]) == null ? void 0 : _a2.id) != null ? _b : "");
|
|
3116
|
+
if (mediaTrack) {
|
|
3117
|
+
mediaTrack.setOnTimeUpdateCallback((time) => {
|
|
3118
|
+
currentTimeRef.current = time;
|
|
3119
|
+
});
|
|
3120
|
+
}
|
|
3121
|
+
playout.setOnPlaybackComplete(() => {
|
|
3122
|
+
stopAnimationFrameLoop();
|
|
3123
|
+
setIsPlaying(false);
|
|
3124
|
+
setActiveAnnotationId(null);
|
|
3125
|
+
currentTimeRef.current = 0;
|
|
3126
|
+
setCurrentTime(0);
|
|
3127
|
+
});
|
|
3128
|
+
playoutRef.current = playout;
|
|
3129
|
+
setDuration(track.waveformData.duration);
|
|
3130
|
+
onReady == null ? void 0 : onReady();
|
|
3131
|
+
} catch (err) {
|
|
3132
|
+
console.warn("[waveform-playlist] MediaElement playout init failed: " + String(err));
|
|
3133
|
+
onError == null ? void 0 : onError(err instanceof Error ? err : new Error(String(err)));
|
|
3134
|
+
}
|
|
3135
|
+
}))();
|
|
4842
3136
|
return () => {
|
|
3137
|
+
cancelled = true;
|
|
4843
3138
|
stopAnimationFrameLoop();
|
|
4844
|
-
|
|
3139
|
+
if (createdPlayout) {
|
|
3140
|
+
createdPlayout.dispose();
|
|
3141
|
+
}
|
|
3142
|
+
playoutRef.current = null;
|
|
4845
3143
|
};
|
|
4846
3144
|
}, [
|
|
4847
3145
|
track.source,
|
|
@@ -4853,10 +3151,12 @@ var MediaElementPlaylistProvider = ({
|
|
|
4853
3151
|
initialPlaybackRate,
|
|
4854
3152
|
preservesPitch,
|
|
4855
3153
|
onReady,
|
|
3154
|
+
onError,
|
|
4856
3155
|
stopAnimationFrameLoop,
|
|
4857
|
-
setActiveAnnotationId
|
|
3156
|
+
setActiveAnnotationId,
|
|
3157
|
+
createPlayout
|
|
4858
3158
|
]);
|
|
4859
|
-
(0,
|
|
3159
|
+
(0, import_react18.useEffect)(() => {
|
|
4860
3160
|
var _a2;
|
|
4861
3161
|
try {
|
|
4862
3162
|
const extractedPeaks = extractPeaksFromWaveformData(
|
|
@@ -4885,7 +3185,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4885
3185
|
console.warn("[waveform-playlist] Failed to extract peaks from waveform data:", err);
|
|
4886
3186
|
}
|
|
4887
3187
|
}, [track.waveformData, track.name, samplesPerPixel, sampleRate]);
|
|
4888
|
-
const startAnimationLoop = (0,
|
|
3188
|
+
const startAnimationLoop = (0, import_react18.useCallback)(() => {
|
|
4889
3189
|
const updateTime = () => {
|
|
4890
3190
|
var _a2, _b, _c;
|
|
4891
3191
|
const time = (_b = (_a2 = playoutRef.current) == null ? void 0 : _a2.getCurrentTime()) != null ? _b : 0;
|
|
@@ -4928,7 +3228,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4928
3228
|
startAnimationFrameLoop(updateTime);
|
|
4929
3229
|
}, [setActiveAnnotationId, sampleRate, startAnimationFrameLoop]);
|
|
4930
3230
|
const stopAnimationLoop = stopAnimationFrameLoop;
|
|
4931
|
-
const play = (0,
|
|
3231
|
+
const play = (0, import_react18.useCallback)(
|
|
4932
3232
|
(startTime) => {
|
|
4933
3233
|
if (!playoutRef.current) return;
|
|
4934
3234
|
const actualStartTime = startTime != null ? startTime : currentTimeRef.current;
|
|
@@ -4938,14 +3238,14 @@ var MediaElementPlaylistProvider = ({
|
|
|
4938
3238
|
},
|
|
4939
3239
|
[startAnimationLoop]
|
|
4940
3240
|
);
|
|
4941
|
-
const pause = (0,
|
|
3241
|
+
const pause = (0, import_react18.useCallback)(() => {
|
|
4942
3242
|
if (!playoutRef.current) return;
|
|
4943
3243
|
playoutRef.current.pause();
|
|
4944
3244
|
setIsPlaying(false);
|
|
4945
3245
|
stopAnimationLoop();
|
|
4946
3246
|
setCurrentTime(playoutRef.current.getCurrentTime());
|
|
4947
3247
|
}, [stopAnimationLoop]);
|
|
4948
|
-
const stop = (0,
|
|
3248
|
+
const stop = (0, import_react18.useCallback)(() => {
|
|
4949
3249
|
if (!playoutRef.current) return;
|
|
4950
3250
|
playoutRef.current.stop();
|
|
4951
3251
|
setIsPlaying(false);
|
|
@@ -4954,7 +3254,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4954
3254
|
setCurrentTime(0);
|
|
4955
3255
|
setActiveAnnotationId(null);
|
|
4956
3256
|
}, [stopAnimationLoop, setActiveAnnotationId]);
|
|
4957
|
-
const seekTo = (0,
|
|
3257
|
+
const seekTo = (0, import_react18.useCallback)(
|
|
4958
3258
|
(time) => {
|
|
4959
3259
|
const clampedTime = Math.max(0, Math.min(time, duration));
|
|
4960
3260
|
currentTimeRef.current = clampedTime;
|
|
@@ -4965,7 +3265,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4965
3265
|
},
|
|
4966
3266
|
[duration]
|
|
4967
3267
|
);
|
|
4968
|
-
const setPlaybackRate = (0,
|
|
3268
|
+
const setPlaybackRate = (0, import_react18.useCallback)((rate) => {
|
|
4969
3269
|
const clampedRate = Math.max(0.5, Math.min(2, rate));
|
|
4970
3270
|
setPlaybackRateState(clampedRate);
|
|
4971
3271
|
if (playoutRef.current) {
|
|
@@ -4973,7 +3273,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4973
3273
|
}
|
|
4974
3274
|
}, []);
|
|
4975
3275
|
const timeScaleHeight = timescale ? 30 : 0;
|
|
4976
|
-
const animationValue = (0,
|
|
3276
|
+
const animationValue = (0, import_react18.useMemo)(
|
|
4977
3277
|
() => ({
|
|
4978
3278
|
isPlaying,
|
|
4979
3279
|
currentTime,
|
|
@@ -4981,7 +3281,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4981
3281
|
}),
|
|
4982
3282
|
[isPlaying, currentTime]
|
|
4983
3283
|
);
|
|
4984
|
-
const stateValue = (0,
|
|
3284
|
+
const stateValue = (0, import_react18.useMemo)(
|
|
4985
3285
|
() => ({
|
|
4986
3286
|
continuousPlay,
|
|
4987
3287
|
annotations,
|
|
@@ -4991,9 +3291,9 @@ var MediaElementPlaylistProvider = ({
|
|
|
4991
3291
|
}),
|
|
4992
3292
|
[continuousPlay, annotations, activeAnnotationId, playbackRate, isAutomaticScroll]
|
|
4993
3293
|
);
|
|
4994
|
-
const onAnnotationsChangeRef = (0,
|
|
3294
|
+
const onAnnotationsChangeRef = (0, import_react18.useRef)(onAnnotationsChange);
|
|
4995
3295
|
onAnnotationsChangeRef.current = onAnnotationsChange;
|
|
4996
|
-
const setAnnotations = (0,
|
|
3296
|
+
const setAnnotations = (0, import_react18.useCallback)(
|
|
4997
3297
|
(action) => {
|
|
4998
3298
|
const updated = typeof action === "function" ? action(annotationsRef.current) : action;
|
|
4999
3299
|
if (!onAnnotationsChangeRef.current) {
|
|
@@ -5008,7 +3308,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
5008
3308
|
},
|
|
5009
3309
|
[]
|
|
5010
3310
|
);
|
|
5011
|
-
const controlsValue = (0,
|
|
3311
|
+
const controlsValue = (0, import_react18.useMemo)(
|
|
5012
3312
|
() => ({
|
|
5013
3313
|
play,
|
|
5014
3314
|
pause,
|
|
@@ -5036,7 +3336,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
5036
3336
|
setScrollContainer
|
|
5037
3337
|
]
|
|
5038
3338
|
);
|
|
5039
|
-
const dataValue = (0,
|
|
3339
|
+
const dataValue = (0, import_react18.useMemo)(
|
|
5040
3340
|
() => ({
|
|
5041
3341
|
duration,
|
|
5042
3342
|
peaksDataArray,
|
|
@@ -5071,28 +3371,28 @@ var MediaElementPlaylistProvider = ({
|
|
|
5071
3371
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_styled_components2.ThemeProvider, { theme: mergedTheme, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MediaElementAnimationContext.Provider, { value: animationValue, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MediaElementStateContext.Provider, { value: stateValue, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MediaElementControlsContext.Provider, { value: controlsValue, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MediaElementDataContext.Provider, { value: dataValue, children }) }) }) }) });
|
|
5072
3372
|
};
|
|
5073
3373
|
var useMediaElementAnimation = () => {
|
|
5074
|
-
const context = (0,
|
|
3374
|
+
const context = (0, import_react18.useContext)(MediaElementAnimationContext);
|
|
5075
3375
|
if (!context) {
|
|
5076
3376
|
throw new Error("useMediaElementAnimation must be used within MediaElementPlaylistProvider");
|
|
5077
3377
|
}
|
|
5078
3378
|
return context;
|
|
5079
3379
|
};
|
|
5080
3380
|
var useMediaElementState = () => {
|
|
5081
|
-
const context = (0,
|
|
3381
|
+
const context = (0, import_react18.useContext)(MediaElementStateContext);
|
|
5082
3382
|
if (!context) {
|
|
5083
3383
|
throw new Error("useMediaElementState must be used within MediaElementPlaylistProvider");
|
|
5084
3384
|
}
|
|
5085
3385
|
return context;
|
|
5086
3386
|
};
|
|
5087
3387
|
var useMediaElementControls = () => {
|
|
5088
|
-
const context = (0,
|
|
3388
|
+
const context = (0, import_react18.useContext)(MediaElementControlsContext);
|
|
5089
3389
|
if (!context) {
|
|
5090
3390
|
throw new Error("useMediaElementControls must be used within MediaElementPlaylistProvider");
|
|
5091
3391
|
}
|
|
5092
3392
|
return context;
|
|
5093
3393
|
};
|
|
5094
3394
|
var useMediaElementData = () => {
|
|
5095
|
-
const context = (0,
|
|
3395
|
+
const context = (0, import_react18.useContext)(MediaElementDataContext);
|
|
5096
3396
|
if (!context) {
|
|
5097
3397
|
throw new Error("useMediaElementData must be used within MediaElementPlaylistProvider");
|
|
5098
3398
|
}
|
|
@@ -5100,7 +3400,7 @@ var useMediaElementData = () => {
|
|
|
5100
3400
|
};
|
|
5101
3401
|
|
|
5102
3402
|
// src/components/PlaybackControls.tsx
|
|
5103
|
-
var
|
|
3403
|
+
var import_react19 = require("react");
|
|
5104
3404
|
var import_ui_components4 = require("@waveform-playlist/ui-components");
|
|
5105
3405
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
5106
3406
|
var PlayButton = ({ className }) => {
|
|
@@ -5236,7 +3536,7 @@ var ClearAllButton = ({
|
|
|
5236
3536
|
className
|
|
5237
3537
|
}) => {
|
|
5238
3538
|
const { stop } = usePlaylistControls();
|
|
5239
|
-
const handleClick = (0,
|
|
3539
|
+
const handleClick = (0, import_react19.useCallback)(() => {
|
|
5240
3540
|
stop();
|
|
5241
3541
|
onClearAll();
|
|
5242
3542
|
}, [stop, onClearAll]);
|
|
@@ -5264,7 +3564,7 @@ var ZoomOutButton = ({
|
|
|
5264
3564
|
};
|
|
5265
3565
|
|
|
5266
3566
|
// src/components/ContextualControls.tsx
|
|
5267
|
-
var
|
|
3567
|
+
var import_react20 = require("react");
|
|
5268
3568
|
var import_ui_components6 = require("@waveform-playlist/ui-components");
|
|
5269
3569
|
var import_styled_components3 = __toESM(require("styled-components"));
|
|
5270
3570
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
@@ -5297,10 +3597,10 @@ var PositionDisplay = import_styled_components3.default.span`
|
|
|
5297
3597
|
`;
|
|
5298
3598
|
var AudioPosition = ({ className }) => {
|
|
5299
3599
|
var _a;
|
|
5300
|
-
const timeRef = (0,
|
|
3600
|
+
const timeRef = (0, import_react20.useRef)(null);
|
|
5301
3601
|
const { isPlaying, currentTimeRef, registerFrameCallback, unregisterFrameCallback } = usePlaybackAnimation();
|
|
5302
3602
|
const { timeFormat: format } = usePlaylistData();
|
|
5303
|
-
(0,
|
|
3603
|
+
(0, import_react20.useEffect)(() => {
|
|
5304
3604
|
const id = "audio-position";
|
|
5305
3605
|
if (isPlaying) {
|
|
5306
3606
|
registerFrameCallback(id, ({ time }) => {
|
|
@@ -5311,7 +3611,7 @@ var AudioPosition = ({ className }) => {
|
|
|
5311
3611
|
}
|
|
5312
3612
|
return () => unregisterFrameCallback(id);
|
|
5313
3613
|
}, [isPlaying, format, registerFrameCallback, unregisterFrameCallback]);
|
|
5314
|
-
(0,
|
|
3614
|
+
(0, import_react20.useEffect)(() => {
|
|
5315
3615
|
var _a2;
|
|
5316
3616
|
if (!isPlaying && timeRef.current) {
|
|
5317
3617
|
timeRef.current.textContent = (0, import_ui_components6.formatTime)((_a2 = currentTimeRef.current) != null ? _a2 : 0, format);
|
|
@@ -5346,11 +3646,11 @@ var AutomaticScrollCheckbox = ({ className }) => {
|
|
|
5346
3646
|
};
|
|
5347
3647
|
|
|
5348
3648
|
// src/AnnotationIntegrationContext.tsx
|
|
5349
|
-
var
|
|
5350
|
-
var AnnotationIntegrationContext = (0,
|
|
3649
|
+
var import_react21 = require("react");
|
|
3650
|
+
var AnnotationIntegrationContext = (0, import_react21.createContext)(null);
|
|
5351
3651
|
var AnnotationIntegrationProvider = AnnotationIntegrationContext.Provider;
|
|
5352
3652
|
function useAnnotationIntegration() {
|
|
5353
|
-
const context = (0,
|
|
3653
|
+
const context = (0, import_react21.useContext)(AnnotationIntegrationContext);
|
|
5354
3654
|
if (!context) {
|
|
5355
3655
|
throw new Error(
|
|
5356
3656
|
"useAnnotationIntegration must be used within <AnnotationProvider>. Install @waveform-playlist/annotations and wrap your app with <AnnotationProvider>. See: https://waveform-playlist.naomiaro.com/docs/guides/annotations"
|
|
@@ -5388,73 +3688,25 @@ var DownloadAnnotationsButton = ({
|
|
|
5388
3688
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Base, { annotations, filename, className });
|
|
5389
3689
|
};
|
|
5390
3690
|
|
|
5391
|
-
// src/components/ExportControls.tsx
|
|
5392
|
-
var import_ui_components7 = require("@waveform-playlist/ui-components");
|
|
5393
|
-
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
5394
|
-
var ExportWavButton = ({
|
|
5395
|
-
label = "Export WAV",
|
|
5396
|
-
filename = "export",
|
|
5397
|
-
mode = "master",
|
|
5398
|
-
trackIndex,
|
|
5399
|
-
bitDepth = 16,
|
|
5400
|
-
applyEffects = true,
|
|
5401
|
-
effectsFunction,
|
|
5402
|
-
createOfflineTrackEffects,
|
|
5403
|
-
className,
|
|
5404
|
-
onExportComplete,
|
|
5405
|
-
onExportError
|
|
5406
|
-
}) => {
|
|
5407
|
-
const { tracks, trackStates } = usePlaylistData();
|
|
5408
|
-
const { exportWav, isExporting, progress } = useExportWav();
|
|
5409
|
-
const handleExport = () => __async(null, null, function* () {
|
|
5410
|
-
try {
|
|
5411
|
-
const result = yield exportWav(tracks, trackStates, {
|
|
5412
|
-
filename,
|
|
5413
|
-
mode,
|
|
5414
|
-
trackIndex,
|
|
5415
|
-
bitDepth,
|
|
5416
|
-
applyEffects,
|
|
5417
|
-
effectsFunction,
|
|
5418
|
-
createOfflineTrackEffects,
|
|
5419
|
-
autoDownload: true
|
|
5420
|
-
});
|
|
5421
|
-
onExportComplete == null ? void 0 : onExportComplete(result.blob);
|
|
5422
|
-
} catch (error) {
|
|
5423
|
-
onExportError == null ? void 0 : onExportError(error instanceof Error ? error : new Error("Export failed"));
|
|
5424
|
-
}
|
|
5425
|
-
});
|
|
5426
|
-
const buttonLabel = isExporting ? `Exporting ${Math.round(progress * 100)}%` : label;
|
|
5427
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
5428
|
-
import_ui_components7.BaseControlButton,
|
|
5429
|
-
{
|
|
5430
|
-
onClick: handleExport,
|
|
5431
|
-
disabled: isExporting || tracks.length === 0,
|
|
5432
|
-
className,
|
|
5433
|
-
children: buttonLabel
|
|
5434
|
-
}
|
|
5435
|
-
);
|
|
5436
|
-
};
|
|
5437
|
-
|
|
5438
3691
|
// src/contexts/ClipInteractionContext.tsx
|
|
5439
|
-
var
|
|
5440
|
-
var ClipInteractionContext = (0,
|
|
3692
|
+
var import_react22 = require("react");
|
|
3693
|
+
var ClipInteractionContext = (0, import_react22.createContext)(false);
|
|
5441
3694
|
var ClipInteractionContextProvider = ClipInteractionContext.Provider;
|
|
5442
3695
|
function useClipInteractionEnabled() {
|
|
5443
|
-
return (0,
|
|
3696
|
+
return (0, import_react22.useContext)(ClipInteractionContext);
|
|
5444
3697
|
}
|
|
5445
3698
|
|
|
5446
3699
|
// src/components/PlaylistVisualization.tsx
|
|
5447
|
-
var
|
|
3700
|
+
var import_react26 = require("react");
|
|
5448
3701
|
var import_react_dom = require("react-dom");
|
|
5449
3702
|
var import_styled_components6 = __toESM(require("styled-components"));
|
|
5450
|
-
var
|
|
5451
|
-
var
|
|
5452
|
-
var import_core8 = require("@waveform-playlist/core");
|
|
3703
|
+
var import_ui_components8 = require("@waveform-playlist/ui-components");
|
|
3704
|
+
var import_core4 = require("@waveform-playlist/core");
|
|
5453
3705
|
|
|
5454
3706
|
// src/components/AnimatedPlayhead.tsx
|
|
5455
|
-
var
|
|
3707
|
+
var import_react23 = require("react");
|
|
5456
3708
|
var import_styled_components4 = __toESM(require("styled-components"));
|
|
5457
|
-
var
|
|
3709
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
5458
3710
|
var PlayheadLine = import_styled_components4.default.div.attrs((props) => ({
|
|
5459
3711
|
style: {
|
|
5460
3712
|
width: `${props.$width}px`,
|
|
@@ -5470,7 +3722,7 @@ var PlayheadLine = import_styled_components4.default.div.attrs((props) => ({
|
|
|
5470
3722
|
will-change: transform;
|
|
5471
3723
|
`;
|
|
5472
3724
|
var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
5473
|
-
const playheadRef = (0,
|
|
3725
|
+
const playheadRef = (0, import_react23.useRef)(null);
|
|
5474
3726
|
const {
|
|
5475
3727
|
isPlaying,
|
|
5476
3728
|
currentTimeRef,
|
|
@@ -5479,7 +3731,7 @@ var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
|
5479
3731
|
unregisterFrameCallback
|
|
5480
3732
|
} = usePlaybackAnimation();
|
|
5481
3733
|
const { samplesPerPixel, sampleRate, progressBarWidth } = usePlaylistData();
|
|
5482
|
-
(0,
|
|
3734
|
+
(0, import_react23.useEffect)(() => {
|
|
5483
3735
|
const id = "playhead";
|
|
5484
3736
|
if (isPlaying) {
|
|
5485
3737
|
registerFrameCallback(id, ({ visualTime, sampleRate: sr, samplesPerPixel: spp }) => {
|
|
@@ -5491,7 +3743,7 @@ var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
|
5491
3743
|
}
|
|
5492
3744
|
return () => unregisterFrameCallback(id);
|
|
5493
3745
|
}, [isPlaying, registerFrameCallback, unregisterFrameCallback]);
|
|
5494
|
-
(0,
|
|
3746
|
+
(0, import_react23.useEffect)(() => {
|
|
5495
3747
|
var _a, _b;
|
|
5496
3748
|
if (!isPlaying && playheadRef.current) {
|
|
5497
3749
|
const time = (_b = (_a = visualTimeRef.current) != null ? _a : currentTimeRef.current) != null ? _b : 0;
|
|
@@ -5499,15 +3751,15 @@ var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
|
5499
3751
|
playheadRef.current.style.transform = `translate3d(${position}px, 0, 0)`;
|
|
5500
3752
|
}
|
|
5501
3753
|
});
|
|
5502
|
-
return /* @__PURE__ */ (0,
|
|
3754
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PlayheadLine, { ref: playheadRef, $color: color, $width: progressBarWidth, "data-playhead": true });
|
|
5503
3755
|
};
|
|
5504
3756
|
|
|
5505
3757
|
// src/components/ChannelWithProgress.tsx
|
|
5506
|
-
var
|
|
3758
|
+
var import_react24 = require("react");
|
|
5507
3759
|
var import_styled_components5 = __toESM(require("styled-components"));
|
|
5508
|
-
var
|
|
5509
|
-
var
|
|
5510
|
-
var
|
|
3760
|
+
var import_core3 = require("@waveform-playlist/core");
|
|
3761
|
+
var import_ui_components7 = require("@waveform-playlist/ui-components");
|
|
3762
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
5511
3763
|
var ChannelWrapper = import_styled_components5.default.div`
|
|
5512
3764
|
position: relative;
|
|
5513
3765
|
`;
|
|
@@ -5561,10 +3813,10 @@ var ChannelWithProgress = (_a) => {
|
|
|
5561
3813
|
"clipSampleRate",
|
|
5562
3814
|
"clipOffsetSeconds"
|
|
5563
3815
|
]);
|
|
5564
|
-
const progressRef = (0,
|
|
5565
|
-
const callbackId = (0,
|
|
5566
|
-
const theme = (0,
|
|
5567
|
-
const { waveHeight } = (0,
|
|
3816
|
+
const progressRef = (0, import_react24.useRef)(null);
|
|
3817
|
+
const callbackId = (0, import_react24.useId)();
|
|
3818
|
+
const theme = (0, import_ui_components7.useTheme)();
|
|
3819
|
+
const { waveHeight } = (0, import_ui_components7.usePlaylistInfo)();
|
|
5568
3820
|
const {
|
|
5569
3821
|
isPlaying,
|
|
5570
3822
|
currentTimeRef,
|
|
@@ -5574,12 +3826,12 @@ var ChannelWithProgress = (_a) => {
|
|
|
5574
3826
|
} = usePlaybackAnimation();
|
|
5575
3827
|
const { samplesPerPixel, sampleRate } = usePlaylistData();
|
|
5576
3828
|
const progressColor = (theme == null ? void 0 : theme.waveProgressColor) || "rgba(0, 0, 0, 0.1)";
|
|
5577
|
-
const clipPixelWidth = (0,
|
|
3829
|
+
const clipPixelWidth = (0, import_core3.clipPixelWidth)(
|
|
5578
3830
|
clipStartSample,
|
|
5579
3831
|
clipDurationSamples,
|
|
5580
3832
|
samplesPerPixel
|
|
5581
3833
|
);
|
|
5582
|
-
(0,
|
|
3834
|
+
(0, import_react24.useEffect)(() => {
|
|
5583
3835
|
if (isPlaying) {
|
|
5584
3836
|
registerFrameCallback(callbackId, ({ visualTime, sampleRate: sr }) => {
|
|
5585
3837
|
if (progressRef.current) {
|
|
@@ -5607,7 +3859,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5607
3859
|
registerFrameCallback,
|
|
5608
3860
|
unregisterFrameCallback
|
|
5609
3861
|
]);
|
|
5610
|
-
(0,
|
|
3862
|
+
(0, import_react24.useEffect)(() => {
|
|
5611
3863
|
var _a2, _b2;
|
|
5612
3864
|
if (!isPlaying && progressRef.current) {
|
|
5613
3865
|
const currentTime = (_b2 = (_a2 = visualTimeRef.current) != null ? _a2 : currentTimeRef.current) != null ? _b2 : 0;
|
|
@@ -5635,14 +3887,14 @@ var ChannelWithProgress = (_a) => {
|
|
|
5635
3887
|
const isSpectrogramMode = smartChannelProps.renderMode === "spectrogram" || smartChannelProps.renderMode === "both";
|
|
5636
3888
|
const isPianoRollMode = smartChannelProps.renderMode === "piano-roll";
|
|
5637
3889
|
const isBothMode = smartChannelProps.renderMode === "both";
|
|
5638
|
-
const backgroundCss = isSpectrogramMode ? "#000" : isPianoRollMode ? (theme == null ? void 0 : theme.pianoRollBackgroundColor) || "#1a1a2e" : (0,
|
|
3890
|
+
const backgroundCss = isSpectrogramMode ? "#000" : isPianoRollMode ? (theme == null ? void 0 : theme.pianoRollBackgroundColor) || "#1a1a2e" : (0, import_ui_components7.waveformColorToCss)(backgroundColor);
|
|
5639
3891
|
const halfHeight = Math.floor(waveHeight / 2);
|
|
5640
3892
|
const effectiveHeight = waveHeight;
|
|
5641
3893
|
const effectiveTop = isBothMode ? smartChannelProps.index * waveHeight : smartChannelProps.index * waveHeight;
|
|
5642
|
-
const waveformBackgroundCss = (0,
|
|
5643
|
-
return /* @__PURE__ */ (0,
|
|
5644
|
-
isBothMode ? /* @__PURE__ */ (0,
|
|
5645
|
-
/* @__PURE__ */ (0,
|
|
3894
|
+
const waveformBackgroundCss = (0, import_ui_components7.waveformColorToCss)(backgroundColor);
|
|
3895
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(ChannelWrapper, { children: [
|
|
3896
|
+
isBothMode ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
3897
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
5646
3898
|
Background,
|
|
5647
3899
|
{
|
|
5648
3900
|
$color: "#000",
|
|
@@ -5651,7 +3903,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5651
3903
|
$width: smartChannelProps.length
|
|
5652
3904
|
}
|
|
5653
3905
|
),
|
|
5654
|
-
/* @__PURE__ */ (0,
|
|
3906
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
5655
3907
|
Background,
|
|
5656
3908
|
{
|
|
5657
3909
|
$color: waveformBackgroundCss,
|
|
@@ -5660,7 +3912,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5660
3912
|
$width: smartChannelProps.length
|
|
5661
3913
|
}
|
|
5662
3914
|
)
|
|
5663
|
-
] }) : /* @__PURE__ */ (0,
|
|
3915
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
5664
3916
|
Background,
|
|
5665
3917
|
{
|
|
5666
3918
|
$color: backgroundCss,
|
|
@@ -5669,7 +3921,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5669
3921
|
$width: smartChannelProps.length
|
|
5670
3922
|
}
|
|
5671
3923
|
),
|
|
5672
|
-
!isPianoRollMode && /* @__PURE__ */ (0,
|
|
3924
|
+
!isPianoRollMode && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
5673
3925
|
ProgressOverlay,
|
|
5674
3926
|
{
|
|
5675
3927
|
ref: progressRef,
|
|
@@ -5679,8 +3931,8 @@ var ChannelWithProgress = (_a) => {
|
|
|
5679
3931
|
$width: clipPixelWidth
|
|
5680
3932
|
}
|
|
5681
3933
|
),
|
|
5682
|
-
/* @__PURE__ */ (0,
|
|
5683
|
-
|
|
3934
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ChannelContainer, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3935
|
+
import_ui_components7.SmartChannel,
|
|
5684
3936
|
__spreadProps(__spreadValues({}, smartChannelProps), {
|
|
5685
3937
|
transparentBackground: true,
|
|
5686
3938
|
midiNotes,
|
|
@@ -5692,11 +3944,11 @@ var ChannelWithProgress = (_a) => {
|
|
|
5692
3944
|
};
|
|
5693
3945
|
|
|
5694
3946
|
// src/SpectrogramIntegrationContext.tsx
|
|
5695
|
-
var
|
|
5696
|
-
var SpectrogramIntegrationContext = (0,
|
|
3947
|
+
var import_react25 = require("react");
|
|
3948
|
+
var SpectrogramIntegrationContext = (0, import_react25.createContext)(null);
|
|
5697
3949
|
var SpectrogramIntegrationProvider = SpectrogramIntegrationContext.Provider;
|
|
5698
3950
|
function useSpectrogramIntegration() {
|
|
5699
|
-
const context = (0,
|
|
3951
|
+
const context = (0, import_react25.useContext)(SpectrogramIntegrationContext);
|
|
5700
3952
|
if (!context) {
|
|
5701
3953
|
throw new Error(
|
|
5702
3954
|
"useSpectrogramIntegration must be used within <SpectrogramProvider>. Install @waveform-playlist/spectrogram and wrap your app with <SpectrogramProvider>."
|
|
@@ -5706,7 +3958,7 @@ function useSpectrogramIntegration() {
|
|
|
5706
3958
|
}
|
|
5707
3959
|
|
|
5708
3960
|
// src/components/PlaylistVisualization.tsx
|
|
5709
|
-
var
|
|
3961
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
5710
3962
|
var DEFAULT_EMPTY_TRACK_DURATION = 60;
|
|
5711
3963
|
var ControlSlot = import_styled_components6.default.div.attrs((props) => ({
|
|
5712
3964
|
style: { height: `${props.$height}px` }
|
|
@@ -5725,7 +3977,8 @@ var CustomPlayhead = ({ renderPlayhead, color, samplesPerPixel, sampleRate }) =>
|
|
|
5725
3977
|
visualTimeRef,
|
|
5726
3978
|
playbackStartTimeRef,
|
|
5727
3979
|
audioStartPositionRef,
|
|
5728
|
-
getPlaybackTime
|
|
3980
|
+
getPlaybackTime,
|
|
3981
|
+
getAudioContextTime
|
|
5729
3982
|
} = usePlaybackAnimation();
|
|
5730
3983
|
const visualTime = (_b = (_a = visualTimeRef.current) != null ? _a : currentTimeRef.current) != null ? _b : 0;
|
|
5731
3984
|
return renderPlayhead({
|
|
@@ -5739,7 +3992,7 @@ var CustomPlayhead = ({ renderPlayhead, color, samplesPerPixel, sampleRate }) =>
|
|
|
5739
3992
|
samplesPerPixel,
|
|
5740
3993
|
sampleRate,
|
|
5741
3994
|
controlsOffset: 0,
|
|
5742
|
-
getAudioContextTime
|
|
3995
|
+
getAudioContextTime,
|
|
5743
3996
|
getPlaybackTime
|
|
5744
3997
|
});
|
|
5745
3998
|
};
|
|
@@ -5763,8 +4016,8 @@ var PlaylistVisualization = ({
|
|
|
5763
4016
|
recordingState
|
|
5764
4017
|
}) => {
|
|
5765
4018
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
5766
|
-
const theme = (0,
|
|
5767
|
-
const { isPlaying, getLookAhead } = usePlaybackAnimation();
|
|
4019
|
+
const theme = (0, import_ui_components8.useTheme)();
|
|
4020
|
+
const { isPlaying, getLookAhead, getOutputLatency } = usePlaybackAnimation();
|
|
5768
4021
|
const {
|
|
5769
4022
|
selectionStart,
|
|
5770
4023
|
selectionEnd,
|
|
@@ -5779,7 +4032,7 @@ var PlaylistVisualization = ({
|
|
|
5779
4032
|
isLoopEnabled,
|
|
5780
4033
|
indefinitePlayback
|
|
5781
4034
|
} = usePlaylistState();
|
|
5782
|
-
const annotationIntegration = (0,
|
|
4035
|
+
const annotationIntegration = (0, import_react26.useContext)(AnnotationIntegrationContext);
|
|
5783
4036
|
const {
|
|
5784
4037
|
setAnnotations: _setAnnotations,
|
|
5785
4038
|
setActiveAnnotationId,
|
|
@@ -5809,8 +4062,8 @@ var PlaylistVisualization = ({
|
|
|
5809
4062
|
isReady,
|
|
5810
4063
|
mono
|
|
5811
4064
|
} = usePlaylistData();
|
|
5812
|
-
const spectrogram = (0,
|
|
5813
|
-
const perTrackSpectrogramHelpers = (0,
|
|
4065
|
+
const spectrogram = (0, import_react26.useContext)(SpectrogramIntegrationContext);
|
|
4066
|
+
const perTrackSpectrogramHelpers = (0, import_react26.useMemo)(() => {
|
|
5814
4067
|
if (!spectrogram)
|
|
5815
4068
|
return /* @__PURE__ */ new Map();
|
|
5816
4069
|
const helpers = /* @__PURE__ */ new Map();
|
|
@@ -5829,11 +4082,11 @@ var PlaylistVisualization = ({
|
|
|
5829
4082
|
});
|
|
5830
4083
|
return helpers;
|
|
5831
4084
|
}, [tracks, spectrogram]);
|
|
5832
|
-
const [settingsModalTrackId, setSettingsModalTrackId] = (0,
|
|
5833
|
-
const [isSelecting, setIsSelecting] = (0,
|
|
5834
|
-
const mouseDownTimeRef = (0,
|
|
5835
|
-
const scrollContainerRef = (0,
|
|
5836
|
-
const handleScrollContainerRef = (0,
|
|
4085
|
+
const [settingsModalTrackId, setSettingsModalTrackId] = (0, import_react26.useState)(null);
|
|
4086
|
+
const [isSelecting, setIsSelecting] = (0, import_react26.useState)(false);
|
|
4087
|
+
const mouseDownTimeRef = (0, import_react26.useRef)(0);
|
|
4088
|
+
const scrollContainerRef = (0, import_react26.useRef)(null);
|
|
4089
|
+
const handleScrollContainerRef = (0, import_react26.useCallback)(
|
|
5837
4090
|
(element) => {
|
|
5838
4091
|
scrollContainerRef.current = element;
|
|
5839
4092
|
setScrollContainer(element);
|
|
@@ -5871,7 +4124,7 @@ var PlaylistVisualization = ({
|
|
|
5871
4124
|
);
|
|
5872
4125
|
}
|
|
5873
4126
|
});
|
|
5874
|
-
const selectTrack = (0,
|
|
4127
|
+
const selectTrack = (0, import_react26.useCallback)(
|
|
5875
4128
|
(trackIndex) => {
|
|
5876
4129
|
if (trackIndex >= 0 && trackIndex < tracks.length) {
|
|
5877
4130
|
const track = tracks[trackIndex];
|
|
@@ -5941,7 +4194,7 @@ var PlaylistVisualization = ({
|
|
|
5941
4194
|
};
|
|
5942
4195
|
const hasClips = tracks.some((track) => track.clips.length > 0);
|
|
5943
4196
|
if (hasClips && peaksDataArray.length === 0) {
|
|
5944
|
-
return /* @__PURE__ */ (0,
|
|
4197
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className, children: "Loading waveform..." });
|
|
5945
4198
|
}
|
|
5946
4199
|
const trackControlsSlots = controls.show ? peaksDataArray.map((trackClipPeaks, trackIndex) => {
|
|
5947
4200
|
var _a2, _b2, _c2;
|
|
@@ -5957,11 +4210,11 @@ var PlaylistVisualization = ({
|
|
|
5957
4210
|
const hasMidiNotes = track.clips.some((c) => c.midiNotes && c.midiNotes.length > 0);
|
|
5958
4211
|
const effectiveRenderMode = (_c2 = (_b2 = (_a2 = spectrogram == null ? void 0 : spectrogram.trackSpectrogramOverrides.get(track.id)) == null ? void 0 : _a2.renderMode) != null ? _b2 : track.renderMode) != null ? _c2 : hasMidiNotes ? "piano-roll" : "waveform";
|
|
5959
4212
|
const maxChannels = getTrackChannelCount(trackClipPeaks, recordingState, track.id, mono);
|
|
5960
|
-
const slotHeight = waveHeight * maxChannels + (showClipHeaders ?
|
|
5961
|
-
const trackControlContent = renderTrackControls ? renderTrackControls(trackIndex) : /* @__PURE__ */ (0,
|
|
5962
|
-
/* @__PURE__ */ (0,
|
|
5963
|
-
onRemoveTrack && /* @__PURE__ */ (0,
|
|
5964
|
-
|
|
4213
|
+
const slotHeight = waveHeight * maxChannels + (showClipHeaders ? import_ui_components8.CLIP_HEADER_HEIGHT : 0);
|
|
4214
|
+
const trackControlContent = renderTrackControls ? renderTrackControls(trackIndex) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ui_components8.Controls, { onClick: () => selectTrack(trackIndex), children: [
|
|
4215
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ui_components8.Header, { style: { justifyContent: "center", position: "relative" }, children: [
|
|
4216
|
+
onRemoveTrack && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4217
|
+
import_ui_components8.CloseButton,
|
|
5965
4218
|
{
|
|
5966
4219
|
onClick: (e) => {
|
|
5967
4220
|
e.stopPropagation();
|
|
@@ -5969,7 +4222,7 @@ var PlaylistVisualization = ({
|
|
|
5969
4222
|
}
|
|
5970
4223
|
}
|
|
5971
4224
|
),
|
|
5972
|
-
/* @__PURE__ */ (0,
|
|
4225
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
5973
4226
|
"span",
|
|
5974
4227
|
{
|
|
5975
4228
|
style: {
|
|
@@ -5982,8 +4235,8 @@ var PlaylistVisualization = ({
|
|
|
5982
4235
|
children: trackState.name || `Track ${trackIndex + 1}`
|
|
5983
4236
|
}
|
|
5984
4237
|
),
|
|
5985
|
-
(spectrogram == null ? void 0 : spectrogram.renderMenuItems) && /* @__PURE__ */ (0,
|
|
5986
|
-
|
|
4238
|
+
(spectrogram == null ? void 0 : spectrogram.renderMenuItems) && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { position: "absolute", right: 0, top: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4239
|
+
import_ui_components8.TrackMenu,
|
|
5987
4240
|
{
|
|
5988
4241
|
items: (onClose) => spectrogram.renderMenuItems({
|
|
5989
4242
|
renderMode: effectiveRenderMode,
|
|
@@ -5994,17 +4247,17 @@ var PlaylistVisualization = ({
|
|
|
5994
4247
|
}
|
|
5995
4248
|
) })
|
|
5996
4249
|
] }),
|
|
5997
|
-
/* @__PURE__ */ (0,
|
|
5998
|
-
/* @__PURE__ */ (0,
|
|
5999
|
-
|
|
4250
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ui_components8.ButtonGroup, { children: [
|
|
4251
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4252
|
+
import_ui_components8.Button,
|
|
6000
4253
|
{
|
|
6001
4254
|
$variant: trackState.muted ? "danger" : "outline",
|
|
6002
4255
|
onClick: () => setTrackMute(trackIndex, !trackState.muted),
|
|
6003
4256
|
children: "Mute"
|
|
6004
4257
|
}
|
|
6005
4258
|
),
|
|
6006
|
-
/* @__PURE__ */ (0,
|
|
6007
|
-
|
|
4259
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4260
|
+
import_ui_components8.Button,
|
|
6008
4261
|
{
|
|
6009
4262
|
$variant: trackState.soloed ? "info" : "outline",
|
|
6010
4263
|
onClick: () => setTrackSolo(trackIndex, !trackState.soloed),
|
|
@@ -6012,10 +4265,10 @@ var PlaylistVisualization = ({
|
|
|
6012
4265
|
}
|
|
6013
4266
|
)
|
|
6014
4267
|
] }),
|
|
6015
|
-
/* @__PURE__ */ (0,
|
|
6016
|
-
/* @__PURE__ */ (0,
|
|
6017
|
-
/* @__PURE__ */ (0,
|
|
6018
|
-
|
|
4268
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ui_components8.SliderWrapper, { children: [
|
|
4269
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ui_components8.VolumeDownIcon, {}),
|
|
4270
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4271
|
+
import_ui_components8.Slider,
|
|
6019
4272
|
{
|
|
6020
4273
|
min: "0",
|
|
6021
4274
|
max: "1",
|
|
@@ -6024,12 +4277,12 @@ var PlaylistVisualization = ({
|
|
|
6024
4277
|
onChange: (e) => setTrackVolume(trackIndex, parseFloat(e.target.value))
|
|
6025
4278
|
}
|
|
6026
4279
|
),
|
|
6027
|
-
/* @__PURE__ */ (0,
|
|
4280
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ui_components8.VolumeUpIcon, {})
|
|
6028
4281
|
] }),
|
|
6029
|
-
/* @__PURE__ */ (0,
|
|
6030
|
-
/* @__PURE__ */ (0,
|
|
6031
|
-
/* @__PURE__ */ (0,
|
|
6032
|
-
|
|
4282
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ui_components8.SliderWrapper, { children: [
|
|
4283
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "L" }),
|
|
4284
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4285
|
+
import_ui_components8.Slider,
|
|
6033
4286
|
{
|
|
6034
4287
|
min: "-1",
|
|
6035
4288
|
max: "1",
|
|
@@ -6038,10 +4291,10 @@ var PlaylistVisualization = ({
|
|
|
6038
4291
|
onChange: (e) => setTrackPan(trackIndex, parseFloat(e.target.value))
|
|
6039
4292
|
}
|
|
6040
4293
|
),
|
|
6041
|
-
/* @__PURE__ */ (0,
|
|
4294
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "R" })
|
|
6042
4295
|
] })
|
|
6043
4296
|
] });
|
|
6044
|
-
return /* @__PURE__ */ (0,
|
|
4297
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6045
4298
|
ControlSlot,
|
|
6046
4299
|
{
|
|
6047
4300
|
$height: slotHeight,
|
|
@@ -6051,9 +4304,9 @@ var PlaylistVisualization = ({
|
|
|
6051
4304
|
track.id
|
|
6052
4305
|
);
|
|
6053
4306
|
}) : void 0;
|
|
6054
|
-
return /* @__PURE__ */ (0,
|
|
6055
|
-
/* @__PURE__ */ (0,
|
|
6056
|
-
|
|
4307
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ui_components8.DevicePixelRatioProvider, { children: [
|
|
4308
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4309
|
+
import_ui_components8.PlaylistInfoContext.Provider,
|
|
6057
4310
|
{
|
|
6058
4311
|
value: {
|
|
6059
4312
|
samplesPerPixel,
|
|
@@ -6066,11 +4319,11 @@ var PlaylistVisualization = ({
|
|
|
6066
4319
|
barWidth,
|
|
6067
4320
|
barGap
|
|
6068
4321
|
},
|
|
6069
|
-
children: /* @__PURE__ */ (0,
|
|
6070
|
-
|
|
4322
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4323
|
+
import_ui_components8.Playlist,
|
|
6071
4324
|
{
|
|
6072
4325
|
theme,
|
|
6073
|
-
backgroundColor: theme.playlistBackgroundColor || (0,
|
|
4326
|
+
backgroundColor: theme.playlistBackgroundColor || (0, import_ui_components8.waveformColorToCss)(theme.waveOutlineColor),
|
|
6074
4327
|
timescaleBackgroundColor: theme.timescaleBackgroundColor,
|
|
6075
4328
|
timescaleWidth: tracksFullWidth,
|
|
6076
4329
|
tracksWidth: tracksFullWidth,
|
|
@@ -6083,10 +4336,10 @@ var PlaylistVisualization = ({
|
|
|
6083
4336
|
"data-playlist-state": isReady ? "ready" : "loading",
|
|
6084
4337
|
trackControlsSlots,
|
|
6085
4338
|
timescaleGapHeight: timeScaleHeight > 0 ? timeScaleHeight + 1 : 0,
|
|
6086
|
-
timescale: timeScaleHeight > 0 ? /* @__PURE__ */ (0,
|
|
6087
|
-
/* @__PURE__ */ (0,
|
|
6088
|
-
isLoopEnabled && /* @__PURE__ */ (0,
|
|
6089
|
-
|
|
4339
|
+
timescale: timeScaleHeight > 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
4340
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ui_components8.SmartScale, { renderTick }),
|
|
4341
|
+
isLoopEnabled && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4342
|
+
import_ui_components8.TimescaleLoopRegion,
|
|
6090
4343
|
{
|
|
6091
4344
|
startPosition: Math.min(loopStart, loopEnd) * sampleRate / samplesPerPixel,
|
|
6092
4345
|
endPosition: Math.max(loopStart, loopEnd) * sampleRate / samplesPerPixel,
|
|
@@ -6102,7 +4355,7 @@ var PlaylistVisualization = ({
|
|
|
6102
4355
|
}
|
|
6103
4356
|
)
|
|
6104
4357
|
] }) : void 0,
|
|
6105
|
-
children: /* @__PURE__ */ (0,
|
|
4358
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
6106
4359
|
peaksDataArray.map((trackClipPeaks, trackIndex) => {
|
|
6107
4360
|
var _a2, _b2, _c2, _d2;
|
|
6108
4361
|
const track = tracks[trackIndex];
|
|
@@ -6115,11 +4368,11 @@ var PlaylistVisualization = ({
|
|
|
6115
4368
|
track.id,
|
|
6116
4369
|
mono
|
|
6117
4370
|
);
|
|
6118
|
-
return /* @__PURE__ */ (0,
|
|
6119
|
-
|
|
4371
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
4372
|
+
import_ui_components8.Track,
|
|
6120
4373
|
{
|
|
6121
4374
|
numChannels: maxChannels,
|
|
6122
|
-
backgroundColor: effectiveRenderMode === "piano-roll" ? theme.pianoRollBackgroundColor || "#1a1a2e" : (0,
|
|
4375
|
+
backgroundColor: effectiveRenderMode === "piano-roll" ? theme.pianoRollBackgroundColor || "#1a1a2e" : (0, import_ui_components8.waveformColorToCss)(theme.waveOutlineColor),
|
|
6123
4376
|
offset: 0,
|
|
6124
4377
|
width: tracksFullWidth,
|
|
6125
4378
|
hasClipHeaders: showClipHeaders,
|
|
@@ -6131,8 +4384,8 @@ var PlaylistVisualization = ({
|
|
|
6131
4384
|
const helpers = perTrackSpectrogramHelpers.get(track.id);
|
|
6132
4385
|
const trackCfg = helpers == null ? void 0 : helpers.config;
|
|
6133
4386
|
if (!(trackCfg == null ? void 0 : trackCfg.labels) || !helpers) return null;
|
|
6134
|
-
return /* @__PURE__ */ (0,
|
|
6135
|
-
|
|
4387
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4388
|
+
import_ui_components8.SpectrogramLabels,
|
|
6136
4389
|
{
|
|
6137
4390
|
waveHeight,
|
|
6138
4391
|
numChannels: maxChannels,
|
|
@@ -6149,8 +4402,8 @@ var PlaylistVisualization = ({
|
|
|
6149
4402
|
trackClipPeaks.map((clip, clipIndex) => {
|
|
6150
4403
|
const peaksData = clip.peaks;
|
|
6151
4404
|
const width = peaksData.length;
|
|
6152
|
-
return /* @__PURE__ */ (0,
|
|
6153
|
-
|
|
4405
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4406
|
+
import_ui_components8.Clip,
|
|
6154
4407
|
{
|
|
6155
4408
|
clipId: clip.clipId,
|
|
6156
4409
|
trackIndex,
|
|
@@ -6179,7 +4432,7 @@ var PlaylistVisualization = ({
|
|
|
6179
4432
|
selectTrack(trackIndex);
|
|
6180
4433
|
},
|
|
6181
4434
|
children: peaksData.data.map((channelPeaks, channelIndex) => {
|
|
6182
|
-
return /* @__PURE__ */ (0,
|
|
4435
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6183
4436
|
ChannelWithProgress,
|
|
6184
4437
|
{
|
|
6185
4438
|
index: channelIndex,
|
|
@@ -6206,14 +4459,12 @@ var PlaylistVisualization = ({
|
|
|
6206
4459
|
);
|
|
6207
4460
|
}),
|
|
6208
4461
|
(recordingState == null ? void 0 : recordingState.isRecording) && recordingState.trackId === track.id && ((_d2 = recordingState.peaks[0]) == null ? void 0 : _d2.length) > 0 && (() => {
|
|
6209
|
-
const
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
outputLatency,
|
|
6214
|
-
lookAhead,
|
|
4462
|
+
const latencyOffsetSamples = (0, import_core4.resolveRecordingOffsetSamples)({
|
|
4463
|
+
overrideSeconds: recordingState.latencyOffset,
|
|
4464
|
+
outputLatency: getOutputLatency(),
|
|
4465
|
+
lookAhead: getLookAhead(),
|
|
6215
4466
|
sampleRate
|
|
6216
|
-
);
|
|
4467
|
+
});
|
|
6217
4468
|
const latencyPixels = Math.floor(latencyOffsetSamples / samplesPerPixel);
|
|
6218
4469
|
const skipPeakElements = latencyPixels * 2;
|
|
6219
4470
|
const previewDuration = Math.max(
|
|
@@ -6223,8 +4474,8 @@ var PlaylistVisualization = ({
|
|
|
6223
4474
|
const previewChannels = (mono ? recordingState.peaks.slice(0, 1) : recordingState.peaks).map(
|
|
6224
4475
|
(channelPeaks) => skipPeakElements > 0 && skipPeakElements < channelPeaks.length ? channelPeaks.subarray(skipPeakElements) : channelPeaks
|
|
6225
4476
|
);
|
|
6226
|
-
return /* @__PURE__ */ (0,
|
|
6227
|
-
|
|
4477
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4478
|
+
import_ui_components8.Clip,
|
|
6228
4479
|
{
|
|
6229
4480
|
clipId: "recording-preview",
|
|
6230
4481
|
trackIndex,
|
|
@@ -6237,7 +4488,7 @@ var PlaylistVisualization = ({
|
|
|
6237
4488
|
disableHeaderDrag: true,
|
|
6238
4489
|
isSelected: track.id === selectedTrackId,
|
|
6239
4490
|
trackId: track.id,
|
|
6240
|
-
children: previewChannels.map((channelPeaks, chIdx) => /* @__PURE__ */ (0,
|
|
4491
|
+
children: previewChannels.map((channelPeaks, chIdx) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6241
4492
|
ChannelWithProgress,
|
|
6242
4493
|
{
|
|
6243
4494
|
index: chIdx,
|
|
@@ -6259,11 +4510,11 @@ var PlaylistVisualization = ({
|
|
|
6259
4510
|
track.id
|
|
6260
4511
|
);
|
|
6261
4512
|
}),
|
|
6262
|
-
annotations.length > 0 && annotationIntegration && /* @__PURE__ */ (0,
|
|
4513
|
+
annotations.length > 0 && annotationIntegration && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(annotationIntegration.AnnotationBoxesWrapper, { height: 30, width: tracksFullWidth, children: annotations.map((annotation, index) => {
|
|
6263
4514
|
const startPosition = annotation.start * sampleRate / samplesPerPixel;
|
|
6264
4515
|
const endPosition = annotation.end * sampleRate / samplesPerPixel;
|
|
6265
4516
|
const label = getAnnotationBoxLabel ? getAnnotationBoxLabel(annotation, index) : annotation.id;
|
|
6266
|
-
return /* @__PURE__ */ (0,
|
|
4517
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6267
4518
|
annotationIntegration.AnnotationBox,
|
|
6268
4519
|
{
|
|
6269
4520
|
annotationId: annotation.id,
|
|
@@ -6279,15 +4530,15 @@ var PlaylistVisualization = ({
|
|
|
6279
4530
|
annotation.id
|
|
6280
4531
|
);
|
|
6281
4532
|
}) }),
|
|
6282
|
-
selectionStart !== selectionEnd && /* @__PURE__ */ (0,
|
|
6283
|
-
|
|
4533
|
+
selectionStart !== selectionEnd && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4534
|
+
import_ui_components8.Selection,
|
|
6284
4535
|
{
|
|
6285
4536
|
startPosition: Math.min(selectionStart, selectionEnd) * sampleRate / samplesPerPixel,
|
|
6286
4537
|
endPosition: Math.max(selectionStart, selectionEnd) * sampleRate / samplesPerPixel,
|
|
6287
4538
|
color: theme.selectionColor
|
|
6288
4539
|
}
|
|
6289
4540
|
),
|
|
6290
|
-
(isPlaying || selectionStart === selectionEnd) && (renderPlayhead ? /* @__PURE__ */ (0,
|
|
4541
|
+
(isPlaying || selectionStart === selectionEnd) && (renderPlayhead ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6291
4542
|
CustomPlayhead,
|
|
6292
4543
|
{
|
|
6293
4544
|
renderPlayhead,
|
|
@@ -6295,14 +4546,14 @@ var PlaylistVisualization = ({
|
|
|
6295
4546
|
samplesPerPixel,
|
|
6296
4547
|
sampleRate
|
|
6297
4548
|
}
|
|
6298
|
-
) : /* @__PURE__ */ (0,
|
|
4549
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AnimatedPlayhead, { color: theme.playheadColor }))
|
|
6299
4550
|
] })
|
|
6300
4551
|
}
|
|
6301
4552
|
)
|
|
6302
4553
|
}
|
|
6303
4554
|
),
|
|
6304
4555
|
(spectrogram == null ? void 0 : spectrogram.SettingsModal) && typeof document !== "undefined" && (0, import_react_dom.createPortal)(
|
|
6305
|
-
/* @__PURE__ */ (0,
|
|
4556
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6306
4557
|
spectrogram.SettingsModal,
|
|
6307
4558
|
{
|
|
6308
4559
|
open: settingsModalTrackId !== null,
|
|
@@ -6322,8 +4573,8 @@ var PlaylistVisualization = ({
|
|
|
6322
4573
|
};
|
|
6323
4574
|
|
|
6324
4575
|
// src/components/PlaylistAnnotationList.tsx
|
|
6325
|
-
var
|
|
6326
|
-
var
|
|
4576
|
+
var import_react27 = require("react");
|
|
4577
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
6327
4578
|
var PlaylistAnnotationList = ({
|
|
6328
4579
|
height,
|
|
6329
4580
|
renderAnnotationItem,
|
|
@@ -6337,7 +4588,7 @@ var PlaylistAnnotationList = ({
|
|
|
6337
4588
|
const integration = useAnnotationIntegration();
|
|
6338
4589
|
const { setAnnotations } = usePlaylistControls();
|
|
6339
4590
|
const resolvedConfig = annotationListConfig != null ? annotationListConfig : { linkEndpoints, continuousPlay };
|
|
6340
|
-
const handleAnnotationUpdate = (0,
|
|
4591
|
+
const handleAnnotationUpdate = (0, import_react27.useCallback)(
|
|
6341
4592
|
(updatedAnnotations) => {
|
|
6342
4593
|
setAnnotations(updatedAnnotations);
|
|
6343
4594
|
onAnnotationUpdate == null ? void 0 : onAnnotationUpdate(updatedAnnotations);
|
|
@@ -6345,7 +4596,7 @@ var PlaylistAnnotationList = ({
|
|
|
6345
4596
|
[setAnnotations, onAnnotationUpdate]
|
|
6346
4597
|
);
|
|
6347
4598
|
const { AnnotationText } = integration;
|
|
6348
|
-
return /* @__PURE__ */ (0,
|
|
4599
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
6349
4600
|
AnnotationText,
|
|
6350
4601
|
{
|
|
6351
4602
|
annotations,
|
|
@@ -6364,7 +4615,7 @@ var PlaylistAnnotationList = ({
|
|
|
6364
4615
|
};
|
|
6365
4616
|
|
|
6366
4617
|
// src/components/Waveform.tsx
|
|
6367
|
-
var
|
|
4618
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
6368
4619
|
var Waveform = ({
|
|
6369
4620
|
renderTrackControls,
|
|
6370
4621
|
renderTick,
|
|
@@ -6388,8 +4639,8 @@ var Waveform = ({
|
|
|
6388
4639
|
const { annotations } = usePlaylistState();
|
|
6389
4640
|
const clipInteractionEnabled = useClipInteractionEnabled();
|
|
6390
4641
|
const effectiveInteractiveClips = interactiveClips || clipInteractionEnabled;
|
|
6391
|
-
return /* @__PURE__ */ (0,
|
|
6392
|
-
/* @__PURE__ */ (0,
|
|
4642
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
4643
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
6393
4644
|
PlaylistVisualization,
|
|
6394
4645
|
{
|
|
6395
4646
|
renderTrackControls,
|
|
@@ -6406,7 +4657,7 @@ var Waveform = ({
|
|
|
6406
4657
|
recordingState
|
|
6407
4658
|
}
|
|
6408
4659
|
),
|
|
6409
|
-
annotations.length > 0 && /* @__PURE__ */ (0,
|
|
4660
|
+
annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
6410
4661
|
PlaylistAnnotationList,
|
|
6411
4662
|
{
|
|
6412
4663
|
height: annotationTextHeight,
|
|
@@ -6421,10 +4672,10 @@ var Waveform = ({
|
|
|
6421
4672
|
};
|
|
6422
4673
|
|
|
6423
4674
|
// src/components/MediaElementPlaylist.tsx
|
|
6424
|
-
var
|
|
6425
|
-
var
|
|
4675
|
+
var import_react30 = require("react");
|
|
4676
|
+
var import_react31 = require("@dnd-kit/react");
|
|
6426
4677
|
var import_modifiers = require("@dnd-kit/abstract/modifiers");
|
|
6427
|
-
var
|
|
4678
|
+
var import_ui_components10 = require("@waveform-playlist/ui-components");
|
|
6428
4679
|
|
|
6429
4680
|
// src/plugins/noDropAnimationPlugins.ts
|
|
6430
4681
|
var import_dom2 = require("@dnd-kit/dom");
|
|
@@ -6446,9 +4697,9 @@ var noDropAnimationPlugins = (defaults) => {
|
|
|
6446
4697
|
};
|
|
6447
4698
|
|
|
6448
4699
|
// src/components/AnimatedMediaElementPlayhead.tsx
|
|
6449
|
-
var
|
|
4700
|
+
var import_react28 = require("react");
|
|
6450
4701
|
var import_styled_components7 = __toESM(require("styled-components"));
|
|
6451
|
-
var
|
|
4702
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
6452
4703
|
var PlayheadLine2 = import_styled_components7.default.div`
|
|
6453
4704
|
position: absolute;
|
|
6454
4705
|
top: 0;
|
|
@@ -6463,11 +4714,11 @@ var PlayheadLine2 = import_styled_components7.default.div`
|
|
|
6463
4714
|
var AnimatedMediaElementPlayhead = ({
|
|
6464
4715
|
color = "#ff0000"
|
|
6465
4716
|
}) => {
|
|
6466
|
-
const playheadRef = (0,
|
|
6467
|
-
const animationFrameRef = (0,
|
|
4717
|
+
const playheadRef = (0, import_react28.useRef)(null);
|
|
4718
|
+
const animationFrameRef = (0, import_react28.useRef)(null);
|
|
6468
4719
|
const { isPlaying, currentTimeRef } = useMediaElementAnimation();
|
|
6469
4720
|
const { samplesPerPixel, sampleRate, progressBarWidth } = useMediaElementData();
|
|
6470
|
-
(0,
|
|
4721
|
+
(0, import_react28.useEffect)(() => {
|
|
6471
4722
|
const updatePosition = () => {
|
|
6472
4723
|
var _a;
|
|
6473
4724
|
if (playheadRef.current) {
|
|
@@ -6491,7 +4742,7 @@ var AnimatedMediaElementPlayhead = ({
|
|
|
6491
4742
|
}
|
|
6492
4743
|
};
|
|
6493
4744
|
}, [isPlaying, sampleRate, samplesPerPixel, currentTimeRef]);
|
|
6494
|
-
(0,
|
|
4745
|
+
(0, import_react28.useEffect)(() => {
|
|
6495
4746
|
var _a;
|
|
6496
4747
|
if (!isPlaying && playheadRef.current) {
|
|
6497
4748
|
const time = (_a = currentTimeRef.current) != null ? _a : 0;
|
|
@@ -6499,14 +4750,14 @@ var AnimatedMediaElementPlayhead = ({
|
|
|
6499
4750
|
playheadRef.current.style.transform = `translate3d(${position}px, 0, 0)`;
|
|
6500
4751
|
}
|
|
6501
4752
|
});
|
|
6502
|
-
return /* @__PURE__ */ (0,
|
|
4753
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PlayheadLine2, { ref: playheadRef, $color: color, $width: progressBarWidth, "data-playhead": true });
|
|
6503
4754
|
};
|
|
6504
4755
|
|
|
6505
4756
|
// src/components/ChannelWithMediaElementProgress.tsx
|
|
6506
|
-
var
|
|
4757
|
+
var import_react29 = require("react");
|
|
6507
4758
|
var import_styled_components8 = __toESM(require("styled-components"));
|
|
6508
|
-
var
|
|
6509
|
-
var
|
|
4759
|
+
var import_ui_components9 = require("@waveform-playlist/ui-components");
|
|
4760
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
6510
4761
|
var ChannelWrapper2 = import_styled_components8.default.div`
|
|
6511
4762
|
position: relative;
|
|
6512
4763
|
`;
|
|
@@ -6543,14 +4794,14 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6543
4794
|
"clipStartSample",
|
|
6544
4795
|
"clipDurationSamples"
|
|
6545
4796
|
]);
|
|
6546
|
-
const progressRef = (0,
|
|
6547
|
-
const animationFrameRef = (0,
|
|
6548
|
-
const theme = (0,
|
|
6549
|
-
const { waveHeight } = (0,
|
|
4797
|
+
const progressRef = (0, import_react29.useRef)(null);
|
|
4798
|
+
const animationFrameRef = (0, import_react29.useRef)(null);
|
|
4799
|
+
const theme = (0, import_ui_components9.useTheme)();
|
|
4800
|
+
const { waveHeight } = (0, import_ui_components9.usePlaylistInfo)();
|
|
6550
4801
|
const { isPlaying, currentTimeRef } = useMediaElementAnimation();
|
|
6551
4802
|
const { samplesPerPixel, sampleRate } = useMediaElementData();
|
|
6552
4803
|
const progressColor = (theme == null ? void 0 : theme.waveProgressColor) || "rgba(0, 0, 0, 0.1)";
|
|
6553
|
-
(0,
|
|
4804
|
+
(0, import_react29.useEffect)(() => {
|
|
6554
4805
|
const updateProgress = () => {
|
|
6555
4806
|
var _a2;
|
|
6556
4807
|
if (progressRef.current) {
|
|
@@ -6592,7 +4843,7 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6592
4843
|
smartChannelProps.length,
|
|
6593
4844
|
currentTimeRef
|
|
6594
4845
|
]);
|
|
6595
|
-
(0,
|
|
4846
|
+
(0, import_react29.useEffect)(() => {
|
|
6596
4847
|
var _a2;
|
|
6597
4848
|
if (!isPlaying && progressRef.current) {
|
|
6598
4849
|
const currentTime = (_a2 = currentTimeRef.current) != null ? _a2 : 0;
|
|
@@ -6617,9 +4868,9 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6617
4868
|
} else {
|
|
6618
4869
|
backgroundColor = (theme == null ? void 0 : theme.selectedWaveOutlineColor) || (theme == null ? void 0 : theme.waveOutlineColor) || "grey";
|
|
6619
4870
|
}
|
|
6620
|
-
const backgroundCss = (0,
|
|
6621
|
-
return /* @__PURE__ */ (0,
|
|
6622
|
-
/* @__PURE__ */ (0,
|
|
4871
|
+
const backgroundCss = (0, import_ui_components9.waveformColorToCss)(backgroundColor);
|
|
4872
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(ChannelWrapper2, { children: [
|
|
4873
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
6623
4874
|
Background2,
|
|
6624
4875
|
{
|
|
6625
4876
|
$color: backgroundCss,
|
|
@@ -6628,7 +4879,7 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6628
4879
|
$width: smartChannelProps.length
|
|
6629
4880
|
}
|
|
6630
4881
|
),
|
|
6631
|
-
/* @__PURE__ */ (0,
|
|
4882
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
6632
4883
|
ProgressOverlay2,
|
|
6633
4884
|
{
|
|
6634
4885
|
ref: progressRef,
|
|
@@ -6637,12 +4888,12 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6637
4888
|
$top: smartChannelProps.index * waveHeight
|
|
6638
4889
|
}
|
|
6639
4890
|
),
|
|
6640
|
-
/* @__PURE__ */ (0,
|
|
4891
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChannelContainer2, { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_ui_components9.SmartChannel, __spreadProps(__spreadValues({}, smartChannelProps), { isSelected: true, transparentBackground: true })) })
|
|
6641
4892
|
] });
|
|
6642
4893
|
};
|
|
6643
4894
|
|
|
6644
4895
|
// src/components/MediaElementPlaylist.tsx
|
|
6645
|
-
var
|
|
4896
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
6646
4897
|
var ZERO_REF = { current: 0 };
|
|
6647
4898
|
var CustomMediaElementPlayhead = ({ renderPlayhead, color, samplesPerPixel, sampleRate }) => {
|
|
6648
4899
|
var _a;
|
|
@@ -6668,10 +4919,10 @@ var MediaElementPlaylist = ({
|
|
|
6668
4919
|
showFades = false,
|
|
6669
4920
|
className
|
|
6670
4921
|
}) => {
|
|
6671
|
-
const theme = (0,
|
|
4922
|
+
const theme = (0, import_ui_components10.useTheme)();
|
|
6672
4923
|
const { isPlaying } = useMediaElementAnimation();
|
|
6673
4924
|
const { annotations, activeAnnotationId } = useMediaElementState();
|
|
6674
|
-
const annotationIntegration = (0,
|
|
4925
|
+
const annotationIntegration = (0, import_react30.useContext)(AnnotationIntegrationContext);
|
|
6675
4926
|
const { play, seekTo, setActiveAnnotationId, setAnnotations, setScrollContainer } = useMediaElementControls();
|
|
6676
4927
|
const {
|
|
6677
4928
|
duration,
|
|
@@ -6687,11 +4938,11 @@ var MediaElementPlaylist = ({
|
|
|
6687
4938
|
fadeIn,
|
|
6688
4939
|
fadeOut
|
|
6689
4940
|
} = useMediaElementData();
|
|
6690
|
-
const [selectionStart, setSelectionStart] = (0,
|
|
6691
|
-
const [selectionEnd, setSelectionEnd] = (0,
|
|
6692
|
-
const [isSelecting, setIsSelecting] = (0,
|
|
6693
|
-
const scrollContainerRef = (0,
|
|
6694
|
-
const handleScrollContainerRef = (0,
|
|
4941
|
+
const [selectionStart, setSelectionStart] = (0, import_react30.useState)(0);
|
|
4942
|
+
const [selectionEnd, setSelectionEnd] = (0, import_react30.useState)(0);
|
|
4943
|
+
const [isSelecting, setIsSelecting] = (0, import_react30.useState)(false);
|
|
4944
|
+
const scrollContainerRef = (0, import_react30.useRef)(null);
|
|
4945
|
+
const handleScrollContainerRef = (0, import_react30.useCallback)(
|
|
6695
4946
|
(el) => {
|
|
6696
4947
|
scrollContainerRef.current = el;
|
|
6697
4948
|
setScrollContainer(el);
|
|
@@ -6699,7 +4950,7 @@ var MediaElementPlaylist = ({
|
|
|
6699
4950
|
[setScrollContainer]
|
|
6700
4951
|
);
|
|
6701
4952
|
const tracksFullWidth = Math.floor(duration * sampleRate / samplesPerPixel);
|
|
6702
|
-
const handleAnnotationClick = (0,
|
|
4953
|
+
const handleAnnotationClick = (0, import_react30.useCallback)(
|
|
6703
4954
|
(annotation) => __async(null, null, function* () {
|
|
6704
4955
|
setActiveAnnotationId(annotation.id);
|
|
6705
4956
|
try {
|
|
@@ -6714,7 +4965,7 @@ var MediaElementPlaylist = ({
|
|
|
6714
4965
|
}),
|
|
6715
4966
|
[setActiveAnnotationId, play]
|
|
6716
4967
|
);
|
|
6717
|
-
const handleAnnotationUpdate = (0,
|
|
4968
|
+
const handleAnnotationUpdate = (0, import_react30.useCallback)(
|
|
6718
4969
|
(updatedAnnotations) => {
|
|
6719
4970
|
setAnnotations(updatedAnnotations);
|
|
6720
4971
|
onAnnotationUpdate == null ? void 0 : onAnnotationUpdate(updatedAnnotations);
|
|
@@ -6728,8 +4979,8 @@ var MediaElementPlaylist = ({
|
|
|
6728
4979
|
duration,
|
|
6729
4980
|
linkEndpoints: linkEndpointsProp
|
|
6730
4981
|
});
|
|
6731
|
-
const mouseDownTimeRef = (0,
|
|
6732
|
-
const handleMouseDown = (0,
|
|
4982
|
+
const mouseDownTimeRef = (0, import_react30.useRef)(0);
|
|
4983
|
+
const handleMouseDown = (0, import_react30.useCallback)(
|
|
6733
4984
|
(e) => {
|
|
6734
4985
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
6735
4986
|
const x = e.clientX - rect.left;
|
|
@@ -6741,7 +4992,7 @@ var MediaElementPlaylist = ({
|
|
|
6741
4992
|
},
|
|
6742
4993
|
[samplesPerPixel, sampleRate]
|
|
6743
4994
|
);
|
|
6744
|
-
const handleMouseMove = (0,
|
|
4995
|
+
const handleMouseMove = (0, import_react30.useCallback)(
|
|
6745
4996
|
(e) => {
|
|
6746
4997
|
if (!isSelecting) return;
|
|
6747
4998
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
@@ -6751,7 +5002,7 @@ var MediaElementPlaylist = ({
|
|
|
6751
5002
|
},
|
|
6752
5003
|
[isSelecting, samplesPerPixel, sampleRate]
|
|
6753
5004
|
);
|
|
6754
|
-
const handleMouseUp = (0,
|
|
5005
|
+
const handleMouseUp = (0, import_react30.useCallback)(
|
|
6755
5006
|
(e) => {
|
|
6756
5007
|
if (!isSelecting) return;
|
|
6757
5008
|
setIsSelecting(false);
|
|
@@ -6781,10 +5032,10 @@ var MediaElementPlaylist = ({
|
|
|
6781
5032
|
[isSelecting, selectionStart, samplesPerPixel, sampleRate, seekTo, isPlaying, playoutRef, play]
|
|
6782
5033
|
);
|
|
6783
5034
|
if (peaksDataArray.length === 0) {
|
|
6784
|
-
return /* @__PURE__ */ (0,
|
|
5035
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className, children: "Loading waveform..." });
|
|
6785
5036
|
}
|
|
6786
|
-
return /* @__PURE__ */ (0,
|
|
6787
|
-
|
|
5037
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ui_components10.DevicePixelRatioProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5038
|
+
import_ui_components10.PlaylistInfoContext.Provider,
|
|
6788
5039
|
{
|
|
6789
5040
|
value: {
|
|
6790
5041
|
samplesPerPixel,
|
|
@@ -6797,11 +5048,11 @@ var MediaElementPlaylist = ({
|
|
|
6797
5048
|
barWidth,
|
|
6798
5049
|
barGap
|
|
6799
5050
|
},
|
|
6800
|
-
children: /* @__PURE__ */ (0,
|
|
6801
|
-
|
|
5051
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5052
|
+
import_ui_components10.Playlist,
|
|
6802
5053
|
{
|
|
6803
5054
|
theme,
|
|
6804
|
-
backgroundColor: (0,
|
|
5055
|
+
backgroundColor: (0, import_ui_components10.waveformColorToCss)(theme.waveOutlineColor),
|
|
6805
5056
|
timescaleBackgroundColor: theme.timescaleBackgroundColor,
|
|
6806
5057
|
timescaleWidth: tracksFullWidth,
|
|
6807
5058
|
tracksWidth: tracksFullWidth,
|
|
@@ -6811,15 +5062,15 @@ var MediaElementPlaylist = ({
|
|
|
6811
5062
|
onTracksMouseUp: handleMouseUp,
|
|
6812
5063
|
scrollContainerRef: handleScrollContainerRef,
|
|
6813
5064
|
isSelecting,
|
|
6814
|
-
timescale: timeScaleHeight > 0 ? /* @__PURE__ */ (0,
|
|
6815
|
-
children: /* @__PURE__ */ (0,
|
|
5065
|
+
timescale: timeScaleHeight > 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ui_components10.SmartScale, {}) : void 0,
|
|
5066
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
6816
5067
|
peaksDataArray.map((trackClipPeaks, trackIndex) => {
|
|
6817
5068
|
const maxChannels = trackClipPeaks.length > 0 ? Math.max(...trackClipPeaks.map((clip) => clip.peaks.data.length)) : 1;
|
|
6818
|
-
return /* @__PURE__ */ (0,
|
|
6819
|
-
|
|
5069
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5070
|
+
import_ui_components10.Track,
|
|
6820
5071
|
{
|
|
6821
5072
|
numChannels: maxChannels,
|
|
6822
|
-
backgroundColor: (0,
|
|
5073
|
+
backgroundColor: (0, import_ui_components10.waveformColorToCss)(theme.waveOutlineColor),
|
|
6823
5074
|
offset: 0,
|
|
6824
5075
|
width: tracksFullWidth,
|
|
6825
5076
|
hasClipHeaders: false,
|
|
@@ -6828,8 +5079,8 @@ var MediaElementPlaylist = ({
|
|
|
6828
5079
|
children: trackClipPeaks.map((clip, clipIndex) => {
|
|
6829
5080
|
const peaksData = clip.peaks;
|
|
6830
5081
|
const width = peaksData.length;
|
|
6831
|
-
return /* @__PURE__ */ (0,
|
|
6832
|
-
|
|
5082
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
5083
|
+
import_ui_components10.Clip,
|
|
6833
5084
|
{
|
|
6834
5085
|
clipId: clip.clipId,
|
|
6835
5086
|
trackIndex,
|
|
@@ -6843,7 +5094,7 @@ var MediaElementPlaylist = ({
|
|
|
6843
5094
|
isSelected: true,
|
|
6844
5095
|
trackId: `media-element-track-${trackIndex}`,
|
|
6845
5096
|
children: [
|
|
6846
|
-
peaksData.data.map((channelPeaks, channelIndex) => /* @__PURE__ */ (0,
|
|
5097
|
+
peaksData.data.map((channelPeaks, channelIndex) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
6847
5098
|
ChannelWithMediaElementProgress,
|
|
6848
5099
|
{
|
|
6849
5100
|
index: channelIndex,
|
|
@@ -6855,8 +5106,8 @@ var MediaElementPlaylist = ({
|
|
|
6855
5106
|
},
|
|
6856
5107
|
`${trackIndex}-${clipIndex}-${channelIndex}`
|
|
6857
5108
|
)),
|
|
6858
|
-
showFades && fadeIn && fadeIn.duration > 0 && /* @__PURE__ */ (0,
|
|
6859
|
-
|
|
5109
|
+
showFades && fadeIn && fadeIn.duration > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5110
|
+
import_ui_components10.FadeOverlay,
|
|
6860
5111
|
{
|
|
6861
5112
|
left: 0,
|
|
6862
5113
|
width: Math.floor(fadeIn.duration * sampleRate / samplesPerPixel),
|
|
@@ -6864,8 +5115,8 @@ var MediaElementPlaylist = ({
|
|
|
6864
5115
|
curveType: fadeIn.type
|
|
6865
5116
|
}
|
|
6866
5117
|
),
|
|
6867
|
-
showFades && fadeOut && fadeOut.duration > 0 && /* @__PURE__ */ (0,
|
|
6868
|
-
|
|
5118
|
+
showFades && fadeOut && fadeOut.duration > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5119
|
+
import_ui_components10.FadeOverlay,
|
|
6869
5120
|
{
|
|
6870
5121
|
left: width - Math.floor(fadeOut.duration * sampleRate / samplesPerPixel),
|
|
6871
5122
|
width: Math.floor(fadeOut.duration * sampleRate / samplesPerPixel),
|
|
@@ -6882,19 +5133,19 @@ var MediaElementPlaylist = ({
|
|
|
6882
5133
|
trackIndex
|
|
6883
5134
|
);
|
|
6884
5135
|
}),
|
|
6885
|
-
annotations.length > 0 && annotationIntegration && /* @__PURE__ */ (0,
|
|
6886
|
-
|
|
5136
|
+
annotations.length > 0 && annotationIntegration && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5137
|
+
import_react31.DragDropProvider,
|
|
6887
5138
|
{
|
|
6888
5139
|
onDragStart,
|
|
6889
5140
|
onDragMove,
|
|
6890
5141
|
onDragEnd,
|
|
6891
5142
|
modifiers: editable ? [import_modifiers.RestrictToHorizontalAxis] : [],
|
|
6892
5143
|
plugins: noDropAnimationPlugins,
|
|
6893
|
-
children: /* @__PURE__ */ (0,
|
|
5144
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(annotationIntegration.AnnotationBoxesWrapper, { height: 30, width: tracksFullWidth, children: annotations.map((annotation, index) => {
|
|
6894
5145
|
const startPosition = annotation.start * sampleRate / samplesPerPixel;
|
|
6895
5146
|
const endPosition = annotation.end * sampleRate / samplesPerPixel;
|
|
6896
5147
|
const label = getAnnotationBoxLabel ? getAnnotationBoxLabel(annotation, index) : annotation.id;
|
|
6897
|
-
return /* @__PURE__ */ (0,
|
|
5148
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
6898
5149
|
annotationIntegration.AnnotationBox,
|
|
6899
5150
|
{
|
|
6900
5151
|
annotationId: annotation.id,
|
|
@@ -6912,15 +5163,15 @@ var MediaElementPlaylist = ({
|
|
|
6912
5163
|
}) })
|
|
6913
5164
|
}
|
|
6914
5165
|
),
|
|
6915
|
-
selectionStart !== selectionEnd && /* @__PURE__ */ (0,
|
|
6916
|
-
|
|
5166
|
+
selectionStart !== selectionEnd && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5167
|
+
import_ui_components10.Selection,
|
|
6917
5168
|
{
|
|
6918
5169
|
startPosition: Math.min(selectionStart, selectionEnd) * sampleRate / samplesPerPixel,
|
|
6919
5170
|
endPosition: Math.max(selectionStart, selectionEnd) * sampleRate / samplesPerPixel,
|
|
6920
5171
|
color: theme.selectionColor
|
|
6921
5172
|
}
|
|
6922
5173
|
),
|
|
6923
|
-
renderPlayhead ? /* @__PURE__ */ (0,
|
|
5174
|
+
renderPlayhead ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
6924
5175
|
CustomMediaElementPlayhead,
|
|
6925
5176
|
{
|
|
6926
5177
|
renderPlayhead,
|
|
@@ -6928,7 +5179,7 @@ var MediaElementPlaylist = ({
|
|
|
6928
5179
|
samplesPerPixel,
|
|
6929
5180
|
sampleRate
|
|
6930
5181
|
}
|
|
6931
|
-
) : /* @__PURE__ */ (0,
|
|
5182
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(AnimatedMediaElementPlayhead, { color: theme.playheadColor })
|
|
6932
5183
|
] })
|
|
6933
5184
|
}
|
|
6934
5185
|
)
|
|
@@ -6937,8 +5188,8 @@ var MediaElementPlaylist = ({
|
|
|
6937
5188
|
};
|
|
6938
5189
|
|
|
6939
5190
|
// src/components/MediaElementAnnotationList.tsx
|
|
6940
|
-
var
|
|
6941
|
-
var
|
|
5191
|
+
var import_react32 = require("react");
|
|
5192
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
6942
5193
|
var MediaElementAnnotationList = ({
|
|
6943
5194
|
height,
|
|
6944
5195
|
renderAnnotationItem,
|
|
@@ -6953,7 +5204,7 @@ var MediaElementAnnotationList = ({
|
|
|
6953
5204
|
const integration = useAnnotationIntegration();
|
|
6954
5205
|
const { setAnnotations } = useMediaElementControls();
|
|
6955
5206
|
const resolvedConfig = annotationListConfig != null ? annotationListConfig : { linkEndpoints: false, continuousPlay };
|
|
6956
|
-
const handleAnnotationUpdate = (0,
|
|
5207
|
+
const handleAnnotationUpdate = (0, import_react32.useCallback)(
|
|
6957
5208
|
(updatedAnnotations) => {
|
|
6958
5209
|
setAnnotations(updatedAnnotations);
|
|
6959
5210
|
onAnnotationUpdate == null ? void 0 : onAnnotationUpdate(updatedAnnotations);
|
|
@@ -6961,7 +5212,7 @@ var MediaElementAnnotationList = ({
|
|
|
6961
5212
|
[setAnnotations, onAnnotationUpdate]
|
|
6962
5213
|
);
|
|
6963
5214
|
const { AnnotationText } = integration;
|
|
6964
|
-
return /* @__PURE__ */ (0,
|
|
5215
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
6965
5216
|
AnnotationText,
|
|
6966
5217
|
{
|
|
6967
5218
|
annotations,
|
|
@@ -6980,7 +5231,7 @@ var MediaElementAnnotationList = ({
|
|
|
6980
5231
|
};
|
|
6981
5232
|
|
|
6982
5233
|
// src/components/MediaElementWaveform.tsx
|
|
6983
|
-
var
|
|
5234
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
6984
5235
|
var MediaElementWaveform = ({
|
|
6985
5236
|
annotationTextHeight,
|
|
6986
5237
|
getAnnotationBoxLabel,
|
|
@@ -6995,8 +5246,8 @@ var MediaElementWaveform = ({
|
|
|
6995
5246
|
className
|
|
6996
5247
|
}) => {
|
|
6997
5248
|
const { annotations } = useMediaElementState();
|
|
6998
|
-
return /* @__PURE__ */ (0,
|
|
6999
|
-
/* @__PURE__ */ (0,
|
|
5249
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
5250
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
7000
5251
|
MediaElementPlaylist,
|
|
7001
5252
|
{
|
|
7002
5253
|
getAnnotationBoxLabel,
|
|
@@ -7008,7 +5259,7 @@ var MediaElementWaveform = ({
|
|
|
7008
5259
|
className
|
|
7009
5260
|
}
|
|
7010
5261
|
),
|
|
7011
|
-
annotations.length > 0 && /* @__PURE__ */ (0,
|
|
5262
|
+
annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
7012
5263
|
MediaElementAnnotationList,
|
|
7013
5264
|
{
|
|
7014
5265
|
height: annotationTextHeight,
|
|
@@ -7083,11 +5334,11 @@ var KeyboardShortcuts = ({
|
|
|
7083
5334
|
};
|
|
7084
5335
|
|
|
7085
5336
|
// src/components/ClipInteractionProvider.tsx
|
|
7086
|
-
var
|
|
7087
|
-
var
|
|
5337
|
+
var import_react33 = __toESM(require("react"));
|
|
5338
|
+
var import_react34 = require("@dnd-kit/react");
|
|
7088
5339
|
var import_modifiers2 = require("@dnd-kit/abstract/modifiers");
|
|
7089
|
-
var
|
|
7090
|
-
var
|
|
5340
|
+
var import_core6 = require("@waveform-playlist/core");
|
|
5341
|
+
var import_ui_components11 = require("@waveform-playlist/ui-components");
|
|
7091
5342
|
|
|
7092
5343
|
// src/modifiers/ClipCollisionModifier.ts
|
|
7093
5344
|
var import_abstract = require("@dnd-kit/abstract");
|
|
@@ -7115,7 +5366,7 @@ var ClipCollisionModifier = _ClipCollisionModifier;
|
|
|
7115
5366
|
|
|
7116
5367
|
// src/modifiers/SnapToGridModifier.ts
|
|
7117
5368
|
var import_abstract2 = require("@dnd-kit/abstract");
|
|
7118
|
-
var
|
|
5369
|
+
var import_core5 = require("@waveform-playlist/core");
|
|
7119
5370
|
var _SnapToGridModifier = class _SnapToGridModifier extends import_abstract2.Modifier {
|
|
7120
5371
|
apply(operation) {
|
|
7121
5372
|
const { transform, source } = operation;
|
|
@@ -7136,18 +5387,18 @@ var _SnapToGridModifier = class _SnapToGridModifier extends import_abstract2.Mod
|
|
|
7136
5387
|
}
|
|
7137
5388
|
const { snapTo, bpm, timeSignature, sampleRate } = this.options;
|
|
7138
5389
|
if (snapTo === "off") return transform;
|
|
7139
|
-
const gridTicks = snapTo === "bar" ? (0,
|
|
5390
|
+
const gridTicks = snapTo === "bar" ? (0, import_core5.ticksPerBar)(timeSignature) : (0, import_core5.ticksPerBeat)(timeSignature);
|
|
7140
5391
|
if (startSample !== void 0) {
|
|
7141
5392
|
const proposedSamples = startSample + transform.x * samplesPerPixel;
|
|
7142
|
-
const proposedTicks = (0,
|
|
7143
|
-
const snappedTicks2 = (0,
|
|
7144
|
-
const snappedSamples2 = (0,
|
|
5393
|
+
const proposedTicks = (0, import_core5.samplesToTicks)(proposedSamples, bpm, sampleRate);
|
|
5394
|
+
const snappedTicks2 = (0, import_core5.snapToGrid)(proposedTicks, gridTicks);
|
|
5395
|
+
const snappedSamples2 = (0, import_core5.ticksToSamples)(snappedTicks2, bpm, sampleRate);
|
|
7145
5396
|
return { x: (snappedSamples2 - startSample) / samplesPerPixel, y: 0 };
|
|
7146
5397
|
}
|
|
7147
5398
|
const deltaSamples = transform.x * samplesPerPixel;
|
|
7148
|
-
const deltaTicks = (0,
|
|
7149
|
-
const snappedTicks = (0,
|
|
7150
|
-
const snappedSamples = (0,
|
|
5399
|
+
const deltaTicks = (0, import_core5.samplesToTicks)(deltaSamples, bpm, sampleRate);
|
|
5400
|
+
const snappedTicks = (0, import_core5.snapToGrid)(deltaTicks, gridTicks);
|
|
5401
|
+
const snappedSamples = (0, import_core5.ticksToSamples)(snappedTicks, bpm, sampleRate);
|
|
7151
5402
|
return { x: snappedSamples / samplesPerPixel, y: 0 };
|
|
7152
5403
|
}
|
|
7153
5404
|
};
|
|
@@ -7155,7 +5406,7 @@ _SnapToGridModifier.configure = (0, import_abstract2.configurator)(_SnapToGridMo
|
|
|
7155
5406
|
var SnapToGridModifier = _SnapToGridModifier;
|
|
7156
5407
|
|
|
7157
5408
|
// src/components/ClipInteractionProvider.tsx
|
|
7158
|
-
var
|
|
5409
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
7159
5410
|
var NOOP_TRACKS_CHANGE = () => {
|
|
7160
5411
|
};
|
|
7161
5412
|
var ClipInteractionProvider = ({
|
|
@@ -7165,28 +5416,28 @@ var ClipInteractionProvider = ({
|
|
|
7165
5416
|
}) => {
|
|
7166
5417
|
const { tracks, samplesPerPixel, sampleRate, playoutRef, isDraggingRef, onTracksChange } = usePlaylistData();
|
|
7167
5418
|
const { setSelectedTrackId } = usePlaylistControls();
|
|
7168
|
-
const beatsAndBars = (0,
|
|
5419
|
+
const beatsAndBars = (0, import_ui_components11.useBeatsAndBars)();
|
|
7169
5420
|
const useBeatsSnap = snap && beatsAndBars != null && beatsAndBars.scaleMode === "beats" && beatsAndBars.snapTo !== "off";
|
|
7170
5421
|
const useTimescaleSnap = snap && !useBeatsSnap;
|
|
7171
|
-
(0,
|
|
5422
|
+
(0, import_react33.useEffect)(() => {
|
|
7172
5423
|
if (onTracksChange == null) {
|
|
7173
5424
|
console.warn(
|
|
7174
5425
|
"[waveform-playlist] ClipInteractionProvider: onTracksChange is not set on WaveformPlaylistProvider. Drag and trim edits will not be persisted."
|
|
7175
5426
|
);
|
|
7176
5427
|
}
|
|
7177
5428
|
}, [onTracksChange]);
|
|
7178
|
-
const snapSamplePosition = (0,
|
|
5429
|
+
const snapSamplePosition = (0, import_react33.useMemo)(() => {
|
|
7179
5430
|
if (useBeatsSnap && beatsAndBars) {
|
|
7180
5431
|
const { bpm, timeSignature, snapTo } = beatsAndBars;
|
|
7181
|
-
const gridTicks = snapTo === "bar" ? (0,
|
|
5432
|
+
const gridTicks = snapTo === "bar" ? (0, import_core6.ticksPerBar)(timeSignature) : (0, import_core6.ticksPerBeat)(timeSignature);
|
|
7182
5433
|
return (samplePos) => {
|
|
7183
|
-
const ticks = (0,
|
|
7184
|
-
const snapped = (0,
|
|
7185
|
-
return (0,
|
|
5434
|
+
const ticks = (0, import_core6.samplesToTicks)(samplePos, bpm, sampleRate);
|
|
5435
|
+
const snapped = (0, import_core6.snapToGrid)(ticks, gridTicks);
|
|
5436
|
+
return (0, import_core6.ticksToSamples)(snapped, bpm, sampleRate);
|
|
7186
5437
|
};
|
|
7187
5438
|
}
|
|
7188
5439
|
if (useTimescaleSnap) {
|
|
7189
|
-
const gridSamples = Math.round((0,
|
|
5440
|
+
const gridSamples = Math.round((0, import_ui_components11.getScaleInfo)(samplesPerPixel).smallStep / 1e3 * sampleRate);
|
|
7190
5441
|
return (samplePos) => Math.round(samplePos / gridSamples) * gridSamples;
|
|
7191
5442
|
}
|
|
7192
5443
|
return void 0;
|
|
@@ -7204,7 +5455,7 @@ var ClipInteractionProvider = ({
|
|
|
7204
5455
|
isDraggingRef,
|
|
7205
5456
|
snapSamplePosition
|
|
7206
5457
|
});
|
|
7207
|
-
const onDragStart =
|
|
5458
|
+
const onDragStart = import_react33.default.useCallback(
|
|
7208
5459
|
(event) => {
|
|
7209
5460
|
var _a, _b, _c;
|
|
7210
5461
|
const trackIndex = (_c = (_b = (_a = event.operation) == null ? void 0 : _a.source) == null ? void 0 : _b.data) == null ? void 0 : _c.trackIndex;
|
|
@@ -7215,7 +5466,7 @@ var ClipInteractionProvider = ({
|
|
|
7215
5466
|
},
|
|
7216
5467
|
[handleDragStart, tracks, setSelectedTrackId]
|
|
7217
5468
|
);
|
|
7218
|
-
const modifiers = (0,
|
|
5469
|
+
const modifiers = (0, import_react33.useMemo)(() => {
|
|
7219
5470
|
const mods = [import_modifiers2.RestrictToHorizontalAxis];
|
|
7220
5471
|
if (useBeatsSnap && beatsAndBars) {
|
|
7221
5472
|
mods.push(
|
|
@@ -7232,7 +5483,7 @@ var ClipInteractionProvider = ({
|
|
|
7232
5483
|
mods.push(
|
|
7233
5484
|
SnapToGridModifier.configure({
|
|
7234
5485
|
mode: "timescale",
|
|
7235
|
-
gridSamples: Math.round((0,
|
|
5486
|
+
gridSamples: Math.round((0, import_ui_components11.getScaleInfo)(samplesPerPixel).smallStep / 1e3 * sampleRate),
|
|
7236
5487
|
samplesPerPixel
|
|
7237
5488
|
})
|
|
7238
5489
|
);
|
|
@@ -7240,8 +5491,8 @@ var ClipInteractionProvider = ({
|
|
|
7240
5491
|
mods.push(ClipCollisionModifier.configure({ tracks, samplesPerPixel }));
|
|
7241
5492
|
return mods;
|
|
7242
5493
|
}, [useBeatsSnap, useTimescaleSnap, beatsAndBars, tracks, samplesPerPixel, sampleRate]);
|
|
7243
|
-
return /* @__PURE__ */ (0,
|
|
7244
|
-
|
|
5494
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ClipInteractionContextProvider, { value: true, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5495
|
+
import_react34.DragDropProvider,
|
|
7245
5496
|
{
|
|
7246
5497
|
sensors,
|
|
7247
5498
|
onDragStart,
|
|
@@ -7264,7 +5515,6 @@ var ClipInteractionProvider = ({
|
|
|
7264
5515
|
ContinuousPlayCheckbox,
|
|
7265
5516
|
DownloadAnnotationsButton,
|
|
7266
5517
|
EditableCheckbox,
|
|
7267
|
-
ExportWavButton,
|
|
7268
5518
|
FastForwardButton,
|
|
7269
5519
|
KeyboardShortcuts,
|
|
7270
5520
|
LinkEndpointsCheckbox,
|
|
@@ -7287,17 +5537,10 @@ var ClipInteractionProvider = ({
|
|
|
7287
5537
|
SpectrogramIntegrationProvider,
|
|
7288
5538
|
StopButton,
|
|
7289
5539
|
TimeFormatSelect,
|
|
7290
|
-
Tone,
|
|
7291
5540
|
Waveform,
|
|
7292
5541
|
WaveformPlaylistProvider,
|
|
7293
5542
|
ZoomInButton,
|
|
7294
5543
|
ZoomOutButton,
|
|
7295
|
-
createEffectChain,
|
|
7296
|
-
createEffectInstance,
|
|
7297
|
-
effectCategories,
|
|
7298
|
-
effectDefinitions,
|
|
7299
|
-
getEffectDefinition,
|
|
7300
|
-
getEffectsByCategory,
|
|
7301
5544
|
getShortcutLabel,
|
|
7302
5545
|
getWaveformDataMetadata,
|
|
7303
5546
|
loadPeaksFromWaveformData,
|
|
@@ -7306,22 +5549,16 @@ var ClipInteractionProvider = ({
|
|
|
7306
5549
|
useAnnotationDragHandlers,
|
|
7307
5550
|
useAnnotationIntegration,
|
|
7308
5551
|
useAnnotationKeyboardControls,
|
|
7309
|
-
useAudioTracks,
|
|
7310
5552
|
useClipDragHandlers,
|
|
7311
5553
|
useClipInteractionEnabled,
|
|
7312
5554
|
useClipSplitting,
|
|
7313
5555
|
useDragSensors,
|
|
7314
|
-
useDynamicEffects,
|
|
7315
|
-
useDynamicTracks,
|
|
7316
|
-
useExportWav,
|
|
7317
5556
|
useKeyboardShortcuts,
|
|
7318
|
-
useMasterAnalyser,
|
|
7319
5557
|
useMasterVolume,
|
|
7320
5558
|
useMediaElementAnimation,
|
|
7321
5559
|
useMediaElementControls,
|
|
7322
5560
|
useMediaElementData,
|
|
7323
5561
|
useMediaElementState,
|
|
7324
|
-
useOutputMeter,
|
|
7325
5562
|
usePlaybackAnimation,
|
|
7326
5563
|
usePlaybackShortcuts,
|
|
7327
5564
|
usePlaylistControls,
|
|
@@ -7330,7 +5567,6 @@ var ClipInteractionProvider = ({
|
|
|
7330
5567
|
usePlaylistState,
|
|
7331
5568
|
useSpectrogramIntegration,
|
|
7332
5569
|
useTimeFormat,
|
|
7333
|
-
useTrackDynamicEffects,
|
|
7334
5570
|
useZoomControls,
|
|
7335
5571
|
waveformDataToPeaks
|
|
7336
5572
|
});
|