@waveform-playlist/browser 13.1.2 → 14.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +50 -434
- package/dist/index.d.ts +50 -434
- package/dist/index.js +618 -2372
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +515 -2293
- package/dist/index.mjs.map +1 -1
- package/dist/tone.d.mts +429 -0
- package/dist/tone.d.ts +429 -0
- package/dist/tone.js +1963 -0
- package/dist/tone.js.map +1 -0
- package/dist/tone.mjs +1958 -0
- package/dist/tone.mjs.map +1 -0
- package/package.json +23 -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,43 +122,65 @@ __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,
|
|
152
138
|
usePlaylistData: () => usePlaylistData,
|
|
139
|
+
usePlaylistDataOptional: () => usePlaylistDataOptional,
|
|
153
140
|
usePlaylistState: () => usePlaylistState,
|
|
154
141
|
useSpectrogramIntegration: () => useSpectrogramIntegration,
|
|
155
142
|
useTimeFormat: () => useTimeFormat,
|
|
156
|
-
useTrackDynamicEffects: () => useTrackDynamicEffects,
|
|
157
143
|
useZoomControls: () => useZoomControls,
|
|
158
144
|
waveformDataToPeaks: () => waveformDataToPeaks
|
|
159
145
|
});
|
|
160
146
|
module.exports = __toCommonJS(index_exports);
|
|
161
|
-
var Tone2 = __toESM(require("tone"));
|
|
162
147
|
|
|
163
148
|
// src/WaveformPlaylistContext.tsx
|
|
164
|
-
var
|
|
149
|
+
var import_react17 = require("react");
|
|
165
150
|
var import_styled_components = require("styled-components");
|
|
166
|
-
|
|
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
|
|
167
182
|
var import_engine3 = require("@waveform-playlist/engine");
|
|
168
183
|
var import_ui_components2 = require("@waveform-playlist/ui-components");
|
|
169
|
-
var import_tone4 = require("tone");
|
|
170
184
|
|
|
171
185
|
// src/waveformDataLoader.ts
|
|
172
186
|
var import_waveform_data = __toESM(require("waveform-data"));
|
|
@@ -332,9 +346,11 @@ function extractPeaksFromWaveformDataFull(waveformData, samplesPerPixel, isMono,
|
|
|
332
346
|
}
|
|
333
347
|
|
|
334
348
|
// src/soundFontSync.ts
|
|
335
|
-
|
|
349
|
+
function supportsSoundFont(adapter) {
|
|
350
|
+
return adapter != null && typeof adapter.setSoundFontCache === "function";
|
|
351
|
+
}
|
|
336
352
|
function syncSoundFontCacheToAdapter(adapter, cache) {
|
|
337
|
-
if (!(
|
|
353
|
+
if (!supportsSoundFont(adapter)) return;
|
|
338
354
|
adapter.setSoundFontCache(cache);
|
|
339
355
|
}
|
|
340
356
|
|
|
@@ -591,223 +607,8 @@ function useUndoState({ engineRef }) {
|
|
|
591
607
|
};
|
|
592
608
|
}
|
|
593
609
|
|
|
594
|
-
// src/hooks/useAudioEffects.ts
|
|
595
|
-
var import_react8 = require("react");
|
|
596
|
-
var import_tone = require("tone");
|
|
597
|
-
var useMasterAnalyser = (fftSize = 256) => {
|
|
598
|
-
const analyserRef = (0, import_react8.useRef)(null);
|
|
599
|
-
const masterEffects = (0, import_react8.useCallback)(
|
|
600
|
-
(masterGainNode, destination, _isOffline) => {
|
|
601
|
-
const analyserNode = new import_tone.Analyser("fft", fftSize);
|
|
602
|
-
masterGainNode.connect(analyserNode);
|
|
603
|
-
masterGainNode.connect(destination);
|
|
604
|
-
analyserRef.current = analyserNode;
|
|
605
|
-
return function cleanup() {
|
|
606
|
-
analyserNode.dispose();
|
|
607
|
-
analyserRef.current = null;
|
|
608
|
-
};
|
|
609
|
-
},
|
|
610
|
-
[fftSize]
|
|
611
|
-
);
|
|
612
|
-
return { analyserRef, masterEffects };
|
|
613
|
-
};
|
|
614
|
-
|
|
615
|
-
// src/hooks/useAudioTracks.ts
|
|
616
|
-
var import_react9 = require("react");
|
|
617
|
-
var import_core = require("@waveform-playlist/core");
|
|
618
|
-
var Tone = __toESM(require("tone"));
|
|
619
|
-
function buildTrackFromConfig(config, index, audioBuffer, stableIds, contextSampleRate = 48e3) {
|
|
620
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
|
|
621
|
-
const buffer = audioBuffer != null ? audioBuffer : config.audioBuffer;
|
|
622
|
-
const sampleRate = (_c = (_b = buffer == null ? void 0 : buffer.sampleRate) != null ? _b : (_a = config.waveformData) == null ? void 0 : _a.sample_rate) != null ? _c : contextSampleRate;
|
|
623
|
-
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;
|
|
624
|
-
if (sourceDuration === void 0) {
|
|
625
|
-
console.warn(
|
|
626
|
-
`[waveform-playlist] Track ${index + 1} ("${(_h = config.name) != null ? _h : "unnamed"}"): Cannot create track \u2014 provide duration, audioBuffer, or waveformData with duration.`
|
|
627
|
-
);
|
|
628
|
-
return null;
|
|
629
|
-
}
|
|
630
|
-
const clip = (0, import_core.createClipFromSeconds)({
|
|
631
|
-
audioBuffer: buffer,
|
|
632
|
-
sampleRate,
|
|
633
|
-
sourceDuration,
|
|
634
|
-
startTime: (_i = config.startTime) != null ? _i : 0,
|
|
635
|
-
duration: (_j = config.duration) != null ? _j : sourceDuration,
|
|
636
|
-
offset: (_k = config.offset) != null ? _k : 0,
|
|
637
|
-
name: config.name || `Track ${index + 1}`,
|
|
638
|
-
fadeIn: config.fadeIn,
|
|
639
|
-
fadeOut: config.fadeOut,
|
|
640
|
-
waveformData: config.waveformData
|
|
641
|
-
});
|
|
642
|
-
if (isNaN(clip.startSample) || isNaN(clip.durationSamples) || isNaN(clip.offsetSamples)) {
|
|
643
|
-
console.error(
|
|
644
|
-
`[waveform-playlist] Invalid clip values for track ${index + 1} ("${(_l = config.name) != null ? _l : "unnamed"}"): startSample=${clip.startSample}, durationSamples=${clip.durationSamples}, offsetSamples=${clip.offsetSamples}`
|
|
645
|
-
);
|
|
646
|
-
return null;
|
|
647
|
-
}
|
|
648
|
-
const track = __spreadProps(__spreadValues({}, (0, import_core.createTrack)({
|
|
649
|
-
name: config.name || `Track ${index + 1}`,
|
|
650
|
-
clips: [clip],
|
|
651
|
-
muted: (_m = config.muted) != null ? _m : false,
|
|
652
|
-
soloed: (_n = config.soloed) != null ? _n : false,
|
|
653
|
-
volume: (_o = config.volume) != null ? _o : 1,
|
|
654
|
-
pan: (_p = config.pan) != null ? _p : 0,
|
|
655
|
-
color: config.color
|
|
656
|
-
})), {
|
|
657
|
-
effects: config.effects,
|
|
658
|
-
renderMode: config.renderMode,
|
|
659
|
-
spectrogramConfig: config.spectrogramConfig,
|
|
660
|
-
spectrogramColorMap: config.spectrogramColorMap
|
|
661
|
-
});
|
|
662
|
-
const existingIds = stableIds.get(index);
|
|
663
|
-
if (existingIds) {
|
|
664
|
-
track.id = existingIds.trackId;
|
|
665
|
-
track.clips[0] = __spreadProps(__spreadValues({}, track.clips[0]), { id: existingIds.clipId });
|
|
666
|
-
} else {
|
|
667
|
-
stableIds.set(index, { trackId: track.id, clipId: track.clips[0].id });
|
|
668
|
-
}
|
|
669
|
-
return track;
|
|
670
|
-
}
|
|
671
|
-
function useAudioTracks(configs, options = {}) {
|
|
672
|
-
const { immediate = false, progressive = false } = options;
|
|
673
|
-
const isImmediate = immediate || progressive;
|
|
674
|
-
const [loading, setLoading] = (0, import_react9.useState)(true);
|
|
675
|
-
const [error, setError] = (0, import_react9.useState)(null);
|
|
676
|
-
const [loadedCount, setLoadedCount] = (0, import_react9.useState)(0);
|
|
677
|
-
const totalCount = configs.length;
|
|
678
|
-
const [loadedBuffers, setLoadedBuffers] = (0, import_react9.useState)(/* @__PURE__ */ new Map());
|
|
679
|
-
const stableIdsRef = (0, import_react9.useRef)(/* @__PURE__ */ new Map());
|
|
680
|
-
const contextSampleRateRef = (0, import_react9.useRef)(48e3);
|
|
681
|
-
const derivedTracks = (0, import_react9.useMemo)(() => {
|
|
682
|
-
if (!isImmediate) return null;
|
|
683
|
-
const result = [];
|
|
684
|
-
for (let i = 0; i < configs.length; i++) {
|
|
685
|
-
const track = buildTrackFromConfig(
|
|
686
|
-
configs[i],
|
|
687
|
-
i,
|
|
688
|
-
loadedBuffers.get(i),
|
|
689
|
-
stableIdsRef.current,
|
|
690
|
-
contextSampleRateRef.current
|
|
691
|
-
);
|
|
692
|
-
if (track) result.push(track);
|
|
693
|
-
}
|
|
694
|
-
return result;
|
|
695
|
-
}, [isImmediate, configs, loadedBuffers]);
|
|
696
|
-
const [tracks, setTracks] = (0, import_react9.useState)(derivedTracks != null ? derivedTracks : []);
|
|
697
|
-
const prevDerivedRef = (0, import_react9.useRef)(derivedTracks);
|
|
698
|
-
if (derivedTracks !== prevDerivedRef.current) {
|
|
699
|
-
prevDerivedRef.current = derivedTracks;
|
|
700
|
-
if (derivedTracks) setTracks(derivedTracks);
|
|
701
|
-
}
|
|
702
|
-
(0, import_react9.useEffect)(() => {
|
|
703
|
-
if (configs.length === 0) {
|
|
704
|
-
setTracks([]);
|
|
705
|
-
setLoading(false);
|
|
706
|
-
setLoadedCount(0);
|
|
707
|
-
return;
|
|
708
|
-
}
|
|
709
|
-
let cancelled = false;
|
|
710
|
-
const abortController = new AbortController();
|
|
711
|
-
const loadTracks = () => __async(null, null, function* () {
|
|
712
|
-
try {
|
|
713
|
-
setLoading(true);
|
|
714
|
-
setError(null);
|
|
715
|
-
setLoadedCount(0);
|
|
716
|
-
if (isImmediate) {
|
|
717
|
-
setLoadedBuffers(/* @__PURE__ */ new Map());
|
|
718
|
-
}
|
|
719
|
-
const audioContext = Tone.getContext().rawContext;
|
|
720
|
-
contextSampleRateRef.current = audioContext.sampleRate;
|
|
721
|
-
const loadPromises = configs.map((config, index) => __async(null, null, function* () {
|
|
722
|
-
if (config.audioBuffer) {
|
|
723
|
-
if (isImmediate && !cancelled) {
|
|
724
|
-
setLoadedBuffers((prev) => {
|
|
725
|
-
const next = new Map(prev);
|
|
726
|
-
next.set(index, config.audioBuffer);
|
|
727
|
-
return next;
|
|
728
|
-
});
|
|
729
|
-
setLoadedCount((prev) => prev + 1);
|
|
730
|
-
return;
|
|
731
|
-
}
|
|
732
|
-
return buildTrackFromConfig(
|
|
733
|
-
config,
|
|
734
|
-
index,
|
|
735
|
-
config.audioBuffer,
|
|
736
|
-
stableIdsRef.current,
|
|
737
|
-
audioContext.sampleRate
|
|
738
|
-
);
|
|
739
|
-
}
|
|
740
|
-
if (!config.src && config.waveformData) {
|
|
741
|
-
if (isImmediate && !cancelled) {
|
|
742
|
-
setLoadedCount((prev) => prev + 1);
|
|
743
|
-
return;
|
|
744
|
-
}
|
|
745
|
-
return buildTrackFromConfig(
|
|
746
|
-
config,
|
|
747
|
-
index,
|
|
748
|
-
void 0,
|
|
749
|
-
stableIdsRef.current,
|
|
750
|
-
audioContext.sampleRate
|
|
751
|
-
);
|
|
752
|
-
}
|
|
753
|
-
if (!config.src) {
|
|
754
|
-
throw new Error(`Track ${index + 1}: Must provide src, audioBuffer, or waveformData`);
|
|
755
|
-
}
|
|
756
|
-
const response = yield fetch(config.src, { signal: abortController.signal });
|
|
757
|
-
if (!response.ok) {
|
|
758
|
-
throw new Error(`Failed to fetch ${config.src}: ${response.statusText}`);
|
|
759
|
-
}
|
|
760
|
-
const arrayBuffer = yield response.arrayBuffer();
|
|
761
|
-
const audioBuffer = yield audioContext.decodeAudioData(arrayBuffer);
|
|
762
|
-
if (!audioBuffer || !audioBuffer.sampleRate || !audioBuffer.duration) {
|
|
763
|
-
throw new Error(`Invalid audio buffer for ${config.src}`);
|
|
764
|
-
}
|
|
765
|
-
if (isImmediate && !cancelled) {
|
|
766
|
-
setLoadedBuffers((prev) => {
|
|
767
|
-
const next = new Map(prev);
|
|
768
|
-
next.set(index, audioBuffer);
|
|
769
|
-
return next;
|
|
770
|
-
});
|
|
771
|
-
setLoadedCount((prev) => prev + 1);
|
|
772
|
-
return;
|
|
773
|
-
}
|
|
774
|
-
return buildTrackFromConfig(
|
|
775
|
-
config,
|
|
776
|
-
index,
|
|
777
|
-
audioBuffer,
|
|
778
|
-
stableIdsRef.current,
|
|
779
|
-
audioContext.sampleRate
|
|
780
|
-
);
|
|
781
|
-
}));
|
|
782
|
-
const loadedTracks = yield Promise.all(loadPromises);
|
|
783
|
-
if (!cancelled) {
|
|
784
|
-
if (!isImmediate) {
|
|
785
|
-
const validTracks = loadedTracks.filter((t) => t != null);
|
|
786
|
-
setTracks(validTracks);
|
|
787
|
-
setLoadedCount(validTracks.length);
|
|
788
|
-
}
|
|
789
|
-
setLoading(false);
|
|
790
|
-
}
|
|
791
|
-
} catch (err) {
|
|
792
|
-
if (!cancelled) {
|
|
793
|
-
const errorMessage = err instanceof Error ? err.message : "Unknown error loading audio";
|
|
794
|
-
setError(errorMessage);
|
|
795
|
-
setLoading(false);
|
|
796
|
-
console.error(`[waveform-playlist] Error loading audio tracks: ${errorMessage}`);
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
});
|
|
800
|
-
loadTracks();
|
|
801
|
-
return () => {
|
|
802
|
-
cancelled = true;
|
|
803
|
-
abortController.abort();
|
|
804
|
-
};
|
|
805
|
-
}, [configs, isImmediate]);
|
|
806
|
-
return { tracks, loading, error, loadedCount, totalCount };
|
|
807
|
-
}
|
|
808
|
-
|
|
809
610
|
// src/hooks/useClipDragHandlers.ts
|
|
810
|
-
var
|
|
611
|
+
var import_react8 = __toESM(require("react"));
|
|
811
612
|
|
|
812
613
|
// src/utils/boundaryTrim.ts
|
|
813
614
|
var import_engine = require("@waveform-playlist/engine");
|
|
@@ -861,11 +662,11 @@ function useClipDragHandlers({
|
|
|
861
662
|
snapSamplePosition
|
|
862
663
|
}) {
|
|
863
664
|
const { sampleRate } = usePlaylistData();
|
|
864
|
-
const snapSamplePositionRef =
|
|
665
|
+
const snapSamplePositionRef = import_react8.default.useRef(snapSamplePosition);
|
|
865
666
|
snapSamplePositionRef.current = snapSamplePosition;
|
|
866
|
-
const originalClipStateRef =
|
|
867
|
-
const lastBoundaryDeltaRef =
|
|
868
|
-
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(
|
|
869
670
|
(event) => {
|
|
870
671
|
var _a;
|
|
871
672
|
const data = (_a = event.operation.source) == null ? void 0 : _a.data;
|
|
@@ -901,7 +702,7 @@ function useClipDragHandlers({
|
|
|
901
702
|
},
|
|
902
703
|
[tracks, isDraggingRef, engineRef]
|
|
903
704
|
);
|
|
904
|
-
const onDragMove =
|
|
705
|
+
const onDragMove = import_react8.default.useCallback(
|
|
905
706
|
(event) => {
|
|
906
707
|
var _a, _b, _c;
|
|
907
708
|
const data = (_a = event.operation.source) == null ? void 0 : _a.data;
|
|
@@ -963,7 +764,7 @@ function useClipDragHandlers({
|
|
|
963
764
|
},
|
|
964
765
|
[tracks, onTracksChange, samplesPerPixel, sampleRate]
|
|
965
766
|
);
|
|
966
|
-
const onDragEnd =
|
|
767
|
+
const onDragEnd = import_react8.default.useCallback(
|
|
967
768
|
(event) => {
|
|
968
769
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
969
770
|
if (event.canceled) {
|
|
@@ -1041,19 +842,19 @@ function useClipDragHandlers({
|
|
|
1041
842
|
}
|
|
1042
843
|
|
|
1043
844
|
// src/hooks/useAnnotationDragHandlers.ts
|
|
1044
|
-
var
|
|
1045
|
-
var import_playout2 = require("@waveform-playlist/playout");
|
|
845
|
+
var import_react9 = __toESM(require("react"));
|
|
1046
846
|
var LINK_THRESHOLD = 0.01;
|
|
1047
847
|
function useAnnotationDragHandlers({
|
|
1048
848
|
annotations,
|
|
1049
849
|
onAnnotationsChange,
|
|
1050
850
|
samplesPerPixel,
|
|
1051
|
-
|
|
851
|
+
// Default mirrors the engine default; the providers always pass the real rate from context (#510).
|
|
852
|
+
sampleRate = 48e3,
|
|
1052
853
|
duration,
|
|
1053
854
|
linkEndpoints
|
|
1054
855
|
}) {
|
|
1055
|
-
const originalAnnotationStateRef =
|
|
1056
|
-
const onDragStart =
|
|
856
|
+
const originalAnnotationStateRef = import_react9.default.useRef(null);
|
|
857
|
+
const onDragStart = import_react9.default.useCallback(
|
|
1057
858
|
(event) => {
|
|
1058
859
|
var _a;
|
|
1059
860
|
const data = (_a = event.operation.source) == null ? void 0 : _a.data;
|
|
@@ -1072,7 +873,7 @@ function useAnnotationDragHandlers({
|
|
|
1072
873
|
},
|
|
1073
874
|
[annotations]
|
|
1074
875
|
);
|
|
1075
|
-
const onDragMove =
|
|
876
|
+
const onDragMove = import_react9.default.useCallback(
|
|
1076
877
|
(event) => {
|
|
1077
878
|
var _a, _b, _c;
|
|
1078
879
|
if (!originalAnnotationStateRef.current) {
|
|
@@ -1098,7 +899,7 @@ function useAnnotationDragHandlers({
|
|
|
1098
899
|
},
|
|
1099
900
|
[annotations, onAnnotationsChange, samplesPerPixel, sampleRate, duration, linkEndpoints]
|
|
1100
901
|
);
|
|
1101
|
-
const onDragEnd =
|
|
902
|
+
const onDragEnd = import_react9.default.useCallback(
|
|
1102
903
|
(event) => {
|
|
1103
904
|
if (event.canceled && originalAnnotationStateRef.current) {
|
|
1104
905
|
const { annotationIndex, start, end } = originalAnnotationStateRef.current;
|
|
@@ -1206,7 +1007,7 @@ function updateAnnotationBoundaries({
|
|
|
1206
1007
|
}
|
|
1207
1008
|
|
|
1208
1009
|
// src/hooks/useDragSensors.ts
|
|
1209
|
-
var
|
|
1010
|
+
var import_react10 = require("react");
|
|
1210
1011
|
var import_dom = require("@dnd-kit/dom");
|
|
1211
1012
|
function useDragSensors(options = {}) {
|
|
1212
1013
|
const {
|
|
@@ -1215,7 +1016,7 @@ function useDragSensors(options = {}) {
|
|
|
1215
1016
|
touchTolerance = 5,
|
|
1216
1017
|
mouseDistance = 1
|
|
1217
1018
|
} = options;
|
|
1218
|
-
return (0,
|
|
1019
|
+
return (0, import_react10.useMemo)(() => {
|
|
1219
1020
|
if (touchOptimized) {
|
|
1220
1021
|
return [
|
|
1221
1022
|
import_dom.PointerSensor.configure({
|
|
@@ -1244,14 +1045,14 @@ function useDragSensors(options = {}) {
|
|
|
1244
1045
|
}
|
|
1245
1046
|
|
|
1246
1047
|
// src/hooks/useClipSplitting.ts
|
|
1247
|
-
var
|
|
1048
|
+
var import_react11 = require("react");
|
|
1248
1049
|
var import_engine2 = require("@waveform-playlist/engine");
|
|
1249
1050
|
var useClipSplitting = (options) => {
|
|
1250
1051
|
const { tracks, engineRef } = options;
|
|
1251
1052
|
const { sampleRate } = usePlaylistData();
|
|
1252
1053
|
const { currentTimeRef } = usePlaybackAnimation();
|
|
1253
1054
|
const { selectedTrackId } = usePlaylistState();
|
|
1254
|
-
const splitClipAt = (0,
|
|
1055
|
+
const splitClipAt = (0, import_react11.useCallback)(
|
|
1255
1056
|
(trackIndex, clipIndex, splitTime) => {
|
|
1256
1057
|
const { samplesPerPixel } = options;
|
|
1257
1058
|
const track = tracks[trackIndex];
|
|
@@ -1275,7 +1076,7 @@ var useClipSplitting = (options) => {
|
|
|
1275
1076
|
},
|
|
1276
1077
|
[tracks, options, engineRef, sampleRate]
|
|
1277
1078
|
);
|
|
1278
|
-
const splitClipAtPlayhead = (0,
|
|
1079
|
+
const splitClipAtPlayhead = (0, import_react11.useCallback)(() => {
|
|
1279
1080
|
var _a;
|
|
1280
1081
|
if (!selectedTrackId) {
|
|
1281
1082
|
console.warn("[waveform-playlist] No track selected \u2014 click a clip to select a track first");
|
|
@@ -1306,16 +1107,16 @@ var useClipSplitting = (options) => {
|
|
|
1306
1107
|
};
|
|
1307
1108
|
|
|
1308
1109
|
// src/hooks/useKeyboardShortcuts.ts
|
|
1309
|
-
var
|
|
1110
|
+
var import_react12 = require("react");
|
|
1111
|
+
var import_core = require("@waveform-playlist/core");
|
|
1310
1112
|
var import_core2 = require("@waveform-playlist/core");
|
|
1311
|
-
var import_core3 = require("@waveform-playlist/core");
|
|
1312
1113
|
var useKeyboardShortcuts = (options) => {
|
|
1313
1114
|
const { shortcuts, enabled = true } = options;
|
|
1314
|
-
const handleKeyDown = (0,
|
|
1315
|
-
(event) => (0,
|
|
1115
|
+
const handleKeyDown = (0, import_react12.useCallback)(
|
|
1116
|
+
(event) => (0, import_core.handleKeyboardEvent)(event, shortcuts, enabled),
|
|
1316
1117
|
[shortcuts, enabled]
|
|
1317
1118
|
);
|
|
1318
|
-
(0,
|
|
1119
|
+
(0, import_react12.useEffect)(() => {
|
|
1319
1120
|
if (!enabled) return;
|
|
1320
1121
|
window.addEventListener("keydown", handleKeyDown);
|
|
1321
1122
|
return () => {
|
|
@@ -1325,22 +1126,22 @@ var useKeyboardShortcuts = (options) => {
|
|
|
1325
1126
|
};
|
|
1326
1127
|
|
|
1327
1128
|
// src/hooks/usePlaybackShortcuts.ts
|
|
1328
|
-
var
|
|
1129
|
+
var import_react13 = require("react");
|
|
1329
1130
|
var usePlaybackShortcuts = (options = {}) => {
|
|
1330
1131
|
const { enabled = true, additionalShortcuts = [], shortcuts: overrideShortcuts } = options;
|
|
1331
1132
|
const { isPlaying } = usePlaybackAnimation();
|
|
1332
1133
|
const { setCurrentTime, play, pause, stop } = usePlaylistControls();
|
|
1333
|
-
const togglePlayPause = (0,
|
|
1134
|
+
const togglePlayPause = (0, import_react13.useCallback)(() => {
|
|
1334
1135
|
if (isPlaying) {
|
|
1335
1136
|
pause();
|
|
1336
1137
|
} else {
|
|
1337
1138
|
play();
|
|
1338
1139
|
}
|
|
1339
1140
|
}, [isPlaying, play, pause]);
|
|
1340
|
-
const stopPlayback = (0,
|
|
1141
|
+
const stopPlayback = (0, import_react13.useCallback)(() => {
|
|
1341
1142
|
stop();
|
|
1342
1143
|
}, [stop]);
|
|
1343
|
-
const rewindToStart = (0,
|
|
1144
|
+
const rewindToStart = (0, import_react13.useCallback)(() => {
|
|
1344
1145
|
setCurrentTime(0);
|
|
1345
1146
|
if (isPlaying) {
|
|
1346
1147
|
play(0);
|
|
@@ -1380,7 +1181,7 @@ var usePlaybackShortcuts = (options = {}) => {
|
|
|
1380
1181
|
};
|
|
1381
1182
|
|
|
1382
1183
|
// src/hooks/useAnnotationKeyboardControls.ts
|
|
1383
|
-
var
|
|
1184
|
+
var import_react14 = require("react");
|
|
1384
1185
|
var LINK_THRESHOLD2 = 0.01;
|
|
1385
1186
|
var TIME_DELTA = 0.01;
|
|
1386
1187
|
function useAnnotationKeyboardControls({
|
|
@@ -1393,14 +1194,18 @@ function useAnnotationKeyboardControls({
|
|
|
1393
1194
|
continuousPlay = false,
|
|
1394
1195
|
enabled = true,
|
|
1395
1196
|
scrollContainerRef,
|
|
1396
|
-
onPlay
|
|
1197
|
+
onPlay,
|
|
1198
|
+
samplesPerPixel: samplesPerPixelProp,
|
|
1199
|
+
sampleRate: sampleRateProp
|
|
1397
1200
|
}) {
|
|
1398
|
-
const
|
|
1399
|
-
const
|
|
1201
|
+
const playlistData = usePlaylistDataOptional();
|
|
1202
|
+
const samplesPerPixel = samplesPerPixelProp != null ? samplesPerPixelProp : playlistData == null ? void 0 : playlistData.samplesPerPixel;
|
|
1203
|
+
const sampleRate = sampleRateProp != null ? sampleRateProp : playlistData == null ? void 0 : playlistData.sampleRate;
|
|
1204
|
+
const activeIndex = (0, import_react14.useMemo)(() => {
|
|
1400
1205
|
if (!activeAnnotationId) return -1;
|
|
1401
1206
|
return annotations.findIndex((a) => a.id === activeAnnotationId);
|
|
1402
1207
|
}, [annotations, activeAnnotationId]);
|
|
1403
|
-
const scrollToAnnotation = (0,
|
|
1208
|
+
const scrollToAnnotation = (0, import_react14.useCallback)(
|
|
1404
1209
|
(annotationId) => {
|
|
1405
1210
|
if (!(scrollContainerRef == null ? void 0 : scrollContainerRef.current) || !samplesPerPixel || !sampleRate) return;
|
|
1406
1211
|
const annotation = annotations.find((a) => a.id === annotationId);
|
|
@@ -1423,12 +1228,12 @@ function useAnnotationKeyboardControls({
|
|
|
1423
1228
|
},
|
|
1424
1229
|
[annotations, scrollContainerRef, samplesPerPixel, sampleRate]
|
|
1425
1230
|
);
|
|
1426
|
-
(0,
|
|
1231
|
+
(0, import_react14.useEffect)(() => {
|
|
1427
1232
|
if (activeAnnotationId && (scrollContainerRef == null ? void 0 : scrollContainerRef.current) && samplesPerPixel && sampleRate) {
|
|
1428
1233
|
scrollToAnnotation(activeAnnotationId);
|
|
1429
1234
|
}
|
|
1430
1235
|
}, [activeAnnotationId, scrollToAnnotation, scrollContainerRef, samplesPerPixel, sampleRate]);
|
|
1431
|
-
const moveStartBoundary = (0,
|
|
1236
|
+
const moveStartBoundary = (0, import_react14.useCallback)(
|
|
1432
1237
|
(delta) => {
|
|
1433
1238
|
if (activeIndex < 0) return;
|
|
1434
1239
|
const annotation = annotations[activeIndex];
|
|
@@ -1457,7 +1262,7 @@ function useAnnotationKeyboardControls({
|
|
|
1457
1262
|
},
|
|
1458
1263
|
[annotations, activeIndex, linkEndpoints, onAnnotationsChange]
|
|
1459
1264
|
);
|
|
1460
|
-
const moveEndBoundary = (0,
|
|
1265
|
+
const moveEndBoundary = (0, import_react14.useCallback)(
|
|
1461
1266
|
(delta) => {
|
|
1462
1267
|
if (activeIndex < 0) return;
|
|
1463
1268
|
const annotation = annotations[activeIndex];
|
|
@@ -1517,7 +1322,7 @@ function useAnnotationKeyboardControls({
|
|
|
1517
1322
|
},
|
|
1518
1323
|
[annotations, activeIndex, duration, linkEndpoints, onAnnotationsChange]
|
|
1519
1324
|
);
|
|
1520
|
-
const selectPrevious = (0,
|
|
1325
|
+
const selectPrevious = (0, import_react14.useCallback)(() => {
|
|
1521
1326
|
if (!onActiveAnnotationChange || annotations.length === 0) return;
|
|
1522
1327
|
if (activeIndex <= 0) {
|
|
1523
1328
|
onActiveAnnotationChange(annotations[annotations.length - 1].id);
|
|
@@ -1525,7 +1330,7 @@ function useAnnotationKeyboardControls({
|
|
|
1525
1330
|
onActiveAnnotationChange(annotations[activeIndex - 1].id);
|
|
1526
1331
|
}
|
|
1527
1332
|
}, [annotations, activeIndex, onActiveAnnotationChange]);
|
|
1528
|
-
const selectNext = (0,
|
|
1333
|
+
const selectNext = (0, import_react14.useCallback)(() => {
|
|
1529
1334
|
if (!onActiveAnnotationChange || annotations.length === 0) return;
|
|
1530
1335
|
if (activeIndex < 0 || activeIndex >= annotations.length - 1) {
|
|
1531
1336
|
onActiveAnnotationChange(annotations[0].id);
|
|
@@ -1533,25 +1338,25 @@ function useAnnotationKeyboardControls({
|
|
|
1533
1338
|
onActiveAnnotationChange(annotations[activeIndex + 1].id);
|
|
1534
1339
|
}
|
|
1535
1340
|
}, [annotations, activeIndex, onActiveAnnotationChange]);
|
|
1536
|
-
const selectFirst = (0,
|
|
1341
|
+
const selectFirst = (0, import_react14.useCallback)(() => {
|
|
1537
1342
|
if (!onActiveAnnotationChange || annotations.length === 0) return;
|
|
1538
1343
|
onActiveAnnotationChange(annotations[0].id);
|
|
1539
1344
|
}, [annotations, onActiveAnnotationChange]);
|
|
1540
|
-
const selectLast = (0,
|
|
1345
|
+
const selectLast = (0, import_react14.useCallback)(() => {
|
|
1541
1346
|
if (!onActiveAnnotationChange || annotations.length === 0) return;
|
|
1542
1347
|
onActiveAnnotationChange(annotations[annotations.length - 1].id);
|
|
1543
1348
|
}, [annotations, onActiveAnnotationChange]);
|
|
1544
|
-
const clearSelection = (0,
|
|
1349
|
+
const clearSelection = (0, import_react14.useCallback)(() => {
|
|
1545
1350
|
if (!onActiveAnnotationChange) return;
|
|
1546
1351
|
onActiveAnnotationChange(null);
|
|
1547
1352
|
}, [onActiveAnnotationChange]);
|
|
1548
|
-
const playActiveAnnotation = (0,
|
|
1353
|
+
const playActiveAnnotation = (0, import_react14.useCallback)(() => {
|
|
1549
1354
|
if (activeIndex < 0 || !onPlay) return;
|
|
1550
1355
|
const annotation = annotations[activeIndex];
|
|
1551
1356
|
const playDuration = !continuousPlay ? annotation.end - annotation.start : void 0;
|
|
1552
1357
|
onPlay(annotation.start, playDuration);
|
|
1553
1358
|
}, [annotations, activeIndex, continuousPlay, onPlay]);
|
|
1554
|
-
const activeAnnotationShortcuts = (0,
|
|
1359
|
+
const activeAnnotationShortcuts = (0, import_react14.useMemo)(
|
|
1555
1360
|
() => [
|
|
1556
1361
|
{
|
|
1557
1362
|
key: "[",
|
|
@@ -1588,7 +1393,7 @@ function useAnnotationKeyboardControls({
|
|
|
1588
1393
|
],
|
|
1589
1394
|
[moveStartBoundary, moveEndBoundary, playActiveAnnotation]
|
|
1590
1395
|
);
|
|
1591
|
-
const navigationShortcuts = (0,
|
|
1396
|
+
const navigationShortcuts = (0, import_react14.useMemo)(
|
|
1592
1397
|
() => [
|
|
1593
1398
|
{
|
|
1594
1399
|
key: "ArrowUp",
|
|
@@ -1634,1404 +1439,46 @@ function useAnnotationKeyboardControls({
|
|
|
1634
1439
|
}
|
|
1635
1440
|
],
|
|
1636
1441
|
[selectPrevious, selectNext, selectFirst, selectLast, clearSelection]
|
|
1637
|
-
);
|
|
1638
|
-
useKeyboardShortcuts({
|
|
1639
|
-
shortcuts: activeAnnotationShortcuts,
|
|
1640
|
-
enabled: enabled && activeIndex >= 0
|
|
1641
|
-
});
|
|
1642
|
-
useKeyboardShortcuts({
|
|
1643
|
-
shortcuts: navigationShortcuts,
|
|
1644
|
-
enabled: enabled && annotations.length > 0 && !!onActiveAnnotationChange
|
|
1645
|
-
});
|
|
1646
|
-
return {
|
|
1647
|
-
moveStartBoundary,
|
|
1648
|
-
moveEndBoundary,
|
|
1649
|
-
selectPrevious,
|
|
1650
|
-
selectNext,
|
|
1651
|
-
selectFirst,
|
|
1652
|
-
selectLast,
|
|
1653
|
-
clearSelection,
|
|
1654
|
-
scrollToAnnotation,
|
|
1655
|
-
playActiveAnnotation
|
|
1656
|
-
};
|
|
1657
|
-
}
|
|
1658
|
-
|
|
1659
|
-
// src/hooks/useDynamicEffects.ts
|
|
1660
|
-
var import_react17 = require("react");
|
|
1661
|
-
|
|
1662
|
-
// src/effects/effectDefinitions.ts
|
|
1663
|
-
var effectDefinitions = [
|
|
1664
|
-
// === REVERB EFFECTS ===
|
|
1665
|
-
{
|
|
1666
|
-
id: "reverb",
|
|
1667
|
-
name: "Reverb",
|
|
1668
|
-
category: "reverb",
|
|
1669
|
-
description: "Simple convolution reverb with adjustable decay time",
|
|
1670
|
-
parameters: [
|
|
1671
|
-
{
|
|
1672
|
-
name: "decay",
|
|
1673
|
-
label: "Decay",
|
|
1674
|
-
type: "number",
|
|
1675
|
-
min: 0.1,
|
|
1676
|
-
max: 10,
|
|
1677
|
-
step: 0.1,
|
|
1678
|
-
default: 1.5,
|
|
1679
|
-
unit: "s"
|
|
1680
|
-
},
|
|
1681
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1682
|
-
]
|
|
1683
|
-
},
|
|
1684
|
-
{
|
|
1685
|
-
id: "freeverb",
|
|
1686
|
-
name: "Freeverb",
|
|
1687
|
-
category: "reverb",
|
|
1688
|
-
description: "Classic Schroeder/Moorer reverb with room size and dampening",
|
|
1689
|
-
parameters: [
|
|
1690
|
-
{
|
|
1691
|
-
name: "roomSize",
|
|
1692
|
-
label: "Room Size",
|
|
1693
|
-
type: "number",
|
|
1694
|
-
min: 0,
|
|
1695
|
-
max: 1,
|
|
1696
|
-
step: 0.01,
|
|
1697
|
-
default: 0.7
|
|
1698
|
-
},
|
|
1699
|
-
{
|
|
1700
|
-
name: "dampening",
|
|
1701
|
-
label: "Dampening",
|
|
1702
|
-
type: "number",
|
|
1703
|
-
min: 0,
|
|
1704
|
-
max: 1e4,
|
|
1705
|
-
step: 100,
|
|
1706
|
-
default: 3e3,
|
|
1707
|
-
unit: "Hz"
|
|
1708
|
-
},
|
|
1709
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1710
|
-
]
|
|
1711
|
-
},
|
|
1712
|
-
{
|
|
1713
|
-
id: "jcReverb",
|
|
1714
|
-
name: "JC Reverb",
|
|
1715
|
-
category: "reverb",
|
|
1716
|
-
description: "Attempt at Roland JC-120 chorus reverb emulation",
|
|
1717
|
-
parameters: [
|
|
1718
|
-
{
|
|
1719
|
-
name: "roomSize",
|
|
1720
|
-
label: "Room Size",
|
|
1721
|
-
type: "number",
|
|
1722
|
-
min: 0,
|
|
1723
|
-
max: 1,
|
|
1724
|
-
step: 0.01,
|
|
1725
|
-
default: 0.5
|
|
1726
|
-
},
|
|
1727
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1728
|
-
]
|
|
1729
|
-
},
|
|
1730
|
-
// === DELAY EFFECTS ===
|
|
1731
|
-
{
|
|
1732
|
-
id: "feedbackDelay",
|
|
1733
|
-
name: "Feedback Delay",
|
|
1734
|
-
category: "delay",
|
|
1735
|
-
description: "Delay line with feedback for echo effects",
|
|
1736
|
-
parameters: [
|
|
1737
|
-
{
|
|
1738
|
-
name: "delayTime",
|
|
1739
|
-
label: "Delay Time",
|
|
1740
|
-
type: "number",
|
|
1741
|
-
min: 0,
|
|
1742
|
-
max: 1,
|
|
1743
|
-
step: 0.01,
|
|
1744
|
-
default: 0.25,
|
|
1745
|
-
unit: "s"
|
|
1746
|
-
},
|
|
1747
|
-
{
|
|
1748
|
-
name: "feedback",
|
|
1749
|
-
label: "Feedback",
|
|
1750
|
-
type: "number",
|
|
1751
|
-
min: 0,
|
|
1752
|
-
max: 0.95,
|
|
1753
|
-
step: 0.01,
|
|
1754
|
-
default: 0.5
|
|
1755
|
-
},
|
|
1756
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1757
|
-
]
|
|
1758
|
-
},
|
|
1759
|
-
{
|
|
1760
|
-
id: "pingPongDelay",
|
|
1761
|
-
name: "Ping Pong Delay",
|
|
1762
|
-
category: "delay",
|
|
1763
|
-
description: "Stereo delay bouncing between left and right channels",
|
|
1764
|
-
parameters: [
|
|
1765
|
-
{
|
|
1766
|
-
name: "delayTime",
|
|
1767
|
-
label: "Delay Time",
|
|
1768
|
-
type: "number",
|
|
1769
|
-
min: 0,
|
|
1770
|
-
max: 1,
|
|
1771
|
-
step: 0.01,
|
|
1772
|
-
default: 0.25,
|
|
1773
|
-
unit: "s"
|
|
1774
|
-
},
|
|
1775
|
-
{
|
|
1776
|
-
name: "feedback",
|
|
1777
|
-
label: "Feedback",
|
|
1778
|
-
type: "number",
|
|
1779
|
-
min: 0,
|
|
1780
|
-
max: 0.95,
|
|
1781
|
-
step: 0.01,
|
|
1782
|
-
default: 0.5
|
|
1783
|
-
},
|
|
1784
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1785
|
-
]
|
|
1786
|
-
},
|
|
1787
|
-
// === MODULATION EFFECTS ===
|
|
1788
|
-
{
|
|
1789
|
-
id: "chorus",
|
|
1790
|
-
name: "Chorus",
|
|
1791
|
-
category: "modulation",
|
|
1792
|
-
description: "Creates thickness by layering detuned copies of the signal",
|
|
1793
|
-
parameters: [
|
|
1794
|
-
{
|
|
1795
|
-
name: "frequency",
|
|
1796
|
-
label: "Rate",
|
|
1797
|
-
type: "number",
|
|
1798
|
-
min: 0.1,
|
|
1799
|
-
max: 10,
|
|
1800
|
-
step: 0.1,
|
|
1801
|
-
default: 1.5,
|
|
1802
|
-
unit: "Hz"
|
|
1803
|
-
},
|
|
1804
|
-
{
|
|
1805
|
-
name: "delayTime",
|
|
1806
|
-
label: "Delay",
|
|
1807
|
-
type: "number",
|
|
1808
|
-
min: 0,
|
|
1809
|
-
max: 20,
|
|
1810
|
-
step: 0.5,
|
|
1811
|
-
default: 3.5,
|
|
1812
|
-
unit: "ms"
|
|
1813
|
-
},
|
|
1814
|
-
{ name: "depth", label: "Depth", type: "number", min: 0, max: 1, step: 0.01, default: 0.7 },
|
|
1815
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1816
|
-
]
|
|
1817
|
-
},
|
|
1818
|
-
{
|
|
1819
|
-
id: "phaser",
|
|
1820
|
-
name: "Phaser",
|
|
1821
|
-
category: "modulation",
|
|
1822
|
-
description: "Classic phaser effect using allpass filters",
|
|
1823
|
-
parameters: [
|
|
1824
|
-
{
|
|
1825
|
-
name: "frequency",
|
|
1826
|
-
label: "Rate",
|
|
1827
|
-
type: "number",
|
|
1828
|
-
min: 0.1,
|
|
1829
|
-
max: 10,
|
|
1830
|
-
step: 0.1,
|
|
1831
|
-
default: 0.5,
|
|
1832
|
-
unit: "Hz"
|
|
1833
|
-
},
|
|
1834
|
-
{ name: "octaves", label: "Octaves", type: "number", min: 1, max: 6, step: 1, default: 3 },
|
|
1835
|
-
{
|
|
1836
|
-
name: "baseFrequency",
|
|
1837
|
-
label: "Base Freq",
|
|
1838
|
-
type: "number",
|
|
1839
|
-
min: 100,
|
|
1840
|
-
max: 2e3,
|
|
1841
|
-
step: 10,
|
|
1842
|
-
default: 350,
|
|
1843
|
-
unit: "Hz"
|
|
1844
|
-
},
|
|
1845
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
1846
|
-
]
|
|
1847
|
-
},
|
|
1848
|
-
{
|
|
1849
|
-
id: "tremolo",
|
|
1850
|
-
name: "Tremolo",
|
|
1851
|
-
category: "modulation",
|
|
1852
|
-
description: "Rhythmic volume modulation",
|
|
1853
|
-
parameters: [
|
|
1854
|
-
{
|
|
1855
|
-
name: "frequency",
|
|
1856
|
-
label: "Rate",
|
|
1857
|
-
type: "number",
|
|
1858
|
-
min: 0.1,
|
|
1859
|
-
max: 20,
|
|
1860
|
-
step: 0.1,
|
|
1861
|
-
default: 4,
|
|
1862
|
-
unit: "Hz"
|
|
1863
|
-
},
|
|
1864
|
-
{ name: "depth", label: "Depth", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 },
|
|
1865
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1866
|
-
]
|
|
1867
|
-
},
|
|
1868
|
-
{
|
|
1869
|
-
id: "vibrato",
|
|
1870
|
-
name: "Vibrato",
|
|
1871
|
-
category: "modulation",
|
|
1872
|
-
description: "Pitch modulation effect",
|
|
1873
|
-
parameters: [
|
|
1874
|
-
{
|
|
1875
|
-
name: "frequency",
|
|
1876
|
-
label: "Rate",
|
|
1877
|
-
type: "number",
|
|
1878
|
-
min: 0.1,
|
|
1879
|
-
max: 20,
|
|
1880
|
-
step: 0.1,
|
|
1881
|
-
default: 5,
|
|
1882
|
-
unit: "Hz"
|
|
1883
|
-
},
|
|
1884
|
-
{ name: "depth", label: "Depth", type: "number", min: 0, max: 1, step: 0.01, default: 0.1 },
|
|
1885
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1886
|
-
]
|
|
1887
|
-
},
|
|
1888
|
-
{
|
|
1889
|
-
id: "autoPanner",
|
|
1890
|
-
name: "Auto Panner",
|
|
1891
|
-
category: "modulation",
|
|
1892
|
-
description: "Automatic left-right panning",
|
|
1893
|
-
parameters: [
|
|
1894
|
-
{
|
|
1895
|
-
name: "frequency",
|
|
1896
|
-
label: "Rate",
|
|
1897
|
-
type: "number",
|
|
1898
|
-
min: 0.1,
|
|
1899
|
-
max: 10,
|
|
1900
|
-
step: 0.1,
|
|
1901
|
-
default: 1,
|
|
1902
|
-
unit: "Hz"
|
|
1903
|
-
},
|
|
1904
|
-
{ name: "depth", label: "Depth", type: "number", min: 0, max: 1, step: 0.01, default: 1 },
|
|
1905
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1906
|
-
]
|
|
1907
|
-
},
|
|
1908
|
-
// === FILTER EFFECTS ===
|
|
1909
|
-
{
|
|
1910
|
-
id: "autoFilter",
|
|
1911
|
-
name: "Auto Filter",
|
|
1912
|
-
category: "filter",
|
|
1913
|
-
description: "Automated filter sweep with LFO",
|
|
1914
|
-
parameters: [
|
|
1915
|
-
{
|
|
1916
|
-
name: "frequency",
|
|
1917
|
-
label: "Rate",
|
|
1918
|
-
type: "number",
|
|
1919
|
-
min: 0.1,
|
|
1920
|
-
max: 10,
|
|
1921
|
-
step: 0.1,
|
|
1922
|
-
default: 1,
|
|
1923
|
-
unit: "Hz"
|
|
1924
|
-
},
|
|
1925
|
-
{
|
|
1926
|
-
name: "baseFrequency",
|
|
1927
|
-
label: "Base Freq",
|
|
1928
|
-
type: "number",
|
|
1929
|
-
min: 20,
|
|
1930
|
-
max: 2e3,
|
|
1931
|
-
step: 10,
|
|
1932
|
-
default: 200,
|
|
1933
|
-
unit: "Hz"
|
|
1934
|
-
},
|
|
1935
|
-
{
|
|
1936
|
-
name: "octaves",
|
|
1937
|
-
label: "Octaves",
|
|
1938
|
-
type: "number",
|
|
1939
|
-
min: 0.5,
|
|
1940
|
-
max: 8,
|
|
1941
|
-
step: 0.5,
|
|
1942
|
-
default: 2.6
|
|
1943
|
-
},
|
|
1944
|
-
{ name: "depth", label: "Depth", type: "number", min: 0, max: 1, step: 0.01, default: 1 },
|
|
1945
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1946
|
-
]
|
|
1947
|
-
},
|
|
1948
|
-
{
|
|
1949
|
-
id: "autoWah",
|
|
1950
|
-
name: "Auto Wah",
|
|
1951
|
-
category: "filter",
|
|
1952
|
-
description: "Envelope follower filter effect",
|
|
1953
|
-
parameters: [
|
|
1954
|
-
{
|
|
1955
|
-
name: "baseFrequency",
|
|
1956
|
-
label: "Base Freq",
|
|
1957
|
-
type: "number",
|
|
1958
|
-
min: 20,
|
|
1959
|
-
max: 500,
|
|
1960
|
-
step: 10,
|
|
1961
|
-
default: 100,
|
|
1962
|
-
unit: "Hz"
|
|
1963
|
-
},
|
|
1964
|
-
{ name: "octaves", label: "Octaves", type: "number", min: 1, max: 8, step: 1, default: 6 },
|
|
1965
|
-
{
|
|
1966
|
-
name: "sensitivity",
|
|
1967
|
-
label: "Sensitivity",
|
|
1968
|
-
type: "number",
|
|
1969
|
-
min: -40,
|
|
1970
|
-
max: 0,
|
|
1971
|
-
step: 1,
|
|
1972
|
-
default: 0,
|
|
1973
|
-
unit: "dB"
|
|
1974
|
-
},
|
|
1975
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
1976
|
-
]
|
|
1977
|
-
},
|
|
1978
|
-
{
|
|
1979
|
-
id: "eq3",
|
|
1980
|
-
name: "3-Band EQ",
|
|
1981
|
-
category: "filter",
|
|
1982
|
-
description: "Three band equalizer with low, mid, and high controls",
|
|
1983
|
-
parameters: [
|
|
1984
|
-
{
|
|
1985
|
-
name: "low",
|
|
1986
|
-
label: "Low",
|
|
1987
|
-
type: "number",
|
|
1988
|
-
min: -24,
|
|
1989
|
-
max: 24,
|
|
1990
|
-
step: 0.5,
|
|
1991
|
-
default: 0,
|
|
1992
|
-
unit: "dB"
|
|
1993
|
-
},
|
|
1994
|
-
{
|
|
1995
|
-
name: "mid",
|
|
1996
|
-
label: "Mid",
|
|
1997
|
-
type: "number",
|
|
1998
|
-
min: -24,
|
|
1999
|
-
max: 24,
|
|
2000
|
-
step: 0.5,
|
|
2001
|
-
default: 0,
|
|
2002
|
-
unit: "dB"
|
|
2003
|
-
},
|
|
2004
|
-
{
|
|
2005
|
-
name: "high",
|
|
2006
|
-
label: "High",
|
|
2007
|
-
type: "number",
|
|
2008
|
-
min: -24,
|
|
2009
|
-
max: 24,
|
|
2010
|
-
step: 0.5,
|
|
2011
|
-
default: 0,
|
|
2012
|
-
unit: "dB"
|
|
2013
|
-
},
|
|
2014
|
-
{
|
|
2015
|
-
name: "lowFrequency",
|
|
2016
|
-
label: "Low Freq",
|
|
2017
|
-
type: "number",
|
|
2018
|
-
min: 20,
|
|
2019
|
-
max: 500,
|
|
2020
|
-
step: 10,
|
|
2021
|
-
default: 400,
|
|
2022
|
-
unit: "Hz"
|
|
2023
|
-
},
|
|
2024
|
-
{
|
|
2025
|
-
name: "highFrequency",
|
|
2026
|
-
label: "High Freq",
|
|
2027
|
-
type: "number",
|
|
2028
|
-
min: 1e3,
|
|
2029
|
-
max: 1e4,
|
|
2030
|
-
step: 100,
|
|
2031
|
-
default: 2500,
|
|
2032
|
-
unit: "Hz"
|
|
2033
|
-
}
|
|
2034
|
-
]
|
|
2035
|
-
},
|
|
2036
|
-
// === DISTORTION EFFECTS ===
|
|
2037
|
-
{
|
|
2038
|
-
id: "distortion",
|
|
2039
|
-
name: "Distortion",
|
|
2040
|
-
category: "distortion",
|
|
2041
|
-
description: "Wave shaping distortion effect",
|
|
2042
|
-
parameters: [
|
|
2043
|
-
{
|
|
2044
|
-
name: "distortion",
|
|
2045
|
-
label: "Drive",
|
|
2046
|
-
type: "number",
|
|
2047
|
-
min: 0,
|
|
2048
|
-
max: 1,
|
|
2049
|
-
step: 0.01,
|
|
2050
|
-
default: 0.4
|
|
2051
|
-
},
|
|
2052
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
2053
|
-
]
|
|
2054
|
-
},
|
|
2055
|
-
{
|
|
2056
|
-
id: "bitCrusher",
|
|
2057
|
-
name: "Bit Crusher",
|
|
2058
|
-
category: "distortion",
|
|
2059
|
-
description: "Reduces bit depth for lo-fi digital texture",
|
|
2060
|
-
parameters: [
|
|
2061
|
-
{ name: "bits", label: "Bits", type: "number", min: 1, max: 16, step: 1, default: 4 },
|
|
2062
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
2063
|
-
]
|
|
2064
|
-
},
|
|
2065
|
-
{
|
|
2066
|
-
id: "chebyshev",
|
|
2067
|
-
name: "Chebyshev",
|
|
2068
|
-
category: "distortion",
|
|
2069
|
-
description: "Waveshaping distortion using Chebyshev polynomials",
|
|
2070
|
-
parameters: [
|
|
2071
|
-
{ name: "order", label: "Order", type: "number", min: 1, max: 100, step: 1, default: 50 },
|
|
2072
|
-
{ name: "wet", label: "Mix", type: "number", min: 0, max: 1, step: 0.01, default: 1 }
|
|
2073
|
-
]
|
|
2074
|
-
},
|
|
2075
|
-
// === DYNAMICS EFFECTS ===
|
|
2076
|
-
{
|
|
2077
|
-
id: "compressor",
|
|
2078
|
-
name: "Compressor",
|
|
2079
|
-
category: "dynamics",
|
|
2080
|
-
description: "Dynamic range compressor",
|
|
2081
|
-
parameters: [
|
|
2082
|
-
{
|
|
2083
|
-
name: "threshold",
|
|
2084
|
-
label: "Threshold",
|
|
2085
|
-
type: "number",
|
|
2086
|
-
min: -60,
|
|
2087
|
-
max: 0,
|
|
2088
|
-
step: 1,
|
|
2089
|
-
default: -24,
|
|
2090
|
-
unit: "dB"
|
|
2091
|
-
},
|
|
2092
|
-
{ name: "ratio", label: "Ratio", type: "number", min: 1, max: 20, step: 0.5, default: 4 },
|
|
2093
|
-
{
|
|
2094
|
-
name: "attack",
|
|
2095
|
-
label: "Attack",
|
|
2096
|
-
type: "number",
|
|
2097
|
-
min: 0,
|
|
2098
|
-
max: 1,
|
|
2099
|
-
step: 1e-3,
|
|
2100
|
-
default: 3e-3,
|
|
2101
|
-
unit: "s"
|
|
2102
|
-
},
|
|
2103
|
-
{
|
|
2104
|
-
name: "release",
|
|
2105
|
-
label: "Release",
|
|
2106
|
-
type: "number",
|
|
2107
|
-
min: 0,
|
|
2108
|
-
max: 1,
|
|
2109
|
-
step: 0.01,
|
|
2110
|
-
default: 0.25,
|
|
2111
|
-
unit: "s"
|
|
2112
|
-
},
|
|
2113
|
-
{
|
|
2114
|
-
name: "knee",
|
|
2115
|
-
label: "Knee",
|
|
2116
|
-
type: "number",
|
|
2117
|
-
min: 0,
|
|
2118
|
-
max: 40,
|
|
2119
|
-
step: 1,
|
|
2120
|
-
default: 30,
|
|
2121
|
-
unit: "dB"
|
|
2122
|
-
}
|
|
2123
|
-
]
|
|
2124
|
-
},
|
|
2125
|
-
{
|
|
2126
|
-
id: "limiter",
|
|
2127
|
-
name: "Limiter",
|
|
2128
|
-
category: "dynamics",
|
|
2129
|
-
description: "Hard limiter to prevent clipping",
|
|
2130
|
-
parameters: [
|
|
2131
|
-
{
|
|
2132
|
-
name: "threshold",
|
|
2133
|
-
label: "Threshold",
|
|
2134
|
-
type: "number",
|
|
2135
|
-
min: -12,
|
|
2136
|
-
max: 0,
|
|
2137
|
-
step: 0.5,
|
|
2138
|
-
default: -6,
|
|
2139
|
-
unit: "dB"
|
|
2140
|
-
}
|
|
2141
|
-
]
|
|
2142
|
-
},
|
|
2143
|
-
{
|
|
2144
|
-
id: "gate",
|
|
2145
|
-
name: "Gate",
|
|
2146
|
-
category: "dynamics",
|
|
2147
|
-
description: "Noise gate to silence signal below threshold",
|
|
2148
|
-
parameters: [
|
|
2149
|
-
{
|
|
2150
|
-
name: "threshold",
|
|
2151
|
-
label: "Threshold",
|
|
2152
|
-
type: "number",
|
|
2153
|
-
min: -100,
|
|
2154
|
-
max: 0,
|
|
2155
|
-
step: 1,
|
|
2156
|
-
default: -40,
|
|
2157
|
-
unit: "dB"
|
|
2158
|
-
},
|
|
2159
|
-
{
|
|
2160
|
-
name: "attack",
|
|
2161
|
-
label: "Attack",
|
|
2162
|
-
type: "number",
|
|
2163
|
-
min: 0,
|
|
2164
|
-
max: 0.3,
|
|
2165
|
-
step: 1e-3,
|
|
2166
|
-
default: 1e-3,
|
|
2167
|
-
unit: "s"
|
|
2168
|
-
},
|
|
2169
|
-
{
|
|
2170
|
-
name: "release",
|
|
2171
|
-
label: "Release",
|
|
2172
|
-
type: "number",
|
|
2173
|
-
min: 0,
|
|
2174
|
-
max: 0.5,
|
|
2175
|
-
step: 0.01,
|
|
2176
|
-
default: 0.1,
|
|
2177
|
-
unit: "s"
|
|
2178
|
-
}
|
|
2179
|
-
]
|
|
2180
|
-
},
|
|
2181
|
-
// === SPATIAL EFFECTS ===
|
|
2182
|
-
{
|
|
2183
|
-
id: "stereoWidener",
|
|
2184
|
-
name: "Stereo Widener",
|
|
2185
|
-
category: "spatial",
|
|
2186
|
-
description: "Expands or narrows the stereo image",
|
|
2187
|
-
parameters: [
|
|
2188
|
-
{ name: "width", label: "Width", type: "number", min: 0, max: 1, step: 0.01, default: 0.5 }
|
|
2189
|
-
]
|
|
2190
|
-
}
|
|
2191
|
-
];
|
|
2192
|
-
var getEffectDefinition = (id) => {
|
|
2193
|
-
return effectDefinitions.find((def) => def.id === id);
|
|
2194
|
-
};
|
|
2195
|
-
var getEffectsByCategory = (category) => {
|
|
2196
|
-
return effectDefinitions.filter((def) => def.category === category);
|
|
2197
|
-
};
|
|
2198
|
-
var effectCategories = [
|
|
2199
|
-
{ id: "reverb", name: "Reverb" },
|
|
2200
|
-
{ id: "delay", name: "Delay" },
|
|
2201
|
-
{ id: "modulation", name: "Modulation" },
|
|
2202
|
-
{ id: "filter", name: "Filter" },
|
|
2203
|
-
{ id: "distortion", name: "Distortion" },
|
|
2204
|
-
{ id: "dynamics", name: "Dynamics" },
|
|
2205
|
-
{ id: "spatial", name: "Spatial" }
|
|
2206
|
-
];
|
|
2207
|
-
|
|
2208
|
-
// src/effects/effectFactory.ts
|
|
2209
|
-
var import_tone2 = require("tone");
|
|
2210
|
-
function asEffectConstructor(ctor) {
|
|
2211
|
-
return ctor;
|
|
2212
|
-
}
|
|
2213
|
-
var effectConstructors = {
|
|
2214
|
-
reverb: asEffectConstructor(import_tone2.Reverb),
|
|
2215
|
-
freeverb: asEffectConstructor(import_tone2.Freeverb),
|
|
2216
|
-
jcReverb: asEffectConstructor(import_tone2.JCReverb),
|
|
2217
|
-
feedbackDelay: asEffectConstructor(import_tone2.FeedbackDelay),
|
|
2218
|
-
pingPongDelay: asEffectConstructor(import_tone2.PingPongDelay),
|
|
2219
|
-
chorus: asEffectConstructor(import_tone2.Chorus),
|
|
2220
|
-
phaser: asEffectConstructor(import_tone2.Phaser),
|
|
2221
|
-
tremolo: asEffectConstructor(import_tone2.Tremolo),
|
|
2222
|
-
vibrato: asEffectConstructor(import_tone2.Vibrato),
|
|
2223
|
-
autoPanner: asEffectConstructor(import_tone2.AutoPanner),
|
|
2224
|
-
autoFilter: asEffectConstructor(import_tone2.AutoFilter),
|
|
2225
|
-
autoWah: asEffectConstructor(import_tone2.AutoWah),
|
|
2226
|
-
eq3: asEffectConstructor(import_tone2.EQ3),
|
|
2227
|
-
distortion: asEffectConstructor(import_tone2.Distortion),
|
|
2228
|
-
bitCrusher: asEffectConstructor(import_tone2.BitCrusher),
|
|
2229
|
-
chebyshev: asEffectConstructor(import_tone2.Chebyshev),
|
|
2230
|
-
compressor: asEffectConstructor(import_tone2.Compressor),
|
|
2231
|
-
limiter: asEffectConstructor(import_tone2.Limiter),
|
|
2232
|
-
gate: asEffectConstructor(import_tone2.Gate),
|
|
2233
|
-
stereoWidener: asEffectConstructor(import_tone2.StereoWidener)
|
|
2234
|
-
};
|
|
2235
|
-
var instanceCounter = 0;
|
|
2236
|
-
var generateInstanceId = () => {
|
|
2237
|
-
return `effect_${Date.now()}_${++instanceCounter}`;
|
|
2238
|
-
};
|
|
2239
|
-
function createEffectInstance(definition, initialParams) {
|
|
2240
|
-
const Constructor = effectConstructors[definition.id];
|
|
2241
|
-
if (!Constructor) {
|
|
2242
|
-
throw new Error(`Unknown effect type: ${definition.id}`);
|
|
2243
|
-
}
|
|
2244
|
-
const options = {};
|
|
2245
|
-
definition.parameters.forEach((param) => {
|
|
2246
|
-
var _a;
|
|
2247
|
-
const value = (_a = initialParams == null ? void 0 : initialParams[param.name]) != null ? _a : param.default;
|
|
2248
|
-
options[param.name] = value;
|
|
2249
|
-
});
|
|
2250
|
-
const effect = new Constructor(options);
|
|
2251
|
-
const instanceId = generateInstanceId();
|
|
2252
|
-
const effectRecord = effect;
|
|
2253
|
-
return {
|
|
2254
|
-
effect,
|
|
2255
|
-
id: definition.id,
|
|
2256
|
-
instanceId,
|
|
2257
|
-
dispose() {
|
|
2258
|
-
try {
|
|
2259
|
-
effect.disconnect();
|
|
2260
|
-
effect.dispose();
|
|
2261
|
-
} catch (e) {
|
|
2262
|
-
console.warn(
|
|
2263
|
-
`[waveform-playlist] Error disposing effect "${definition.id}" (${instanceId}):`,
|
|
2264
|
-
e
|
|
2265
|
-
);
|
|
2266
|
-
}
|
|
2267
|
-
},
|
|
2268
|
-
setParameter(name, value) {
|
|
2269
|
-
const prop = effectRecord[name];
|
|
2270
|
-
if (name === "wet") {
|
|
2271
|
-
const wetProp = effectRecord["wet"];
|
|
2272
|
-
if (wetProp && typeof wetProp === "object" && "value" in wetProp) {
|
|
2273
|
-
wetProp.value = value;
|
|
2274
|
-
return;
|
|
2275
|
-
}
|
|
2276
|
-
}
|
|
2277
|
-
if (prop !== void 0) {
|
|
2278
|
-
if (prop && typeof prop === "object" && "value" in prop) {
|
|
2279
|
-
prop.value = value;
|
|
2280
|
-
} else {
|
|
2281
|
-
effectRecord[name] = value;
|
|
2282
|
-
}
|
|
2283
|
-
}
|
|
2284
|
-
},
|
|
2285
|
-
getParameter(name) {
|
|
2286
|
-
if (name === "wet") {
|
|
2287
|
-
const wetProp = effectRecord["wet"];
|
|
2288
|
-
if (wetProp && typeof wetProp === "object" && "value" in wetProp) {
|
|
2289
|
-
return wetProp.value;
|
|
2290
|
-
}
|
|
2291
|
-
}
|
|
2292
|
-
const prop = effectRecord[name];
|
|
2293
|
-
if (prop !== void 0) {
|
|
2294
|
-
if (prop && typeof prop === "object" && "value" in prop) {
|
|
2295
|
-
return prop.value;
|
|
2296
|
-
}
|
|
2297
|
-
return prop;
|
|
2298
|
-
}
|
|
2299
|
-
return void 0;
|
|
2300
|
-
},
|
|
2301
|
-
connect(destination) {
|
|
2302
|
-
effect.connect(destination);
|
|
2303
|
-
},
|
|
2304
|
-
disconnect() {
|
|
2305
|
-
try {
|
|
2306
|
-
effect.disconnect();
|
|
2307
|
-
} catch (e) {
|
|
2308
|
-
console.warn(
|
|
2309
|
-
`[waveform-playlist] Error disconnecting effect "${definition.id}" (${instanceId}):`,
|
|
2310
|
-
e
|
|
2311
|
-
);
|
|
2312
|
-
}
|
|
2313
|
-
}
|
|
2314
|
-
};
|
|
2315
|
-
}
|
|
2316
|
-
function createEffectChain(effects) {
|
|
2317
|
-
if (effects.length === 0) {
|
|
2318
|
-
throw new Error("Cannot create effect chain with no effects");
|
|
2319
|
-
}
|
|
2320
|
-
for (let i = 0; i < effects.length - 1; i++) {
|
|
2321
|
-
effects[i].effect.connect(effects[i + 1].effect);
|
|
2322
|
-
}
|
|
2323
|
-
return {
|
|
2324
|
-
input: effects[0].effect,
|
|
2325
|
-
output: effects[effects.length - 1].effect,
|
|
2326
|
-
dispose() {
|
|
2327
|
-
effects.forEach((e) => e.dispose());
|
|
2328
|
-
}
|
|
2329
|
-
};
|
|
2330
|
-
}
|
|
2331
|
-
|
|
2332
|
-
// src/hooks/useDynamicEffects.ts
|
|
2333
|
-
var import_tone3 = require("tone");
|
|
2334
|
-
function useDynamicEffects(fftSize = 256) {
|
|
2335
|
-
const [activeEffects, setActiveEffects] = (0, import_react17.useState)([]);
|
|
2336
|
-
const activeEffectsRef = (0, import_react17.useRef)(activeEffects);
|
|
2337
|
-
activeEffectsRef.current = activeEffects;
|
|
2338
|
-
const effectInstancesRef = (0, import_react17.useRef)(/* @__PURE__ */ new Map());
|
|
2339
|
-
const analyserRef = (0, import_react17.useRef)(null);
|
|
2340
|
-
const graphNodesRef = (0, import_react17.useRef)(null);
|
|
2341
|
-
const rebuildChain = (0, import_react17.useCallback)((effects) => {
|
|
2342
|
-
const nodes = graphNodesRef.current;
|
|
2343
|
-
if (!nodes) return;
|
|
2344
|
-
const { masterGainNode, destination, analyserNode } = nodes;
|
|
2345
|
-
try {
|
|
2346
|
-
masterGainNode.disconnect();
|
|
2347
|
-
} catch (e) {
|
|
2348
|
-
console.warn("[waveform-playlist] Error disconnecting master effects chain:", e);
|
|
2349
|
-
}
|
|
2350
|
-
const instances = effects.map((ae) => effectInstancesRef.current.get(ae.instanceId)).filter((inst) => inst !== void 0);
|
|
2351
|
-
if (instances.length === 0) {
|
|
2352
|
-
masterGainNode.connect(analyserNode);
|
|
2353
|
-
analyserNode.connect(destination);
|
|
2354
|
-
} else {
|
|
2355
|
-
let currentNode = masterGainNode;
|
|
2356
|
-
instances.forEach((inst) => {
|
|
2357
|
-
try {
|
|
2358
|
-
inst.disconnect();
|
|
2359
|
-
} catch (e) {
|
|
2360
|
-
console.warn(`[waveform-playlist] Error disconnecting effect "${inst.id}":`, e);
|
|
2361
|
-
}
|
|
2362
|
-
currentNode.connect(inst.effect);
|
|
2363
|
-
currentNode = inst.effect;
|
|
2364
|
-
});
|
|
2365
|
-
currentNode.connect(analyserNode);
|
|
2366
|
-
analyserNode.connect(destination);
|
|
2367
|
-
}
|
|
2368
|
-
}, []);
|
|
2369
|
-
const addEffect = (0, import_react17.useCallback)((effectId) => {
|
|
2370
|
-
const definition = getEffectDefinition(effectId);
|
|
2371
|
-
if (!definition) {
|
|
2372
|
-
console.error(`Unknown effect: ${effectId}`);
|
|
2373
|
-
return;
|
|
2374
|
-
}
|
|
2375
|
-
const params = {};
|
|
2376
|
-
definition.parameters.forEach((p) => {
|
|
2377
|
-
params[p.name] = p.default;
|
|
2378
|
-
});
|
|
2379
|
-
const instance = createEffectInstance(definition, params);
|
|
2380
|
-
effectInstancesRef.current.set(instance.instanceId, instance);
|
|
2381
|
-
const newActiveEffect = {
|
|
2382
|
-
instanceId: instance.instanceId,
|
|
2383
|
-
effectId: definition.id,
|
|
2384
|
-
definition,
|
|
2385
|
-
params,
|
|
2386
|
-
bypassed: false
|
|
2387
|
-
};
|
|
2388
|
-
setActiveEffects((prev) => [...prev, newActiveEffect]);
|
|
2389
|
-
}, []);
|
|
2390
|
-
const removeEffect = (0, import_react17.useCallback)((instanceId) => {
|
|
2391
|
-
const instance = effectInstancesRef.current.get(instanceId);
|
|
2392
|
-
if (instance) {
|
|
2393
|
-
instance.dispose();
|
|
2394
|
-
effectInstancesRef.current.delete(instanceId);
|
|
2395
|
-
}
|
|
2396
|
-
setActiveEffects((prev) => prev.filter((e) => e.instanceId !== instanceId));
|
|
2397
|
-
}, []);
|
|
2398
|
-
const updateParameter = (0, import_react17.useCallback)(
|
|
2399
|
-
(instanceId, paramName, value) => {
|
|
2400
|
-
const instance = effectInstancesRef.current.get(instanceId);
|
|
2401
|
-
if (instance) {
|
|
2402
|
-
instance.setParameter(paramName, value);
|
|
2403
|
-
}
|
|
2404
|
-
setActiveEffects(
|
|
2405
|
-
(prev) => prev.map(
|
|
2406
|
-
(e) => e.instanceId === instanceId ? __spreadProps(__spreadValues({}, e), { params: __spreadProps(__spreadValues({}, e.params), { [paramName]: value }) }) : e
|
|
2407
|
-
)
|
|
2408
|
-
);
|
|
2409
|
-
},
|
|
2410
|
-
[]
|
|
2411
|
-
);
|
|
2412
|
-
const toggleBypass = (0, import_react17.useCallback)((instanceId) => {
|
|
2413
|
-
var _a;
|
|
2414
|
-
const effect = activeEffectsRef.current.find((e) => e.instanceId === instanceId);
|
|
2415
|
-
if (!effect) return;
|
|
2416
|
-
const newBypassed = !effect.bypassed;
|
|
2417
|
-
const instance = effectInstancesRef.current.get(instanceId);
|
|
2418
|
-
if (instance) {
|
|
2419
|
-
const originalWet = (_a = effect.params.wet) != null ? _a : 1;
|
|
2420
|
-
instance.setParameter("wet", newBypassed ? 0 : originalWet);
|
|
2421
|
-
}
|
|
2422
|
-
setActiveEffects(
|
|
2423
|
-
(prev) => prev.map((e) => e.instanceId === instanceId ? __spreadProps(__spreadValues({}, e), { bypassed: newBypassed }) : e)
|
|
2424
|
-
);
|
|
2425
|
-
}, []);
|
|
2426
|
-
const reorderEffects = (0, import_react17.useCallback)((fromIndex, toIndex) => {
|
|
2427
|
-
setActiveEffects((prev) => {
|
|
2428
|
-
const newEffects = [...prev];
|
|
2429
|
-
const [removed] = newEffects.splice(fromIndex, 1);
|
|
2430
|
-
newEffects.splice(toIndex, 0, removed);
|
|
2431
|
-
return newEffects;
|
|
2432
|
-
});
|
|
2433
|
-
}, []);
|
|
2434
|
-
const clearAllEffects = (0, import_react17.useCallback)(() => {
|
|
2435
|
-
effectInstancesRef.current.forEach((inst) => inst.dispose());
|
|
2436
|
-
effectInstancesRef.current.clear();
|
|
2437
|
-
setActiveEffects([]);
|
|
2438
|
-
}, []);
|
|
2439
|
-
(0, import_react17.useEffect)(() => {
|
|
2440
|
-
rebuildChain(activeEffects);
|
|
2441
|
-
}, [activeEffects, rebuildChain]);
|
|
2442
|
-
const masterEffects = (0, import_react17.useCallback)(
|
|
2443
|
-
(masterGainNode, destination, _isOffline) => {
|
|
2444
|
-
const analyserNode = new import_tone3.Analyser("fft", fftSize);
|
|
2445
|
-
analyserRef.current = analyserNode;
|
|
2446
|
-
graphNodesRef.current = {
|
|
2447
|
-
masterGainNode,
|
|
2448
|
-
destination,
|
|
2449
|
-
analyserNode
|
|
2450
|
-
};
|
|
2451
|
-
const effects = activeEffectsRef.current;
|
|
2452
|
-
const instances = effects.map((ae) => effectInstancesRef.current.get(ae.instanceId)).filter((inst) => inst !== void 0);
|
|
2453
|
-
if (instances.length === 0) {
|
|
2454
|
-
masterGainNode.connect(analyserNode);
|
|
2455
|
-
analyserNode.connect(destination);
|
|
2456
|
-
} else {
|
|
2457
|
-
let currentNode = masterGainNode;
|
|
2458
|
-
instances.forEach((inst) => {
|
|
2459
|
-
currentNode.connect(inst.effect);
|
|
2460
|
-
currentNode = inst.effect;
|
|
2461
|
-
});
|
|
2462
|
-
currentNode.connect(analyserNode);
|
|
2463
|
-
analyserNode.connect(destination);
|
|
2464
|
-
}
|
|
2465
|
-
return function cleanup() {
|
|
2466
|
-
analyserNode.dispose();
|
|
2467
|
-
analyserRef.current = null;
|
|
2468
|
-
graphNodesRef.current = null;
|
|
2469
|
-
};
|
|
2470
|
-
},
|
|
2471
|
-
[fftSize]
|
|
2472
|
-
// Only fftSize - reads effects from ref
|
|
2473
|
-
);
|
|
2474
|
-
(0, import_react17.useEffect)(() => {
|
|
2475
|
-
const effectInstances = effectInstancesRef.current;
|
|
2476
|
-
return () => {
|
|
2477
|
-
effectInstances.forEach((inst) => inst.dispose());
|
|
2478
|
-
effectInstances.clear();
|
|
2479
|
-
};
|
|
2480
|
-
}, []);
|
|
2481
|
-
const createOfflineEffectsFunction = (0, import_react17.useCallback)(() => {
|
|
2482
|
-
const nonBypassedEffects = activeEffects.filter((e) => !e.bypassed);
|
|
2483
|
-
if (nonBypassedEffects.length === 0) {
|
|
2484
|
-
return void 0;
|
|
2485
|
-
}
|
|
2486
|
-
return (masterGainNode, destination, _isOffline) => {
|
|
2487
|
-
const offlineInstances = [];
|
|
2488
|
-
for (const activeEffect of nonBypassedEffects) {
|
|
2489
|
-
const instance = createEffectInstance(activeEffect.definition, activeEffect.params);
|
|
2490
|
-
offlineInstances.push(instance);
|
|
2491
|
-
}
|
|
2492
|
-
if (offlineInstances.length === 0) {
|
|
2493
|
-
masterGainNode.connect(destination);
|
|
2494
|
-
} else {
|
|
2495
|
-
let currentNode = masterGainNode;
|
|
2496
|
-
offlineInstances.forEach((inst) => {
|
|
2497
|
-
currentNode.connect(inst.effect);
|
|
2498
|
-
currentNode = inst.effect;
|
|
2499
|
-
});
|
|
2500
|
-
currentNode.connect(destination);
|
|
2501
|
-
}
|
|
2502
|
-
return function cleanup() {
|
|
2503
|
-
offlineInstances.forEach((inst) => inst.dispose());
|
|
2504
|
-
};
|
|
2505
|
-
};
|
|
2506
|
-
}, [activeEffects]);
|
|
2507
|
-
return {
|
|
2508
|
-
activeEffects,
|
|
2509
|
-
availableEffects: effectDefinitions,
|
|
2510
|
-
addEffect,
|
|
2511
|
-
removeEffect,
|
|
2512
|
-
updateParameter,
|
|
2513
|
-
toggleBypass,
|
|
2514
|
-
reorderEffects,
|
|
2515
|
-
clearAllEffects,
|
|
2516
|
-
masterEffects,
|
|
2517
|
-
createOfflineEffectsFunction,
|
|
2518
|
-
analyserRef
|
|
2519
|
-
};
|
|
2520
|
-
}
|
|
2521
|
-
|
|
2522
|
-
// src/hooks/useTrackDynamicEffects.ts
|
|
2523
|
-
var import_react18 = require("react");
|
|
2524
|
-
function useTrackDynamicEffects() {
|
|
2525
|
-
const [trackEffectsState, setTrackEffectsState] = (0, import_react18.useState)(
|
|
2526
|
-
/* @__PURE__ */ new Map()
|
|
2527
|
-
);
|
|
2528
|
-
const trackEffectInstancesRef = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
|
|
2529
|
-
const trackGraphNodesRef = (0, import_react18.useRef)(/* @__PURE__ */ new Map());
|
|
2530
|
-
const rebuildTrackChain = (0, import_react18.useCallback)((trackId, trackEffects) => {
|
|
2531
|
-
const nodes = trackGraphNodesRef.current.get(trackId);
|
|
2532
|
-
if (!nodes) return;
|
|
2533
|
-
const { graphEnd, masterGainNode } = nodes;
|
|
2534
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2535
|
-
try {
|
|
2536
|
-
graphEnd.disconnect();
|
|
2537
|
-
} catch (e) {
|
|
2538
|
-
console.warn(`[waveform-playlist] Error disconnecting track "${trackId}" effect chain:`, e);
|
|
2539
|
-
}
|
|
2540
|
-
const instances = trackEffects.map((ae) => instancesMap == null ? void 0 : instancesMap.get(ae.instanceId)).filter((inst) => inst !== void 0);
|
|
2541
|
-
if (instances.length === 0) {
|
|
2542
|
-
graphEnd.connect(masterGainNode);
|
|
2543
|
-
} else {
|
|
2544
|
-
let currentNode = graphEnd;
|
|
2545
|
-
instances.forEach((inst) => {
|
|
2546
|
-
try {
|
|
2547
|
-
inst.disconnect();
|
|
2548
|
-
} catch (e) {
|
|
2549
|
-
console.warn(
|
|
2550
|
-
`[waveform-playlist] Error disconnecting effect "${inst.id}" on track "${trackId}":`,
|
|
2551
|
-
e
|
|
2552
|
-
);
|
|
2553
|
-
}
|
|
2554
|
-
currentNode.connect(inst.effect);
|
|
2555
|
-
currentNode = inst.effect;
|
|
2556
|
-
});
|
|
2557
|
-
currentNode.connect(masterGainNode);
|
|
2558
|
-
}
|
|
2559
|
-
}, []);
|
|
2560
|
-
const addEffectToTrack = (0, import_react18.useCallback)((trackId, effectId) => {
|
|
2561
|
-
const definition = getEffectDefinition(effectId);
|
|
2562
|
-
if (!definition) {
|
|
2563
|
-
console.error(`Unknown effect: ${effectId}`);
|
|
2564
|
-
return;
|
|
2565
|
-
}
|
|
2566
|
-
const params = {};
|
|
2567
|
-
definition.parameters.forEach((p) => {
|
|
2568
|
-
params[p.name] = p.default;
|
|
2569
|
-
});
|
|
2570
|
-
const instance = createEffectInstance(definition, params);
|
|
2571
|
-
if (!trackEffectInstancesRef.current.has(trackId)) {
|
|
2572
|
-
trackEffectInstancesRef.current.set(trackId, /* @__PURE__ */ new Map());
|
|
2573
|
-
}
|
|
2574
|
-
trackEffectInstancesRef.current.get(trackId).set(instance.instanceId, instance);
|
|
2575
|
-
const newActiveEffect = {
|
|
2576
|
-
instanceId: instance.instanceId,
|
|
2577
|
-
effectId: definition.id,
|
|
2578
|
-
definition,
|
|
2579
|
-
params,
|
|
2580
|
-
bypassed: false
|
|
2581
|
-
};
|
|
2582
|
-
setTrackEffectsState((prev) => {
|
|
2583
|
-
const newState = new Map(prev);
|
|
2584
|
-
const existing = newState.get(trackId) || [];
|
|
2585
|
-
newState.set(trackId, [...existing, newActiveEffect]);
|
|
2586
|
-
return newState;
|
|
2587
|
-
});
|
|
2588
|
-
}, []);
|
|
2589
|
-
const removeEffectFromTrack = (0, import_react18.useCallback)((trackId, instanceId) => {
|
|
2590
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2591
|
-
const instance = instancesMap == null ? void 0 : instancesMap.get(instanceId);
|
|
2592
|
-
if (instance) {
|
|
2593
|
-
instance.dispose();
|
|
2594
|
-
instancesMap == null ? void 0 : instancesMap.delete(instanceId);
|
|
2595
|
-
}
|
|
2596
|
-
setTrackEffectsState((prev) => {
|
|
2597
|
-
const newState = new Map(prev);
|
|
2598
|
-
const existing = newState.get(trackId) || [];
|
|
2599
|
-
newState.set(
|
|
2600
|
-
trackId,
|
|
2601
|
-
existing.filter((e) => e.instanceId !== instanceId)
|
|
2602
|
-
);
|
|
2603
|
-
return newState;
|
|
2604
|
-
});
|
|
2605
|
-
}, []);
|
|
2606
|
-
const updateTrackEffectParameter = (0, import_react18.useCallback)(
|
|
2607
|
-
(trackId, instanceId, paramName, value) => {
|
|
2608
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2609
|
-
const instance = instancesMap == null ? void 0 : instancesMap.get(instanceId);
|
|
2610
|
-
if (instance) {
|
|
2611
|
-
instance.setParameter(paramName, value);
|
|
2612
|
-
}
|
|
2613
|
-
setTrackEffectsState((prev) => {
|
|
2614
|
-
const newState = new Map(prev);
|
|
2615
|
-
const existing = newState.get(trackId) || [];
|
|
2616
|
-
newState.set(
|
|
2617
|
-
trackId,
|
|
2618
|
-
existing.map(
|
|
2619
|
-
(e) => e.instanceId === instanceId ? __spreadProps(__spreadValues({}, e), { params: __spreadProps(__spreadValues({}, e.params), { [paramName]: value }) }) : e
|
|
2620
|
-
)
|
|
2621
|
-
);
|
|
2622
|
-
return newState;
|
|
2623
|
-
});
|
|
2624
|
-
},
|
|
2625
|
-
[]
|
|
2626
|
-
);
|
|
2627
|
-
const toggleBypass = (0, import_react18.useCallback)((trackId, instanceId) => {
|
|
2628
|
-
var _a;
|
|
2629
|
-
const trackEffects = trackEffectsStateRef.current.get(trackId) || [];
|
|
2630
|
-
const effect = trackEffects.find((e) => e.instanceId === instanceId);
|
|
2631
|
-
if (!effect) return;
|
|
2632
|
-
const newBypassed = !effect.bypassed;
|
|
2633
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2634
|
-
const instance = instancesMap == null ? void 0 : instancesMap.get(instanceId);
|
|
2635
|
-
if (instance) {
|
|
2636
|
-
const originalWet = (_a = effect.params.wet) != null ? _a : 1;
|
|
2637
|
-
instance.setParameter("wet", newBypassed ? 0 : originalWet);
|
|
2638
|
-
}
|
|
2639
|
-
setTrackEffectsState((prev) => {
|
|
2640
|
-
const newState = new Map(prev);
|
|
2641
|
-
const existing = newState.get(trackId) || [];
|
|
2642
|
-
newState.set(
|
|
2643
|
-
trackId,
|
|
2644
|
-
existing.map((e) => e.instanceId === instanceId ? __spreadProps(__spreadValues({}, e), { bypassed: newBypassed }) : e)
|
|
2645
|
-
);
|
|
2646
|
-
return newState;
|
|
2647
|
-
});
|
|
2648
|
-
}, []);
|
|
2649
|
-
const clearTrackEffects = (0, import_react18.useCallback)((trackId) => {
|
|
2650
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2651
|
-
if (instancesMap) {
|
|
2652
|
-
instancesMap.forEach((inst) => inst.dispose());
|
|
2653
|
-
instancesMap.clear();
|
|
2654
|
-
}
|
|
2655
|
-
setTrackEffectsState((prev) => {
|
|
2656
|
-
const newState = new Map(prev);
|
|
2657
|
-
newState.set(trackId, []);
|
|
2658
|
-
return newState;
|
|
2659
|
-
});
|
|
2660
|
-
}, []);
|
|
2661
|
-
const trackEffectsStateRef = (0, import_react18.useRef)(trackEffectsState);
|
|
2662
|
-
trackEffectsStateRef.current = trackEffectsState;
|
|
2663
|
-
const getTrackEffectsFunction = (0, import_react18.useCallback)(
|
|
2664
|
-
(trackId) => {
|
|
2665
|
-
return (graphEnd, masterGainNode, _isOffline) => {
|
|
2666
|
-
trackGraphNodesRef.current.set(trackId, {
|
|
2667
|
-
graphEnd,
|
|
2668
|
-
masterGainNode
|
|
2669
|
-
});
|
|
2670
|
-
const trackEffects = trackEffectsStateRef.current.get(trackId) || [];
|
|
2671
|
-
const instancesMap = trackEffectInstancesRef.current.get(trackId);
|
|
2672
|
-
const instances = trackEffects.map((ae) => instancesMap == null ? void 0 : instancesMap.get(ae.instanceId)).filter((inst) => inst !== void 0);
|
|
2673
|
-
if (instances.length === 0) {
|
|
2674
|
-
graphEnd.connect(masterGainNode);
|
|
2675
|
-
} else {
|
|
2676
|
-
let currentNode = graphEnd;
|
|
2677
|
-
instances.forEach((inst) => {
|
|
2678
|
-
currentNode.connect(inst.effect);
|
|
2679
|
-
currentNode = inst.effect;
|
|
2680
|
-
});
|
|
2681
|
-
currentNode.connect(masterGainNode);
|
|
2682
|
-
}
|
|
2683
|
-
return function cleanup() {
|
|
2684
|
-
trackGraphNodesRef.current.delete(trackId);
|
|
2685
|
-
};
|
|
2686
|
-
};
|
|
2687
|
-
},
|
|
2688
|
-
[]
|
|
2689
|
-
// No dependencies - stable function that reads from refs
|
|
2690
|
-
);
|
|
2691
|
-
(0, import_react18.useEffect)(() => {
|
|
2692
|
-
trackEffectsState.forEach((effects, trackId) => {
|
|
2693
|
-
rebuildTrackChain(trackId, effects);
|
|
2694
|
-
});
|
|
2695
|
-
}, [trackEffectsState, rebuildTrackChain]);
|
|
2696
|
-
(0, import_react18.useEffect)(() => {
|
|
2697
|
-
const trackEffectInstances = trackEffectInstancesRef.current;
|
|
2698
|
-
return () => {
|
|
2699
|
-
trackEffectInstances.forEach((instancesMap) => {
|
|
2700
|
-
instancesMap.forEach((inst) => inst.dispose());
|
|
2701
|
-
instancesMap.clear();
|
|
2702
|
-
});
|
|
2703
|
-
trackEffectInstances.clear();
|
|
2704
|
-
};
|
|
2705
|
-
}, []);
|
|
2706
|
-
const createOfflineTrackEffectsFunction = (0, import_react18.useCallback)(
|
|
2707
|
-
(trackId) => {
|
|
2708
|
-
const trackEffects = trackEffectsState.get(trackId) || [];
|
|
2709
|
-
const nonBypassedEffects = trackEffects.filter((e) => !e.bypassed);
|
|
2710
|
-
if (nonBypassedEffects.length === 0) {
|
|
2711
|
-
return void 0;
|
|
2712
|
-
}
|
|
2713
|
-
return (graphEnd, masterGainNode, _isOffline) => {
|
|
2714
|
-
const offlineInstances = [];
|
|
2715
|
-
for (const activeEffect of nonBypassedEffects) {
|
|
2716
|
-
const instance = createEffectInstance(activeEffect.definition, activeEffect.params);
|
|
2717
|
-
offlineInstances.push(instance);
|
|
2718
|
-
}
|
|
2719
|
-
if (offlineInstances.length === 0) {
|
|
2720
|
-
graphEnd.connect(masterGainNode);
|
|
2721
|
-
} else {
|
|
2722
|
-
let currentNode = graphEnd;
|
|
2723
|
-
offlineInstances.forEach((inst) => {
|
|
2724
|
-
currentNode.connect(inst.effect);
|
|
2725
|
-
currentNode = inst.effect;
|
|
2726
|
-
});
|
|
2727
|
-
currentNode.connect(masterGainNode);
|
|
2728
|
-
}
|
|
2729
|
-
return function cleanup() {
|
|
2730
|
-
offlineInstances.forEach((inst) => inst.dispose());
|
|
2731
|
-
};
|
|
2732
|
-
};
|
|
2733
|
-
},
|
|
2734
|
-
[trackEffectsState]
|
|
2735
|
-
);
|
|
2736
|
-
return {
|
|
2737
|
-
trackEffectsState,
|
|
2738
|
-
addEffectToTrack,
|
|
2739
|
-
removeEffectFromTrack,
|
|
2740
|
-
updateTrackEffectParameter,
|
|
2741
|
-
toggleBypass,
|
|
2742
|
-
clearTrackEffects,
|
|
2743
|
-
getTrackEffectsFunction,
|
|
2744
|
-
createOfflineTrackEffectsFunction,
|
|
2745
|
-
availableEffects: effectDefinitions
|
|
2746
|
-
};
|
|
2747
|
-
}
|
|
2748
|
-
|
|
2749
|
-
// src/hooks/useExportWav.ts
|
|
2750
|
-
var import_react19 = require("react");
|
|
2751
|
-
var import_core4 = require("@waveform-playlist/core");
|
|
2752
|
-
var import_playout3 = require("@waveform-playlist/playout");
|
|
2753
|
-
|
|
2754
|
-
// src/utils/wavEncoder.ts
|
|
2755
|
-
function encodeWav(audioBuffer, options = {}) {
|
|
2756
|
-
const { bitDepth = 16 } = options;
|
|
2757
|
-
const numChannels = audioBuffer.numberOfChannels;
|
|
2758
|
-
const sampleRate = audioBuffer.sampleRate;
|
|
2759
|
-
const numSamples = audioBuffer.length;
|
|
2760
|
-
const bytesPerSample = bitDepth / 8;
|
|
2761
|
-
const blockAlign = numChannels * bytesPerSample;
|
|
2762
|
-
const byteRate = sampleRate * blockAlign;
|
|
2763
|
-
const dataSize = numSamples * blockAlign;
|
|
2764
|
-
const headerSize = 44;
|
|
2765
|
-
const totalSize = headerSize + dataSize;
|
|
2766
|
-
const buffer = new ArrayBuffer(totalSize);
|
|
2767
|
-
const view = new DataView(buffer);
|
|
2768
|
-
writeString(view, 0, "RIFF");
|
|
2769
|
-
view.setUint32(4, totalSize - 8, true);
|
|
2770
|
-
writeString(view, 8, "WAVE");
|
|
2771
|
-
writeString(view, 12, "fmt ");
|
|
2772
|
-
view.setUint32(16, 16, true);
|
|
2773
|
-
view.setUint16(20, bitDepth === 32 ? 3 : 1, true);
|
|
2774
|
-
view.setUint16(22, numChannels, true);
|
|
2775
|
-
view.setUint32(24, sampleRate, true);
|
|
2776
|
-
view.setUint32(28, byteRate, true);
|
|
2777
|
-
view.setUint16(32, blockAlign, true);
|
|
2778
|
-
view.setUint16(34, bitDepth, true);
|
|
2779
|
-
writeString(view, 36, "data");
|
|
2780
|
-
view.setUint32(40, dataSize, true);
|
|
2781
|
-
const channelData = [];
|
|
2782
|
-
for (let ch = 0; ch < numChannels; ch++) {
|
|
2783
|
-
channelData.push(audioBuffer.getChannelData(ch));
|
|
2784
|
-
}
|
|
2785
|
-
let offset = headerSize;
|
|
2786
|
-
if (bitDepth === 16) {
|
|
2787
|
-
for (let i = 0; i < numSamples; i++) {
|
|
2788
|
-
for (let ch = 0; ch < numChannels; ch++) {
|
|
2789
|
-
const sample = channelData[ch][i];
|
|
2790
|
-
const clampedSample = Math.max(-1, Math.min(1, sample));
|
|
2791
|
-
const intSample = clampedSample < 0 ? clampedSample * 32768 : clampedSample * 32767;
|
|
2792
|
-
view.setInt16(offset, intSample, true);
|
|
2793
|
-
offset += 2;
|
|
2794
|
-
}
|
|
2795
|
-
}
|
|
2796
|
-
} else {
|
|
2797
|
-
for (let i = 0; i < numSamples; i++) {
|
|
2798
|
-
for (let ch = 0; ch < numChannels; ch++) {
|
|
2799
|
-
view.setFloat32(offset, channelData[ch][i], true);
|
|
2800
|
-
offset += 4;
|
|
2801
|
-
}
|
|
2802
|
-
}
|
|
2803
|
-
}
|
|
2804
|
-
return new Blob([buffer], { type: "audio/wav" });
|
|
2805
|
-
}
|
|
2806
|
-
function writeString(view, offset, str) {
|
|
2807
|
-
for (let i = 0; i < str.length; i++) {
|
|
2808
|
-
view.setUint8(offset + i, str.charCodeAt(i));
|
|
2809
|
-
}
|
|
2810
|
-
}
|
|
2811
|
-
function downloadBlob(blob, filename) {
|
|
2812
|
-
const url = URL.createObjectURL(blob);
|
|
2813
|
-
const a = document.createElement("a");
|
|
2814
|
-
a.href = url;
|
|
2815
|
-
a.download = filename;
|
|
2816
|
-
a.style.display = "none";
|
|
2817
|
-
document.body.appendChild(a);
|
|
2818
|
-
a.click();
|
|
2819
|
-
document.body.removeChild(a);
|
|
2820
|
-
URL.revokeObjectURL(url);
|
|
2821
|
-
}
|
|
2822
|
-
|
|
2823
|
-
// src/hooks/useExportWav.ts
|
|
2824
|
-
function useExportWav() {
|
|
2825
|
-
const [isExporting, setIsExporting] = (0, import_react19.useState)(false);
|
|
2826
|
-
const [progress, setProgress] = (0, import_react19.useState)(0);
|
|
2827
|
-
const [error, setError] = (0, import_react19.useState)(null);
|
|
2828
|
-
const exportWav = (0, import_react19.useCallback)(
|
|
2829
|
-
(_0, _1, ..._2) => __async(null, [_0, _1, ..._2], function* (tracks, trackStates, options = {}) {
|
|
2830
|
-
const {
|
|
2831
|
-
filename = "export",
|
|
2832
|
-
mode = "master",
|
|
2833
|
-
trackIndex,
|
|
2834
|
-
autoDownload = true,
|
|
2835
|
-
applyEffects = true,
|
|
2836
|
-
effectsFunction,
|
|
2837
|
-
createOfflineTrackEffects,
|
|
2838
|
-
bitDepth = 16,
|
|
2839
|
-
onProgress
|
|
2840
|
-
} = options;
|
|
2841
|
-
setIsExporting(true);
|
|
2842
|
-
setProgress(0);
|
|
2843
|
-
setError(null);
|
|
2844
|
-
try {
|
|
2845
|
-
if (tracks.length === 0) {
|
|
2846
|
-
throw new Error("No tracks to export");
|
|
2847
|
-
}
|
|
2848
|
-
if (mode === "individual" && (trackIndex === void 0 || trackIndex < 0 || trackIndex >= tracks.length)) {
|
|
2849
|
-
throw new Error("Invalid track index for individual export");
|
|
2850
|
-
}
|
|
2851
|
-
const sampleRate = (0, import_playout3.getGlobalAudioContext)().sampleRate;
|
|
2852
|
-
let totalDurationSamples = 0;
|
|
2853
|
-
for (const track of tracks) {
|
|
2854
|
-
for (const clip of track.clips) {
|
|
2855
|
-
const clipEndSample = clip.startSample + clip.durationSamples;
|
|
2856
|
-
totalDurationSamples = Math.max(totalDurationSamples, clipEndSample);
|
|
2857
|
-
}
|
|
2858
|
-
}
|
|
2859
|
-
totalDurationSamples += Math.round(sampleRate * 0.1);
|
|
2860
|
-
const duration = totalDurationSamples / sampleRate;
|
|
2861
|
-
const tracksToRender = mode === "individual" ? [{ track: tracks[trackIndex], state: trackStates[trackIndex], index: trackIndex }] : tracks.map((track, index) => ({ track, state: trackStates[index], index }));
|
|
2862
|
-
const hasSolo = mode === "master" && trackStates.some((state) => state.soloed);
|
|
2863
|
-
const reportProgress = (p) => {
|
|
2864
|
-
setProgress(p);
|
|
2865
|
-
onProgress == null ? void 0 : onProgress(p);
|
|
2866
|
-
};
|
|
2867
|
-
const renderedBuffer = yield renderOffline(
|
|
2868
|
-
tracksToRender,
|
|
2869
|
-
hasSolo,
|
|
2870
|
-
duration,
|
|
2871
|
-
sampleRate,
|
|
2872
|
-
applyEffects,
|
|
2873
|
-
effectsFunction,
|
|
2874
|
-
createOfflineTrackEffects,
|
|
2875
|
-
reportProgress
|
|
2876
|
-
);
|
|
2877
|
-
reportProgress(0.9);
|
|
2878
|
-
const blob = encodeWav(renderedBuffer, { bitDepth });
|
|
2879
|
-
reportProgress(1);
|
|
2880
|
-
if (autoDownload) {
|
|
2881
|
-
const exportFilename = mode === "individual" ? `${filename}_${tracks[trackIndex].name}` : filename;
|
|
2882
|
-
downloadBlob(blob, `${exportFilename}.wav`);
|
|
2883
|
-
}
|
|
2884
|
-
return {
|
|
2885
|
-
audioBuffer: renderedBuffer,
|
|
2886
|
-
blob,
|
|
2887
|
-
duration
|
|
2888
|
-
};
|
|
2889
|
-
} catch (err) {
|
|
2890
|
-
const message = err instanceof Error ? err.message : "Export failed";
|
|
2891
|
-
setError(message);
|
|
2892
|
-
throw err;
|
|
2893
|
-
} finally {
|
|
2894
|
-
setIsExporting(false);
|
|
2895
|
-
}
|
|
2896
|
-
}),
|
|
2897
|
-
[]
|
|
2898
|
-
);
|
|
2899
|
-
return {
|
|
2900
|
-
exportWav,
|
|
2901
|
-
isExporting,
|
|
2902
|
-
progress,
|
|
2903
|
-
error
|
|
2904
|
-
};
|
|
2905
|
-
}
|
|
2906
|
-
function renderOffline(tracksToRender, hasSolo, duration, sampleRate, applyEffects, effectsFunction, createOfflineTrackEffects, onProgress) {
|
|
2907
|
-
return __async(this, null, function* () {
|
|
2908
|
-
const { Offline, Volume: Volume2, Gain, Panner, Player, ToneAudioBuffer } = yield import("tone");
|
|
2909
|
-
onProgress(0.1);
|
|
2910
|
-
const audibleTracks = tracksToRender.filter(({ state }) => {
|
|
2911
|
-
if (state.muted && !state.soloed) return false;
|
|
2912
|
-
if (hasSolo && !state.soloed) return false;
|
|
2913
|
-
return true;
|
|
2914
|
-
});
|
|
2915
|
-
const outputChannels = audibleTracks.reduce(
|
|
2916
|
-
(max, { track }) => Math.max(max, (0, import_core4.trackChannelCount)(track)),
|
|
2917
|
-
1
|
|
2918
|
-
);
|
|
2919
|
-
let buffer;
|
|
2920
|
-
try {
|
|
2921
|
-
buffer = yield Offline(
|
|
2922
|
-
(_0) => __async(null, [_0], function* ({ transport, destination }) {
|
|
2923
|
-
const masterVolume = new Volume2(0);
|
|
2924
|
-
if (effectsFunction && applyEffects) {
|
|
2925
|
-
effectsFunction(masterVolume, destination, true);
|
|
2926
|
-
} else {
|
|
2927
|
-
masterVolume.connect(destination);
|
|
2928
|
-
}
|
|
2929
|
-
for (const { track, state } of audibleTracks) {
|
|
2930
|
-
const trackVolume = new Volume2((0, import_core4.gainToDb)(state.volume));
|
|
2931
|
-
const trackPan = new Panner({ pan: state.pan, channelCount: (0, import_core4.trackChannelCount)(track) });
|
|
2932
|
-
const trackMute = new Gain(state.muted ? 0 : 1);
|
|
2933
|
-
const trackEffects = createOfflineTrackEffects == null ? void 0 : createOfflineTrackEffects(track.id);
|
|
2934
|
-
if (trackEffects && applyEffects) {
|
|
2935
|
-
trackEffects(trackMute, masterVolume, true);
|
|
2936
|
-
} else {
|
|
2937
|
-
trackMute.connect(masterVolume);
|
|
2938
|
-
}
|
|
2939
|
-
trackPan.connect(trackMute);
|
|
2940
|
-
trackVolume.connect(trackPan);
|
|
2941
|
-
for (const clip of track.clips) {
|
|
2942
|
-
const {
|
|
2943
|
-
audioBuffer,
|
|
2944
|
-
startSample,
|
|
2945
|
-
durationSamples,
|
|
2946
|
-
offsetSamples,
|
|
2947
|
-
gain: clipGain,
|
|
2948
|
-
fadeIn,
|
|
2949
|
-
fadeOut
|
|
2950
|
-
} = clip;
|
|
2951
|
-
if (!audioBuffer) {
|
|
2952
|
-
console.warn(
|
|
2953
|
-
'[waveform-playlist] Skipping clip "' + (clip.name || clip.id) + '" - no audioBuffer for export'
|
|
2954
|
-
);
|
|
2955
|
-
continue;
|
|
2956
|
-
}
|
|
2957
|
-
const startTime = startSample / sampleRate;
|
|
2958
|
-
const clipDuration = durationSamples / sampleRate;
|
|
2959
|
-
const offset = offsetSamples / sampleRate;
|
|
2960
|
-
const toneBuffer = new ToneAudioBuffer(audioBuffer);
|
|
2961
|
-
const player = new Player(toneBuffer);
|
|
2962
|
-
const fadeGain = new Gain(clipGain);
|
|
2963
|
-
player.connect(fadeGain);
|
|
2964
|
-
fadeGain.connect(trackVolume);
|
|
2965
|
-
if (applyEffects) {
|
|
2966
|
-
const audioParam = (0, import_playout3.getUnderlyingAudioParam)(fadeGain.gain);
|
|
2967
|
-
if (audioParam) {
|
|
2968
|
-
applyClipFades(audioParam, clipGain, startTime, clipDuration, fadeIn, fadeOut);
|
|
2969
|
-
} else if (fadeIn || fadeOut) {
|
|
2970
|
-
console.warn(
|
|
2971
|
-
'[waveform-playlist] Cannot apply fades for clip "' + (clip.name || clip.id) + '" - AudioParam not accessible'
|
|
2972
|
-
);
|
|
2973
|
-
}
|
|
2974
|
-
}
|
|
2975
|
-
player.start(startTime, offset, clipDuration);
|
|
2976
|
-
}
|
|
2977
|
-
}
|
|
2978
|
-
transport.start(0);
|
|
2979
|
-
}),
|
|
2980
|
-
duration,
|
|
2981
|
-
outputChannels,
|
|
2982
|
-
sampleRate
|
|
2983
|
-
);
|
|
2984
|
-
} catch (err) {
|
|
2985
|
-
if (err instanceof Error) {
|
|
2986
|
-
throw err;
|
|
2987
|
-
} else {
|
|
2988
|
-
throw new Error("Tone.Offline rendering failed: " + String(err));
|
|
2989
|
-
}
|
|
2990
|
-
}
|
|
2991
|
-
onProgress(0.9);
|
|
2992
|
-
const result = buffer.get();
|
|
2993
|
-
if (!result) {
|
|
2994
|
-
throw new Error("Offline rendering produced no audio buffer");
|
|
2995
|
-
}
|
|
2996
|
-
return result;
|
|
1442
|
+
);
|
|
1443
|
+
useKeyboardShortcuts({
|
|
1444
|
+
shortcuts: activeAnnotationShortcuts,
|
|
1445
|
+
enabled: enabled && activeIndex >= 0
|
|
2997
1446
|
});
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
(0, import_core4.applyFadeOut)(gainParam, fadeOutStart, fadeOut.duration, fadeOut.type || "linear", clipGain, 0);
|
|
3014
|
-
}
|
|
1447
|
+
useKeyboardShortcuts({
|
|
1448
|
+
shortcuts: navigationShortcuts,
|
|
1449
|
+
enabled: enabled && annotations.length > 0 && !!onActiveAnnotationChange
|
|
1450
|
+
});
|
|
1451
|
+
return {
|
|
1452
|
+
moveStartBoundary,
|
|
1453
|
+
moveEndBoundary,
|
|
1454
|
+
selectPrevious,
|
|
1455
|
+
selectNext,
|
|
1456
|
+
selectFirst,
|
|
1457
|
+
selectLast,
|
|
1458
|
+
clearSelection,
|
|
1459
|
+
scrollToAnnotation,
|
|
1460
|
+
playActiveAnnotation
|
|
1461
|
+
};
|
|
3015
1462
|
}
|
|
3016
1463
|
|
|
3017
1464
|
// src/hooks/useAnimationFrameLoop.ts
|
|
3018
|
-
var
|
|
1465
|
+
var import_react15 = require("react");
|
|
3019
1466
|
var useAnimationFrameLoop = () => {
|
|
3020
|
-
const animationFrameRef = (0,
|
|
3021
|
-
const stopAnimationFrameLoop = (0,
|
|
1467
|
+
const animationFrameRef = (0, import_react15.useRef)(null);
|
|
1468
|
+
const stopAnimationFrameLoop = (0, import_react15.useCallback)(() => {
|
|
3022
1469
|
if (animationFrameRef.current !== null) {
|
|
3023
1470
|
cancelAnimationFrame(animationFrameRef.current);
|
|
3024
1471
|
animationFrameRef.current = null;
|
|
3025
1472
|
}
|
|
3026
1473
|
}, []);
|
|
3027
|
-
const startAnimationFrameLoop = (0,
|
|
1474
|
+
const startAnimationFrameLoop = (0, import_react15.useCallback)(
|
|
3028
1475
|
(callback) => {
|
|
3029
1476
|
stopAnimationFrameLoop();
|
|
3030
1477
|
animationFrameRef.current = requestAnimationFrame(callback);
|
|
3031
1478
|
},
|
|
3032
1479
|
[stopAnimationFrameLoop]
|
|
3033
1480
|
);
|
|
3034
|
-
(0,
|
|
1481
|
+
(0, import_react15.useEffect)(() => {
|
|
3035
1482
|
return () => {
|
|
3036
1483
|
stopAnimationFrameLoop();
|
|
3037
1484
|
};
|
|
@@ -3044,7 +1491,7 @@ var useAnimationFrameLoop = () => {
|
|
|
3044
1491
|
};
|
|
3045
1492
|
|
|
3046
1493
|
// src/hooks/useWaveformDataCache.ts
|
|
3047
|
-
var
|
|
1494
|
+
var import_react16 = require("react");
|
|
3048
1495
|
|
|
3049
1496
|
// src/workers/peaksWorker.ts
|
|
3050
1497
|
var import_waveform_data2 = __toESM(require("waveform-data"));
|
|
@@ -3276,20 +1723,20 @@ function createPeaksWorker() {
|
|
|
3276
1723
|
|
|
3277
1724
|
// src/hooks/useWaveformDataCache.ts
|
|
3278
1725
|
function useWaveformDataCache(tracks, baseScale) {
|
|
3279
|
-
const [cache, setCache] = (0,
|
|
3280
|
-
const [isGenerating, setIsGenerating] = (0,
|
|
3281
|
-
const workerRef = (0,
|
|
3282
|
-
const generatedByBufferRef = (0,
|
|
3283
|
-
const inflightByBufferRef = (0,
|
|
3284
|
-
const subscribersByBufferRef = (0,
|
|
3285
|
-
const pendingCountRef = (0,
|
|
3286
|
-
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)(() => {
|
|
3287
1734
|
if (!workerRef.current) {
|
|
3288
1735
|
workerRef.current = createPeaksWorker();
|
|
3289
1736
|
}
|
|
3290
1737
|
return workerRef.current;
|
|
3291
1738
|
}, []);
|
|
3292
|
-
(0,
|
|
1739
|
+
(0, import_react16.useEffect)(() => {
|
|
3293
1740
|
let cancelled = false;
|
|
3294
1741
|
const generatedByBuffer = generatedByBufferRef.current;
|
|
3295
1742
|
const inflightByBuffer = inflightByBufferRef.current;
|
|
@@ -3394,7 +1841,7 @@ function useWaveformDataCache(tracks, baseScale) {
|
|
|
3394
1841
|
setIsGenerating(false);
|
|
3395
1842
|
};
|
|
3396
1843
|
}, [tracks, baseScale, getWorker]);
|
|
3397
|
-
(0,
|
|
1844
|
+
(0, import_react16.useEffect)(() => {
|
|
3398
1845
|
return () => {
|
|
3399
1846
|
var _a;
|
|
3400
1847
|
(_a = workerRef.current) == null ? void 0 : _a.terminate();
|
|
@@ -3404,232 +1851,12 @@ function useWaveformDataCache(tracks, baseScale) {
|
|
|
3404
1851
|
return { cache, isGenerating };
|
|
3405
1852
|
}
|
|
3406
1853
|
|
|
3407
|
-
// src/hooks/useDynamicTracks.ts
|
|
3408
|
-
var import_react22 = require("react");
|
|
3409
|
-
var import_core5 = require("@waveform-playlist/core");
|
|
3410
|
-
var import_playout4 = require("@waveform-playlist/playout");
|
|
3411
|
-
function getSourceName(source) {
|
|
3412
|
-
var _a, _b, _c, _d, _e;
|
|
3413
|
-
if (source instanceof File) {
|
|
3414
|
-
return source.name.replace(/\.[^/.]+$/, "");
|
|
3415
|
-
}
|
|
3416
|
-
if (source instanceof Blob) {
|
|
3417
|
-
return "Untitled";
|
|
3418
|
-
}
|
|
3419
|
-
if (typeof source === "string") {
|
|
3420
|
-
return (_b = (_a = source.split("/").pop()) == null ? void 0 : _a.replace(/\.[^/.]+$/, "")) != null ? _b : "Untitled";
|
|
3421
|
-
}
|
|
3422
|
-
return (_e = (_d = source.name) != null ? _d : (_c = source.src.split("/").pop()) == null ? void 0 : _c.replace(/\.[^/.]+$/, "")) != null ? _e : "Untitled";
|
|
3423
|
-
}
|
|
3424
|
-
function decodeSource(source, audioContext, signal) {
|
|
3425
|
-
return __async(this, null, function* () {
|
|
3426
|
-
const name = getSourceName(source);
|
|
3427
|
-
if (source instanceof Blob) {
|
|
3428
|
-
const arrayBuffer2 = yield source.arrayBuffer();
|
|
3429
|
-
signal == null ? void 0 : signal.throwIfAborted();
|
|
3430
|
-
const audioBuffer2 = yield audioContext.decodeAudioData(arrayBuffer2);
|
|
3431
|
-
return { audioBuffer: audioBuffer2, name };
|
|
3432
|
-
}
|
|
3433
|
-
const url = typeof source === "string" ? source : source.src;
|
|
3434
|
-
const response = yield fetch(url, { signal });
|
|
3435
|
-
if (!response.ok) throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
|
|
3436
|
-
const arrayBuffer = yield response.arrayBuffer();
|
|
3437
|
-
signal == null ? void 0 : signal.throwIfAborted();
|
|
3438
|
-
const audioBuffer = yield audioContext.decodeAudioData(arrayBuffer);
|
|
3439
|
-
return { audioBuffer, name };
|
|
3440
|
-
});
|
|
3441
|
-
}
|
|
3442
|
-
function useDynamicTracks() {
|
|
3443
|
-
const [tracks, setTracks] = (0, import_react22.useState)([]);
|
|
3444
|
-
const [loadingCount, setLoadingCount] = (0, import_react22.useState)(0);
|
|
3445
|
-
const [errors, setErrors] = (0, import_react22.useState)([]);
|
|
3446
|
-
const cancelledRef = (0, import_react22.useRef)(false);
|
|
3447
|
-
const loadingIdsRef = (0, import_react22.useRef)(/* @__PURE__ */ new Set());
|
|
3448
|
-
const abortControllersRef = (0, import_react22.useRef)(/* @__PURE__ */ new Map());
|
|
3449
|
-
(0, import_react22.useEffect)(() => {
|
|
3450
|
-
const controllers = abortControllersRef.current;
|
|
3451
|
-
return () => {
|
|
3452
|
-
cancelledRef.current = true;
|
|
3453
|
-
for (const controller of controllers.values()) {
|
|
3454
|
-
controller.abort();
|
|
3455
|
-
}
|
|
3456
|
-
controllers.clear();
|
|
3457
|
-
};
|
|
3458
|
-
}, []);
|
|
3459
|
-
const addTracks = (0, import_react22.useCallback)((sources) => {
|
|
3460
|
-
if (sources.length === 0) return;
|
|
3461
|
-
const audioContext = (0, import_playout4.getGlobalAudioContext)();
|
|
3462
|
-
const placeholders = sources.map((source) => ({
|
|
3463
|
-
track: (0, import_core5.createTrack)({ name: `${getSourceName(source)} (loading...)`, clips: [] }),
|
|
3464
|
-
source
|
|
3465
|
-
}));
|
|
3466
|
-
setTracks((prev) => [...prev, ...placeholders.map((p) => p.track)]);
|
|
3467
|
-
setLoadingCount((prev) => prev + sources.length);
|
|
3468
|
-
for (const { track, source } of placeholders) {
|
|
3469
|
-
loadingIdsRef.current.add(track.id);
|
|
3470
|
-
const controller = new AbortController();
|
|
3471
|
-
abortControllersRef.current.set(track.id, controller);
|
|
3472
|
-
(() => __async(null, null, function* () {
|
|
3473
|
-
try {
|
|
3474
|
-
const { audioBuffer, name } = yield decodeSource(source, audioContext, controller.signal);
|
|
3475
|
-
const clip = (0, import_core5.createClipFromSeconds)({
|
|
3476
|
-
audioBuffer,
|
|
3477
|
-
startTime: 0,
|
|
3478
|
-
duration: audioBuffer.duration,
|
|
3479
|
-
offset: 0,
|
|
3480
|
-
name
|
|
3481
|
-
});
|
|
3482
|
-
if (!cancelledRef.current && loadingIdsRef.current.has(track.id)) {
|
|
3483
|
-
setTracks(
|
|
3484
|
-
(prev) => prev.map((t) => t.id === track.id ? __spreadProps(__spreadValues({}, t), { name, clips: [clip] }) : t)
|
|
3485
|
-
);
|
|
3486
|
-
}
|
|
3487
|
-
} catch (error) {
|
|
3488
|
-
if (error instanceof DOMException && error.name === "AbortError") return;
|
|
3489
|
-
console.warn("[waveform-playlist] Error loading audio:", error);
|
|
3490
|
-
if (!cancelledRef.current && loadingIdsRef.current.has(track.id)) {
|
|
3491
|
-
setTracks((prev) => prev.filter((t) => t.id !== track.id));
|
|
3492
|
-
setErrors((prev) => [
|
|
3493
|
-
...prev,
|
|
3494
|
-
{
|
|
3495
|
-
name: getSourceName(source),
|
|
3496
|
-
error: error instanceof Error ? error : new Error(String(error))
|
|
3497
|
-
}
|
|
3498
|
-
]);
|
|
3499
|
-
}
|
|
3500
|
-
} finally {
|
|
3501
|
-
abortControllersRef.current.delete(track.id);
|
|
3502
|
-
if (!cancelledRef.current && loadingIdsRef.current.delete(track.id)) {
|
|
3503
|
-
setLoadingCount((prev) => prev - 1);
|
|
3504
|
-
}
|
|
3505
|
-
}
|
|
3506
|
-
}))();
|
|
3507
|
-
}
|
|
3508
|
-
}, []);
|
|
3509
|
-
const removeTrack = (0, import_react22.useCallback)((trackId) => {
|
|
3510
|
-
setTracks((prev) => prev.filter((t) => t.id !== trackId));
|
|
3511
|
-
const controller = abortControllersRef.current.get(trackId);
|
|
3512
|
-
if (controller) {
|
|
3513
|
-
controller.abort();
|
|
3514
|
-
abortControllersRef.current.delete(trackId);
|
|
3515
|
-
}
|
|
3516
|
-
if (loadingIdsRef.current.delete(trackId)) {
|
|
3517
|
-
setLoadingCount((prev) => prev - 1);
|
|
3518
|
-
}
|
|
3519
|
-
}, []);
|
|
3520
|
-
return {
|
|
3521
|
-
tracks,
|
|
3522
|
-
addTracks,
|
|
3523
|
-
removeTrack,
|
|
3524
|
-
loadingCount,
|
|
3525
|
-
isLoading: loadingCount > 0,
|
|
3526
|
-
errors
|
|
3527
|
-
};
|
|
3528
|
-
}
|
|
3529
|
-
|
|
3530
|
-
// src/hooks/useOutputMeter.ts
|
|
3531
|
-
var import_react23 = require("react");
|
|
3532
|
-
var import_playout5 = require("@waveform-playlist/playout");
|
|
3533
|
-
var import_core6 = require("@waveform-playlist/core");
|
|
3534
|
-
var import_worklets = require("@waveform-playlist/worklets");
|
|
3535
|
-
var PEAK_DECAY = 0.98;
|
|
3536
|
-
function useOutputMeter(options = {}) {
|
|
3537
|
-
const { channelCount = 2, updateRate = 60, isPlaying = false } = options;
|
|
3538
|
-
const [levels, setLevels] = (0, import_react23.useState)(() => new Array(channelCount).fill(0));
|
|
3539
|
-
const [peakLevels, setPeakLevels] = (0, import_react23.useState)(() => new Array(channelCount).fill(0));
|
|
3540
|
-
const [rmsLevels, setRmsLevels] = (0, import_react23.useState)(() => new Array(channelCount).fill(0));
|
|
3541
|
-
const workletNodeRef = (0, import_react23.useRef)(null);
|
|
3542
|
-
const smoothedPeakRef = (0, import_react23.useRef)(new Array(channelCount).fill(0));
|
|
3543
|
-
const [meterError, setMeterError] = (0, import_react23.useState)(null);
|
|
3544
|
-
const resetPeak = (0, import_react23.useCallback)(
|
|
3545
|
-
() => setPeakLevels(new Array(channelCount).fill(0)),
|
|
3546
|
-
[channelCount]
|
|
3547
|
-
);
|
|
3548
|
-
(0, import_react23.useEffect)(() => {
|
|
3549
|
-
if (!isPlaying) {
|
|
3550
|
-
const zeros = new Array(channelCount).fill(0);
|
|
3551
|
-
smoothedPeakRef.current = new Array(channelCount).fill(0);
|
|
3552
|
-
setLevels(zeros);
|
|
3553
|
-
setRmsLevels(zeros);
|
|
3554
|
-
setPeakLevels(zeros);
|
|
3555
|
-
}
|
|
3556
|
-
}, [isPlaying, channelCount]);
|
|
3557
|
-
(0, import_react23.useEffect)(() => {
|
|
3558
|
-
let isMounted = true;
|
|
3559
|
-
const setup = () => __async(null, null, function* () {
|
|
3560
|
-
const context = (0, import_playout5.getGlobalContext)();
|
|
3561
|
-
const rawCtx = context.rawContext;
|
|
3562
|
-
yield rawCtx.audioWorklet.addModule(import_worklets.meterProcessorUrl);
|
|
3563
|
-
if (!isMounted) return;
|
|
3564
|
-
const workletNode = context.createAudioWorkletNode("meter-processor", {
|
|
3565
|
-
channelCount,
|
|
3566
|
-
channelCountMode: "explicit",
|
|
3567
|
-
processorOptions: {
|
|
3568
|
-
numberOfChannels: channelCount,
|
|
3569
|
-
updateRate
|
|
3570
|
-
}
|
|
3571
|
-
});
|
|
3572
|
-
workletNodeRef.current = workletNode;
|
|
3573
|
-
workletNode.onprocessorerror = (event) => {
|
|
3574
|
-
console.warn("[waveform-playlist] Output meter worklet processor error:", String(event));
|
|
3575
|
-
};
|
|
3576
|
-
const destination = context.destination;
|
|
3577
|
-
destination.chain(workletNode);
|
|
3578
|
-
smoothedPeakRef.current = new Array(channelCount).fill(0);
|
|
3579
|
-
workletNode.port.onmessage = (event) => {
|
|
3580
|
-
var _a;
|
|
3581
|
-
if (!isMounted) return;
|
|
3582
|
-
const { peak, rms } = event.data;
|
|
3583
|
-
const smoothed = smoothedPeakRef.current;
|
|
3584
|
-
const peakValues = [];
|
|
3585
|
-
const rmsValues = [];
|
|
3586
|
-
for (let ch = 0; ch < peak.length; ch++) {
|
|
3587
|
-
smoothed[ch] = Math.max(peak[ch], ((_a = smoothed[ch]) != null ? _a : 0) * PEAK_DECAY);
|
|
3588
|
-
peakValues.push((0, import_core6.gainToNormalized)(smoothed[ch]));
|
|
3589
|
-
rmsValues.push((0, import_core6.gainToNormalized)(rms[ch]));
|
|
3590
|
-
}
|
|
3591
|
-
setLevels(peakValues);
|
|
3592
|
-
setRmsLevels(rmsValues);
|
|
3593
|
-
setPeakLevels((prev) => peakValues.map((val, i) => {
|
|
3594
|
-
var _a2;
|
|
3595
|
-
return Math.max((_a2 = prev[i]) != null ? _a2 : 0, val);
|
|
3596
|
-
}));
|
|
3597
|
-
};
|
|
3598
|
-
});
|
|
3599
|
-
setup().catch((err) => {
|
|
3600
|
-
console.warn("[waveform-playlist] Failed to set up output meter:", String(err));
|
|
3601
|
-
if (isMounted) {
|
|
3602
|
-
setMeterError(err instanceof Error ? err : new Error(String(err)));
|
|
3603
|
-
}
|
|
3604
|
-
});
|
|
3605
|
-
return () => {
|
|
3606
|
-
isMounted = false;
|
|
3607
|
-
if (workletNodeRef.current) {
|
|
3608
|
-
try {
|
|
3609
|
-
const context = (0, import_playout5.getGlobalContext)();
|
|
3610
|
-
context.destination.chain();
|
|
3611
|
-
} catch (err) {
|
|
3612
|
-
console.warn("[waveform-playlist] Failed to restore destination chain:", String(err));
|
|
3613
|
-
}
|
|
3614
|
-
try {
|
|
3615
|
-
workletNodeRef.current.disconnect();
|
|
3616
|
-
workletNodeRef.current.port.close();
|
|
3617
|
-
} catch (err) {
|
|
3618
|
-
console.warn("[waveform-playlist] Output meter disconnect during cleanup:", String(err));
|
|
3619
|
-
}
|
|
3620
|
-
workletNodeRef.current = null;
|
|
3621
|
-
}
|
|
3622
|
-
};
|
|
3623
|
-
}, [channelCount, updateRate]);
|
|
3624
|
-
return { levels, peakLevels, rmsLevels, resetPeak, error: meterError };
|
|
3625
|
-
}
|
|
3626
|
-
|
|
3627
1854
|
// src/WaveformPlaylistContext.tsx
|
|
3628
1855
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
3629
|
-
var PlaybackAnimationContext = (0,
|
|
3630
|
-
var PlaylistStateContext = (0,
|
|
3631
|
-
var PlaylistControlsContext = (0,
|
|
3632
|
-
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);
|
|
3633
1860
|
var WaveformPlaylistProvider = ({
|
|
3634
1861
|
tracks,
|
|
3635
1862
|
timescale = false,
|
|
@@ -3643,6 +1870,7 @@ var WaveformPlaylistProvider = ({
|
|
|
3643
1870
|
annotationList,
|
|
3644
1871
|
effects,
|
|
3645
1872
|
onReady,
|
|
1873
|
+
onError,
|
|
3646
1874
|
onAnnotationUpdate: _onAnnotationUpdate,
|
|
3647
1875
|
onAnnotationsChange,
|
|
3648
1876
|
barWidth = 1,
|
|
@@ -3653,18 +1881,19 @@ var WaveformPlaylistProvider = ({
|
|
|
3653
1881
|
deferEngineRebuild = false,
|
|
3654
1882
|
indefinitePlayback = false,
|
|
3655
1883
|
sampleRate: sampleRateProp,
|
|
1884
|
+
createAdapter,
|
|
3656
1885
|
children
|
|
3657
1886
|
}) => {
|
|
3658
1887
|
var _a, _b, _c, _d;
|
|
3659
1888
|
const progressBarWidth = progressBarWidthProp != null ? progressBarWidthProp : barWidth + barGap;
|
|
3660
|
-
const indefinitePlaybackRef = (0,
|
|
1889
|
+
const indefinitePlaybackRef = (0, import_react17.useRef)(indefinitePlayback);
|
|
3661
1890
|
indefinitePlaybackRef.current = indefinitePlayback;
|
|
3662
|
-
const stableZoomLevels = (0,
|
|
1891
|
+
const stableZoomLevels = (0, import_react17.useMemo)(
|
|
3663
1892
|
() => zoomLevels,
|
|
3664
1893
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3665
1894
|
[zoomLevels == null ? void 0 : zoomLevels.join(",")]
|
|
3666
1895
|
);
|
|
3667
|
-
const annotations = (0,
|
|
1896
|
+
const annotations = (0, import_react17.useMemo)(() => {
|
|
3668
1897
|
if (!(annotationList == null ? void 0 : annotationList.annotations)) return [];
|
|
3669
1898
|
if (process.env.NODE_ENV !== "production" && annotationList.annotations.length > 0) {
|
|
3670
1899
|
const first = annotationList.annotations[0];
|
|
@@ -3677,63 +1906,50 @@ var WaveformPlaylistProvider = ({
|
|
|
3677
1906
|
}
|
|
3678
1907
|
return annotationList.annotations;
|
|
3679
1908
|
}, [annotationList == null ? void 0 : annotationList.annotations]);
|
|
3680
|
-
const annotationsRef = (0,
|
|
1909
|
+
const annotationsRef = (0, import_react17.useRef)(annotations);
|
|
3681
1910
|
annotationsRef.current = annotations;
|
|
3682
|
-
const [activeAnnotationId, setActiveAnnotationIdState] = (0,
|
|
3683
|
-
const [isPlaying, setIsPlaying] = (0,
|
|
3684
|
-
const [currentTime, setCurrentTime] = (0,
|
|
3685
|
-
const [duration, setDuration] = (0,
|
|
3686
|
-
const [audioBuffers, setAudioBuffers] = (0,
|
|
3687
|
-
const [peaksDataArray, setPeaksDataArray] = (0,
|
|
3688
|
-
const [trackStates, setTrackStates] = (0,
|
|
3689
|
-
const [isAutomaticScroll, setIsAutomaticScroll] = (0,
|
|
3690
|
-
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)(
|
|
3691
1920
|
(_a = annotationList == null ? void 0 : annotationList.isContinuousPlay) != null ? _a : false
|
|
3692
1921
|
);
|
|
3693
|
-
const [linkEndpoints, setLinkEndpoints] = (0,
|
|
3694
|
-
const [annotationsEditable, setAnnotationsEditable] = (0,
|
|
3695
|
-
const [isReady, setIsReady] = (0,
|
|
3696
|
-
const engineRef = (0,
|
|
3697
|
-
const adapterRef = (0,
|
|
3698
|
-
const audioInitializedRef = (0,
|
|
3699
|
-
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);
|
|
3700
1929
|
isPlayingRef.current = isPlaying;
|
|
3701
|
-
const playStartPositionRef = (0,
|
|
3702
|
-
const currentTimeRef = (0,
|
|
3703
|
-
const visualTimeRef = (0,
|
|
3704
|
-
const tracksRef = (0,
|
|
3705
|
-
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);
|
|
3706
1935
|
soundFontCacheRef.current = soundFontCache;
|
|
3707
|
-
const trackStatesRef = (0,
|
|
3708
|
-
const playbackStartTimeRef = (0,
|
|
3709
|
-
const audioStartPositionRef = (0,
|
|
3710
|
-
const playbackEndTimeRef = (0,
|
|
3711
|
-
const scrollContainerRef = (0,
|
|
3712
|
-
const isAutomaticScrollRef = (0,
|
|
3713
|
-
const frameCallbacksRef = (0,
|
|
3714
|
-
const continuousPlayRef = (0,
|
|
3715
|
-
const activeAnnotationIdRef = (0,
|
|
3716
|
-
const engineTracksRef = (0,
|
|
3717
|
-
const lastTracksVersionRef = (0,
|
|
3718
|
-
const skipEngineDisposeRef = (0,
|
|
3719
|
-
const isDraggingRef = (0,
|
|
3720
|
-
const prevTracksRef = (0,
|
|
3721
|
-
const samplesPerPixelRef = (0,
|
|
3722
|
-
const [initialSampleRate] = (0,
|
|
3723
|
-
|
|
3724
|
-
try {
|
|
3725
|
-
if (sampleRateProp !== void 0) {
|
|
3726
|
-
return (0, import_playout6.configureGlobalContext)({ sampleRate: sampleRateProp });
|
|
3727
|
-
}
|
|
3728
|
-
return (0, import_playout6.getGlobalAudioContext)().sampleRate;
|
|
3729
|
-
} catch (err) {
|
|
3730
|
-
console.warn(
|
|
3731
|
-
"[waveform-playlist] Failed to configure AudioContext: " + String(err) + " \u2014 falling back to " + (sampleRateProp != null ? sampleRateProp : 48e3) + " Hz"
|
|
3732
|
-
);
|
|
3733
|
-
return sampleRateProp != null ? sampleRateProp : 48e3;
|
|
3734
|
-
}
|
|
3735
|
-
});
|
|
3736
|
-
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);
|
|
3737
1953
|
const { timeFormat, setTimeFormat, formatTime: formatTime2 } = useTimeFormat();
|
|
3738
1954
|
const zoom = useZoomControls({ engineRef, initialSamplesPerPixel });
|
|
3739
1955
|
const { samplesPerPixel, onEngineState: onZoomEngineState } = zoom;
|
|
@@ -3778,20 +1994,20 @@ var WaveformPlaylistProvider = ({
|
|
|
3778
1994
|
onEngineState: onUndoEngineState
|
|
3779
1995
|
} = useUndoState({ engineRef });
|
|
3780
1996
|
const { animationFrameRef, startAnimationFrameLoop, stopAnimationFrameLoop } = useAnimationFrameLoop();
|
|
3781
|
-
const baseScale = (0,
|
|
1997
|
+
const baseScale = (0, import_react17.useMemo)(
|
|
3782
1998
|
() => Math.min(...stableZoomLevels != null ? stableZoomLevels : [256, 512, 1024, 2048, 4096, 8192]),
|
|
3783
1999
|
[stableZoomLevels]
|
|
3784
2000
|
);
|
|
3785
2001
|
const { cache: waveformDataCache } = useWaveformDataCache(tracks, baseScale);
|
|
3786
|
-
const setContinuousPlay = (0,
|
|
2002
|
+
const setContinuousPlay = (0, import_react17.useCallback)((value) => {
|
|
3787
2003
|
continuousPlayRef.current = value;
|
|
3788
2004
|
setContinuousPlayState(value);
|
|
3789
2005
|
}, []);
|
|
3790
|
-
const setActiveAnnotationId = (0,
|
|
2006
|
+
const setActiveAnnotationId = (0, import_react17.useCallback)((value) => {
|
|
3791
2007
|
activeAnnotationIdRef.current = value;
|
|
3792
2008
|
setActiveAnnotationIdState(value);
|
|
3793
2009
|
}, []);
|
|
3794
|
-
const setLoopRegionFromSelection = (0,
|
|
2010
|
+
const setLoopRegionFromSelection = (0, import_react17.useCallback)(() => {
|
|
3795
2011
|
var _a2, _b2;
|
|
3796
2012
|
const start = (_a2 = selectionStartRef.current) != null ? _a2 : 0;
|
|
3797
2013
|
const end = (_b2 = selectionEndRef.current) != null ? _b2 : 0;
|
|
@@ -3799,10 +2015,10 @@ var WaveformPlaylistProvider = ({
|
|
|
3799
2015
|
setLoopRegion(start, end);
|
|
3800
2016
|
}
|
|
3801
2017
|
}, [setLoopRegion, selectionStartRef, selectionEndRef]);
|
|
3802
|
-
(0,
|
|
2018
|
+
(0, import_react17.useEffect)(() => {
|
|
3803
2019
|
isAutomaticScrollRef.current = isAutomaticScroll;
|
|
3804
2020
|
}, [isAutomaticScroll]);
|
|
3805
|
-
(0,
|
|
2021
|
+
(0, import_react17.useEffect)(() => {
|
|
3806
2022
|
trackStatesRef.current = trackStates;
|
|
3807
2023
|
}, [trackStates]);
|
|
3808
2024
|
tracksRef.current = tracks;
|
|
@@ -3813,7 +2029,7 @@ var WaveformPlaylistProvider = ({
|
|
|
3813
2029
|
return current === pt;
|
|
3814
2030
|
});
|
|
3815
2031
|
skipEngineDisposeRef.current = isEngineTracks || isDraggingRef.current || isIncrementalAdd;
|
|
3816
|
-
(0,
|
|
2032
|
+
(0, import_react17.useEffect)(() => {
|
|
3817
2033
|
if (!scrollContainerRef.current || duration === 0) return;
|
|
3818
2034
|
const container = scrollContainerRef.current;
|
|
3819
2035
|
const oldSamplesPerPixel = samplesPerPixelRef.current;
|
|
@@ -3829,8 +2045,8 @@ var WaveformPlaylistProvider = ({
|
|
|
3829
2045
|
container.scrollLeft = newScrollLeft;
|
|
3830
2046
|
samplesPerPixelRef.current = newSamplesPerPixel;
|
|
3831
2047
|
}, [samplesPerPixel, duration]);
|
|
3832
|
-
const pendingResumeRef = (0,
|
|
3833
|
-
(0,
|
|
2048
|
+
const pendingResumeRef = (0, import_react17.useRef)(null);
|
|
2049
|
+
(0, import_react17.useEffect)(() => {
|
|
3834
2050
|
var _a2, _b2, _c2, _d2;
|
|
3835
2051
|
if (isEngineTracks || isDraggingRef.current) {
|
|
3836
2052
|
if (isEngineTracks) {
|
|
@@ -3935,6 +2151,7 @@ var WaveformPlaylistProvider = ({
|
|
|
3935
2151
|
stopAnimationFrameLoop();
|
|
3936
2152
|
pendingResumeRef.current = { position: resumePosition };
|
|
3937
2153
|
}
|
|
2154
|
+
let cancelled = false;
|
|
3938
2155
|
const loadAudio = () => __async(null, null, function* () {
|
|
3939
2156
|
var _a3, _b3, _c3, _d3, _e;
|
|
3940
2157
|
try {
|
|
@@ -3977,7 +2194,17 @@ var WaveformPlaylistProvider = ({
|
|
|
3977
2194
|
lastTracksVersionRef.current = 0;
|
|
3978
2195
|
engineTracksRef.current = null;
|
|
3979
2196
|
audioInitializedRef.current = false;
|
|
3980
|
-
const adapter =
|
|
2197
|
+
const adapter = yield resolvePlayoutAdapter({
|
|
2198
|
+
createAdapter,
|
|
2199
|
+
effects,
|
|
2200
|
+
soundFontCache: soundFontCacheRef.current,
|
|
2201
|
+
sampleRate: sampleRateProp
|
|
2202
|
+
});
|
|
2203
|
+
if (cancelled) {
|
|
2204
|
+
adapter.dispose();
|
|
2205
|
+
return;
|
|
2206
|
+
}
|
|
2207
|
+
sampleRateRef.current = adapter.audioContext.sampleRate;
|
|
3981
2208
|
adapterRef.current = adapter;
|
|
3982
2209
|
const engine = new import_engine3.PlaylistEngine({
|
|
3983
2210
|
adapter,
|
|
@@ -4035,11 +2262,23 @@ var WaveformPlaylistProvider = ({
|
|
|
4035
2262
|
prevTracksRef.current = tracks;
|
|
4036
2263
|
onReady == null ? void 0 : onReady();
|
|
4037
2264
|
} catch (error) {
|
|
4038
|
-
|
|
2265
|
+
if (!engineRef.current && adapterRef.current) {
|
|
2266
|
+
try {
|
|
2267
|
+
adapterRef.current.dispose();
|
|
2268
|
+
} catch (disposeErr) {
|
|
2269
|
+
console.warn(
|
|
2270
|
+
"[waveform-playlist] adapter dispose after load failure threw: " + String(disposeErr)
|
|
2271
|
+
);
|
|
2272
|
+
}
|
|
2273
|
+
adapterRef.current = null;
|
|
2274
|
+
}
|
|
2275
|
+
console.warn("[waveform-playlist] Error loading audio: " + String(error));
|
|
2276
|
+
onError == null ? void 0 : onError(error instanceof Error ? error : new Error(String(error)));
|
|
4039
2277
|
}
|
|
4040
2278
|
});
|
|
4041
2279
|
loadAudio();
|
|
4042
2280
|
return () => {
|
|
2281
|
+
cancelled = true;
|
|
4043
2282
|
if (skipEngineDisposeRef.current) {
|
|
4044
2283
|
skipEngineDisposeRef.current = false;
|
|
4045
2284
|
return;
|
|
@@ -4062,6 +2301,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4062
2301
|
// to the live adapter by the sync effect below; only adapter creation reads it
|
|
4063
2302
|
// (via soundFontCacheRef).
|
|
4064
2303
|
onReady,
|
|
2304
|
+
onError,
|
|
4065
2305
|
effects,
|
|
4066
2306
|
stopAnimationFrameLoop,
|
|
4067
2307
|
onSelectionEngineState,
|
|
@@ -4080,10 +2320,10 @@ var WaveformPlaylistProvider = ({
|
|
|
4080
2320
|
stableZoomLevels,
|
|
4081
2321
|
deferEngineRebuild
|
|
4082
2322
|
]);
|
|
4083
|
-
(0,
|
|
2323
|
+
(0, import_react17.useEffect)(() => {
|
|
4084
2324
|
syncSoundFontCacheToAdapter(adapterRef.current, soundFontCache);
|
|
4085
2325
|
}, [soundFontCache]);
|
|
4086
|
-
(0,
|
|
2326
|
+
(0, import_react17.useEffect)(() => {
|
|
4087
2327
|
if (tracks.length === 0) return;
|
|
4088
2328
|
const allTrackPeaks = tracks.map((track) => {
|
|
4089
2329
|
const clipPeaks = track.clips.map((clip) => {
|
|
@@ -4164,8 +2404,15 @@ var WaveformPlaylistProvider = ({
|
|
|
4164
2404
|
});
|
|
4165
2405
|
setPeaksDataArray(allTrackPeaks);
|
|
4166
2406
|
}, [tracks, samplesPerPixel, mono, waveformDataCache, deferEngineRebuild]);
|
|
4167
|
-
const
|
|
4168
|
-
|
|
2407
|
+
const getAudioContextTime = (0, import_react17.useCallback)(
|
|
2408
|
+
() => {
|
|
2409
|
+
var _a2, _b2;
|
|
2410
|
+
return (_b2 = (_a2 = adapterRef.current) == null ? void 0 : _a2.audioContext.currentTime) != null ? _b2 : 0;
|
|
2411
|
+
},
|
|
2412
|
+
[]
|
|
2413
|
+
);
|
|
2414
|
+
const getPlaybackTimeFallbackWarnedRef = (0, import_react17.useRef)(false);
|
|
2415
|
+
const getPlaybackTime = (0, import_react17.useCallback)(() => {
|
|
4169
2416
|
var _a2, _b2;
|
|
4170
2417
|
if (engineRef.current) {
|
|
4171
2418
|
return engineRef.current.getCurrentTime();
|
|
@@ -4176,30 +2423,35 @@ var WaveformPlaylistProvider = ({
|
|
|
4176
2423
|
"[waveform-playlist] getPlaybackTime called without engine. Falling back to manual elapsed time (loop wrapping will not work)."
|
|
4177
2424
|
);
|
|
4178
2425
|
}
|
|
4179
|
-
const elapsed = (
|
|
2426
|
+
const elapsed = getAudioContextTime() - ((_a2 = playbackStartTimeRef.current) != null ? _a2 : 0);
|
|
4180
2427
|
return ((_b2 = audioStartPositionRef.current) != null ? _b2 : 0) + elapsed;
|
|
4181
|
-
}, []);
|
|
4182
|
-
const toVisualTime = (0,
|
|
2428
|
+
}, [getAudioContextTime]);
|
|
2429
|
+
const toVisualTime = (0, import_react17.useCallback)((rawTime) => {
|
|
4183
2430
|
return Number.isFinite(rawTime) ? Math.max(0, rawTime) : 0;
|
|
4184
2431
|
}, []);
|
|
4185
|
-
const setCurrentTimeRefs = (0,
|
|
2432
|
+
const setCurrentTimeRefs = (0, import_react17.useCallback)(
|
|
4186
2433
|
(rawTime) => {
|
|
4187
2434
|
currentTimeRef.current = rawTime;
|
|
4188
2435
|
visualTimeRef.current = toVisualTime(rawTime);
|
|
4189
2436
|
},
|
|
4190
2437
|
[toVisualTime]
|
|
4191
2438
|
);
|
|
4192
|
-
const getLookAhead = (0,
|
|
2439
|
+
const getLookAhead = (0, import_react17.useCallback)(() => {
|
|
4193
2440
|
var _a2, _b2;
|
|
4194
2441
|
return (_b2 = (_a2 = engineRef.current) == null ? void 0 : _a2.lookAhead) != null ? _b2 : 0;
|
|
4195
2442
|
}, []);
|
|
4196
|
-
const
|
|
2443
|
+
const getOutputLatency = (0, import_react17.useCallback)(() => {
|
|
2444
|
+
var _a2;
|
|
2445
|
+
const audioCtx = (_a2 = adapterRef.current) == null ? void 0 : _a2.audioContext;
|
|
2446
|
+
return audioCtx && "outputLatency" in audioCtx ? audioCtx.outputLatency : 0;
|
|
2447
|
+
}, []);
|
|
2448
|
+
const registerFrameCallback = (0, import_react17.useCallback)((id, cb) => {
|
|
4197
2449
|
frameCallbacksRef.current.set(id, cb);
|
|
4198
2450
|
}, []);
|
|
4199
|
-
const unregisterFrameCallback = (0,
|
|
2451
|
+
const unregisterFrameCallback = (0, import_react17.useCallback)((id) => {
|
|
4200
2452
|
frameCallbacksRef.current.delete(id);
|
|
4201
2453
|
}, []);
|
|
4202
|
-
const startAnimationLoop = (0,
|
|
2454
|
+
const startAnimationLoop = (0, import_react17.useCallback)(() => {
|
|
4203
2455
|
const updateTime = () => {
|
|
4204
2456
|
const time = getPlaybackTime();
|
|
4205
2457
|
currentTimeRef.current = time;
|
|
@@ -4287,15 +2539,14 @@ var WaveformPlaylistProvider = ({
|
|
|
4287
2539
|
setCurrentTimeRefs
|
|
4288
2540
|
]);
|
|
4289
2541
|
const stopAnimationLoop = stopAnimationFrameLoop;
|
|
4290
|
-
(0,
|
|
2542
|
+
(0, import_react17.useEffect)(() => {
|
|
4291
2543
|
const reschedulePlayback = () => __async(null, null, function* () {
|
|
4292
2544
|
if (isPlaying && animationFrameRef.current && engineRef.current) {
|
|
4293
2545
|
if (continuousPlay) {
|
|
4294
2546
|
const currentPos = currentTimeRef.current;
|
|
4295
2547
|
engineRef.current.stop();
|
|
4296
2548
|
stopAnimationLoop();
|
|
4297
|
-
const
|
|
4298
|
-
const timeNow = context.currentTime;
|
|
2549
|
+
const timeNow = getAudioContextTime();
|
|
4299
2550
|
playbackStartTimeRef.current = timeNow;
|
|
4300
2551
|
audioStartPositionRef.current = currentPos;
|
|
4301
2552
|
engineRef.current.play(currentPos);
|
|
@@ -4311,14 +2562,20 @@ var WaveformPlaylistProvider = ({
|
|
|
4311
2562
|
setIsPlaying(false);
|
|
4312
2563
|
stopAnimationLoop();
|
|
4313
2564
|
});
|
|
4314
|
-
}, [
|
|
4315
|
-
|
|
2565
|
+
}, [
|
|
2566
|
+
continuousPlay,
|
|
2567
|
+
isPlaying,
|
|
2568
|
+
startAnimationLoop,
|
|
2569
|
+
stopAnimationLoop,
|
|
2570
|
+
animationFrameRef,
|
|
2571
|
+
getAudioContextTime
|
|
2572
|
+
]);
|
|
2573
|
+
(0, import_react17.useEffect)(() => {
|
|
4316
2574
|
const resumePlayback = () => __async(null, null, function* () {
|
|
4317
2575
|
if (pendingResumeRef.current && engineRef.current) {
|
|
4318
2576
|
const { position } = pendingResumeRef.current;
|
|
4319
2577
|
pendingResumeRef.current = null;
|
|
4320
|
-
const
|
|
4321
|
-
const timeNow = context.currentTime;
|
|
2578
|
+
const timeNow = getAudioContextTime();
|
|
4322
2579
|
playbackStartTimeRef.current = timeNow;
|
|
4323
2580
|
audioStartPositionRef.current = position;
|
|
4324
2581
|
if (!audioInitializedRef.current) {
|
|
@@ -4335,8 +2592,8 @@ var WaveformPlaylistProvider = ({
|
|
|
4335
2592
|
setIsPlaying(false);
|
|
4336
2593
|
stopAnimationLoop();
|
|
4337
2594
|
});
|
|
4338
|
-
}, [tracks, startAnimationLoop, stopAnimationLoop]);
|
|
4339
|
-
const play = (0,
|
|
2595
|
+
}, [tracks, startAnimationLoop, stopAnimationLoop, getAudioContextTime]);
|
|
2596
|
+
const play = (0, import_react17.useCallback)(
|
|
4340
2597
|
(startTime, playDuration) => __async(null, null, function* () {
|
|
4341
2598
|
if (!engineRef.current) return;
|
|
4342
2599
|
const actualStartTime = startTime != null ? startTime : currentTimeRef.current;
|
|
@@ -4345,8 +2602,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4345
2602
|
engineRef.current.stop();
|
|
4346
2603
|
engineRef.current.seek(actualStartTime);
|
|
4347
2604
|
stopAnimationLoop();
|
|
4348
|
-
const
|
|
4349
|
-
const startTimeNow = context.currentTime;
|
|
2605
|
+
const startTimeNow = getAudioContextTime();
|
|
4350
2606
|
playbackStartTimeRef.current = startTimeNow;
|
|
4351
2607
|
audioStartPositionRef.current = actualStartTime;
|
|
4352
2608
|
playbackEndTimeRef.current = playDuration !== void 0 ? actualStartTime + playDuration : null;
|
|
@@ -4365,9 +2621,9 @@ var WaveformPlaylistProvider = ({
|
|
|
4365
2621
|
setIsPlaying(true);
|
|
4366
2622
|
startAnimationLoop();
|
|
4367
2623
|
}),
|
|
4368
|
-
[startAnimationLoop, stopAnimationLoop, setCurrentTimeRefs]
|
|
2624
|
+
[startAnimationLoop, stopAnimationLoop, setCurrentTimeRefs, getAudioContextTime]
|
|
4369
2625
|
);
|
|
4370
|
-
const pause = (0,
|
|
2626
|
+
const pause = (0, import_react17.useCallback)(() => {
|
|
4371
2627
|
if (!engineRef.current) return;
|
|
4372
2628
|
const pauseTime = getPlaybackTime();
|
|
4373
2629
|
engineRef.current.pause();
|
|
@@ -4376,7 +2632,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4376
2632
|
setCurrentTimeRefs(pauseTime);
|
|
4377
2633
|
setCurrentTime(pauseTime);
|
|
4378
2634
|
}, [stopAnimationLoop, getPlaybackTime, setCurrentTimeRefs]);
|
|
4379
|
-
const stop = (0,
|
|
2635
|
+
const stop = (0, import_react17.useCallback)(() => {
|
|
4380
2636
|
if (!engineRef.current) return;
|
|
4381
2637
|
engineRef.current.stop();
|
|
4382
2638
|
setIsPlaying(false);
|
|
@@ -4385,7 +2641,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4385
2641
|
setCurrentTime(playStartPositionRef.current);
|
|
4386
2642
|
setActiveAnnotationId(null);
|
|
4387
2643
|
}, [stopAnimationLoop, setActiveAnnotationId, setCurrentTimeRefs]);
|
|
4388
|
-
const seekTo = (0,
|
|
2644
|
+
const seekTo = (0, import_react17.useCallback)(
|
|
4389
2645
|
(time) => {
|
|
4390
2646
|
const clampedTime = Math.max(0, Math.min(time, duration));
|
|
4391
2647
|
setCurrentTimeRefs(clampedTime);
|
|
@@ -4396,7 +2652,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4396
2652
|
},
|
|
4397
2653
|
[duration, isPlaying, play, setCurrentTimeRefs]
|
|
4398
2654
|
);
|
|
4399
|
-
const setTrackMute = (0,
|
|
2655
|
+
const setTrackMute = (0, import_react17.useCallback)(
|
|
4400
2656
|
(trackIndex, muted) => {
|
|
4401
2657
|
var _a2;
|
|
4402
2658
|
const trackId = (_a2 = tracksRef.current[trackIndex]) == null ? void 0 : _a2.id;
|
|
@@ -4410,7 +2666,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4410
2666
|
},
|
|
4411
2667
|
[trackStates]
|
|
4412
2668
|
);
|
|
4413
|
-
const setTrackSolo = (0,
|
|
2669
|
+
const setTrackSolo = (0, import_react17.useCallback)(
|
|
4414
2670
|
(trackIndex, soloed) => {
|
|
4415
2671
|
var _a2;
|
|
4416
2672
|
const trackId = (_a2 = tracksRef.current[trackIndex]) == null ? void 0 : _a2.id;
|
|
@@ -4424,7 +2680,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4424
2680
|
},
|
|
4425
2681
|
[trackStates]
|
|
4426
2682
|
);
|
|
4427
|
-
const setTrackVolume = (0,
|
|
2683
|
+
const setTrackVolume = (0, import_react17.useCallback)(
|
|
4428
2684
|
(trackIndex, volume2) => {
|
|
4429
2685
|
var _a2;
|
|
4430
2686
|
const trackId = (_a2 = tracksRef.current[trackIndex]) == null ? void 0 : _a2.id;
|
|
@@ -4438,7 +2694,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4438
2694
|
},
|
|
4439
2695
|
[trackStates]
|
|
4440
2696
|
);
|
|
4441
|
-
const setTrackPan = (0,
|
|
2697
|
+
const setTrackPan = (0, import_react17.useCallback)(
|
|
4442
2698
|
(trackIndex, pan) => {
|
|
4443
2699
|
var _a2;
|
|
4444
2700
|
const trackId = (_a2 = tracksRef.current[trackIndex]) == null ? void 0 : _a2.id;
|
|
@@ -4452,7 +2708,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4452
2708
|
},
|
|
4453
2709
|
[trackStates]
|
|
4454
2710
|
);
|
|
4455
|
-
const setSelection = (0,
|
|
2711
|
+
const setSelection = (0, import_react17.useCallback)(
|
|
4456
2712
|
(start, end) => {
|
|
4457
2713
|
setSelectionEngine(start, end);
|
|
4458
2714
|
setCurrentTimeRefs(start);
|
|
@@ -4465,12 +2721,12 @@ var WaveformPlaylistProvider = ({
|
|
|
4465
2721
|
},
|
|
4466
2722
|
[isPlaying, setSelectionEngine, setCurrentTimeRefs]
|
|
4467
2723
|
);
|
|
4468
|
-
const setScrollContainer = (0,
|
|
2724
|
+
const setScrollContainer = (0, import_react17.useCallback)((element) => {
|
|
4469
2725
|
scrollContainerRef.current = element;
|
|
4470
2726
|
}, []);
|
|
4471
|
-
const onAnnotationsChangeRef = (0,
|
|
2727
|
+
const onAnnotationsChangeRef = (0, import_react17.useRef)(onAnnotationsChange);
|
|
4472
2728
|
onAnnotationsChangeRef.current = onAnnotationsChange;
|
|
4473
|
-
const setAnnotations = (0,
|
|
2729
|
+
const setAnnotations = (0, import_react17.useCallback)(
|
|
4474
2730
|
(action) => {
|
|
4475
2731
|
const updated = typeof action === "function" ? action(annotationsRef.current) : action;
|
|
4476
2732
|
if (!onAnnotationsChangeRef.current) {
|
|
@@ -4488,7 +2744,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4488
2744
|
const sampleRate = sampleRateRef.current;
|
|
4489
2745
|
const timeScaleHeight = timescale ? 30 : 0;
|
|
4490
2746
|
const minimumPlaylistHeight = tracks.length * waveHeight + timeScaleHeight;
|
|
4491
|
-
const animationValue = (0,
|
|
2747
|
+
const animationValue = (0, import_react17.useMemo)(
|
|
4492
2748
|
() => ({
|
|
4493
2749
|
isPlaying,
|
|
4494
2750
|
currentTime,
|
|
@@ -4497,7 +2753,9 @@ var WaveformPlaylistProvider = ({
|
|
|
4497
2753
|
playbackStartTimeRef,
|
|
4498
2754
|
audioStartPositionRef,
|
|
4499
2755
|
getPlaybackTime,
|
|
2756
|
+
getAudioContextTime,
|
|
4500
2757
|
getLookAhead,
|
|
2758
|
+
getOutputLatency,
|
|
4501
2759
|
registerFrameCallback,
|
|
4502
2760
|
unregisterFrameCallback
|
|
4503
2761
|
}),
|
|
@@ -4509,12 +2767,14 @@ var WaveformPlaylistProvider = ({
|
|
|
4509
2767
|
playbackStartTimeRef,
|
|
4510
2768
|
audioStartPositionRef,
|
|
4511
2769
|
getPlaybackTime,
|
|
2770
|
+
getAudioContextTime,
|
|
4512
2771
|
getLookAhead,
|
|
2772
|
+
getOutputLatency,
|
|
4513
2773
|
registerFrameCallback,
|
|
4514
2774
|
unregisterFrameCallback
|
|
4515
2775
|
]
|
|
4516
2776
|
);
|
|
4517
|
-
const stateValue = (0,
|
|
2777
|
+
const stateValue = (0, import_react17.useMemo)(
|
|
4518
2778
|
() => ({
|
|
4519
2779
|
continuousPlay,
|
|
4520
2780
|
linkEndpoints,
|
|
@@ -4550,17 +2810,17 @@ var WaveformPlaylistProvider = ({
|
|
|
4550
2810
|
canRedo
|
|
4551
2811
|
]
|
|
4552
2812
|
);
|
|
4553
|
-
const setCurrentTimeControl = (0,
|
|
2813
|
+
const setCurrentTimeControl = (0, import_react17.useCallback)(
|
|
4554
2814
|
(time) => {
|
|
4555
2815
|
setCurrentTimeRefs(time);
|
|
4556
2816
|
setCurrentTime(time);
|
|
4557
2817
|
},
|
|
4558
2818
|
[setCurrentTimeRefs]
|
|
4559
2819
|
);
|
|
4560
|
-
const setAutomaticScrollControl = (0,
|
|
2820
|
+
const setAutomaticScrollControl = (0, import_react17.useCallback)((enabled) => {
|
|
4561
2821
|
setIsAutomaticScroll(enabled);
|
|
4562
2822
|
}, []);
|
|
4563
|
-
const controlsValue = (0,
|
|
2823
|
+
const controlsValue = (0, import_react17.useMemo)(
|
|
4564
2824
|
() => ({
|
|
4565
2825
|
// Playback controls
|
|
4566
2826
|
play,
|
|
@@ -4636,7 +2896,7 @@ var WaveformPlaylistProvider = ({
|
|
|
4636
2896
|
redo
|
|
4637
2897
|
]
|
|
4638
2898
|
);
|
|
4639
|
-
const dataValue = (0,
|
|
2899
|
+
const dataValue = (0, import_react17.useMemo)(
|
|
4640
2900
|
() => ({
|
|
4641
2901
|
duration,
|
|
4642
2902
|
audioBuffers,
|
|
@@ -4692,44 +2952,69 @@ var WaveformPlaylistProvider = ({
|
|
|
4692
2952
|
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 }) }) }) }) });
|
|
4693
2953
|
};
|
|
4694
2954
|
var usePlaybackAnimation = () => {
|
|
4695
|
-
const context = (0,
|
|
2955
|
+
const context = (0, import_react17.useContext)(PlaybackAnimationContext);
|
|
4696
2956
|
if (!context) {
|
|
4697
2957
|
throw new Error("usePlaybackAnimation must be used within WaveformPlaylistProvider");
|
|
4698
2958
|
}
|
|
4699
2959
|
return context;
|
|
4700
2960
|
};
|
|
4701
2961
|
var usePlaylistState = () => {
|
|
4702
|
-
const context = (0,
|
|
2962
|
+
const context = (0, import_react17.useContext)(PlaylistStateContext);
|
|
4703
2963
|
if (!context) {
|
|
4704
2964
|
throw new Error("usePlaylistState must be used within WaveformPlaylistProvider");
|
|
4705
2965
|
}
|
|
4706
2966
|
return context;
|
|
4707
2967
|
};
|
|
4708
2968
|
var usePlaylistControls = () => {
|
|
4709
|
-
const context = (0,
|
|
2969
|
+
const context = (0, import_react17.useContext)(PlaylistControlsContext);
|
|
4710
2970
|
if (!context) {
|
|
4711
2971
|
throw new Error("usePlaylistControls must be used within WaveformPlaylistProvider");
|
|
4712
2972
|
}
|
|
4713
2973
|
return context;
|
|
4714
2974
|
};
|
|
4715
2975
|
var usePlaylistData = () => {
|
|
4716
|
-
const context = (0,
|
|
2976
|
+
const context = (0, import_react17.useContext)(PlaylistDataContext);
|
|
4717
2977
|
if (!context) {
|
|
4718
2978
|
throw new Error("usePlaylistData must be used within WaveformPlaylistProvider");
|
|
4719
2979
|
}
|
|
4720
2980
|
return context;
|
|
4721
2981
|
};
|
|
2982
|
+
var usePlaylistDataOptional = () => (0, import_react17.useContext)(PlaylistDataContext);
|
|
4722
2983
|
|
|
4723
2984
|
// src/MediaElementPlaylistContext.tsx
|
|
4724
|
-
var
|
|
2985
|
+
var import_react18 = require("react");
|
|
4725
2986
|
var import_styled_components2 = require("styled-components");
|
|
4726
|
-
|
|
2987
|
+
|
|
2988
|
+
// src/playout/resolveMediaElementPlayout.ts
|
|
2989
|
+
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`.";
|
|
2990
|
+
function resolveMediaElementPlayout(opts) {
|
|
2991
|
+
return __async(this, null, function* () {
|
|
2992
|
+
if (opts.createPlayout) {
|
|
2993
|
+
return opts.createPlayout();
|
|
2994
|
+
}
|
|
2995
|
+
let mod;
|
|
2996
|
+
try {
|
|
2997
|
+
mod = yield import("@waveform-playlist/media-element-playout");
|
|
2998
|
+
} catch (originalErr) {
|
|
2999
|
+
console.warn(
|
|
3000
|
+
"[waveform-playlist] @waveform-playlist/media-element-playout dynamic import failed: " + String(originalErr)
|
|
3001
|
+
);
|
|
3002
|
+
throw new Error(INSTALL_HINT2);
|
|
3003
|
+
}
|
|
3004
|
+
return new mod.MediaElementPlayout({
|
|
3005
|
+
playbackRate: opts.playbackRate,
|
|
3006
|
+
preservesPitch: opts.preservesPitch
|
|
3007
|
+
});
|
|
3008
|
+
});
|
|
3009
|
+
}
|
|
3010
|
+
|
|
3011
|
+
// src/MediaElementPlaylistContext.tsx
|
|
4727
3012
|
var import_ui_components3 = require("@waveform-playlist/ui-components");
|
|
4728
3013
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
4729
|
-
var MediaElementAnimationContext = (0,
|
|
4730
|
-
var MediaElementStateContext = (0,
|
|
4731
|
-
var MediaElementControlsContext = (0,
|
|
4732
|
-
var MediaElementDataContext = (0,
|
|
3014
|
+
var MediaElementAnimationContext = (0, import_react18.createContext)(null);
|
|
3015
|
+
var MediaElementStateContext = (0, import_react18.createContext)(null);
|
|
3016
|
+
var MediaElementControlsContext = (0, import_react18.createContext)(null);
|
|
3017
|
+
var MediaElementDataContext = (0, import_react18.createContext)(null);
|
|
4733
3018
|
var MediaElementPlaylistProvider = ({
|
|
4734
3019
|
track,
|
|
4735
3020
|
samplesPerPixel: initialSamplesPerPixel = 1024,
|
|
@@ -4747,16 +3032,18 @@ var MediaElementPlaylistProvider = ({
|
|
|
4747
3032
|
audioContext,
|
|
4748
3033
|
onAnnotationsChange,
|
|
4749
3034
|
onReady,
|
|
3035
|
+
onError,
|
|
3036
|
+
createPlayout,
|
|
4750
3037
|
children
|
|
4751
3038
|
}) => {
|
|
4752
3039
|
var _a;
|
|
4753
3040
|
const progressBarWidth = progressBarWidthProp != null ? progressBarWidthProp : barWidth + barGap;
|
|
4754
|
-
const [isPlaying, setIsPlaying] = (0,
|
|
4755
|
-
const [currentTime, setCurrentTime] = (0,
|
|
4756
|
-
const [duration, setDuration] = (0,
|
|
4757
|
-
const [peaksDataArray, setPeaksDataArray] = (0,
|
|
4758
|
-
const [playbackRate, setPlaybackRateState] = (0,
|
|
4759
|
-
const annotations = (0,
|
|
3041
|
+
const [isPlaying, setIsPlaying] = (0, import_react18.useState)(false);
|
|
3042
|
+
const [currentTime, setCurrentTime] = (0, import_react18.useState)(0);
|
|
3043
|
+
const [duration, setDuration] = (0, import_react18.useState)(0);
|
|
3044
|
+
const [peaksDataArray, setPeaksDataArray] = (0, import_react18.useState)([]);
|
|
3045
|
+
const [playbackRate, setPlaybackRateState] = (0, import_react18.useState)(initialPlaybackRate);
|
|
3046
|
+
const annotations = (0, import_react18.useMemo)(() => {
|
|
4760
3047
|
if (!(annotationList == null ? void 0 : annotationList.annotations)) return [];
|
|
4761
3048
|
if (process.env.NODE_ENV !== "production" && annotationList.annotations.length > 0) {
|
|
4762
3049
|
const first = annotationList.annotations[0];
|
|
@@ -4769,73 +3056,92 @@ var MediaElementPlaylistProvider = ({
|
|
|
4769
3056
|
}
|
|
4770
3057
|
return annotationList.annotations;
|
|
4771
3058
|
}, [annotationList == null ? void 0 : annotationList.annotations]);
|
|
4772
|
-
const annotationsRef = (0,
|
|
3059
|
+
const annotationsRef = (0, import_react18.useRef)(annotations);
|
|
4773
3060
|
annotationsRef.current = annotations;
|
|
4774
|
-
const [activeAnnotationId, setActiveAnnotationIdState] = (0,
|
|
4775
|
-
const [continuousPlay, setContinuousPlayState] = (0,
|
|
3061
|
+
const [activeAnnotationId, setActiveAnnotationIdState] = (0, import_react18.useState)(null);
|
|
3062
|
+
const [continuousPlay, setContinuousPlayState] = (0, import_react18.useState)(
|
|
4776
3063
|
(_a = annotationList == null ? void 0 : annotationList.isContinuousPlay) != null ? _a : false
|
|
4777
3064
|
);
|
|
4778
|
-
const [samplesPerPixel] = (0,
|
|
4779
|
-
const [isAutomaticScroll, setIsAutomaticScroll] = (0,
|
|
4780
|
-
const playoutRef = (0,
|
|
4781
|
-
const currentTimeRef = (0,
|
|
4782
|
-
const continuousPlayRef = (0,
|
|
4783
|
-
const activeAnnotationIdRef = (0,
|
|
4784
|
-
const scrollContainerRef = (0,
|
|
4785
|
-
const isAutomaticScrollRef = (0,
|
|
4786
|
-
const samplesPerPixelRef = (0,
|
|
3065
|
+
const [samplesPerPixel] = (0, import_react18.useState)(initialSamplesPerPixel);
|
|
3066
|
+
const [isAutomaticScroll, setIsAutomaticScroll] = (0, import_react18.useState)(automaticScroll);
|
|
3067
|
+
const playoutRef = (0, import_react18.useRef)(null);
|
|
3068
|
+
const currentTimeRef = (0, import_react18.useRef)(0);
|
|
3069
|
+
const continuousPlayRef = (0, import_react18.useRef)(continuousPlay);
|
|
3070
|
+
const activeAnnotationIdRef = (0, import_react18.useRef)(null);
|
|
3071
|
+
const scrollContainerRef = (0, import_react18.useRef)(null);
|
|
3072
|
+
const isAutomaticScrollRef = (0, import_react18.useRef)(automaticScroll);
|
|
3073
|
+
const samplesPerPixelRef = (0, import_react18.useRef)(initialSamplesPerPixel);
|
|
4787
3074
|
const { startAnimationFrameLoop, stopAnimationFrameLoop } = useAnimationFrameLoop();
|
|
4788
|
-
(0,
|
|
3075
|
+
(0, import_react18.useEffect)(() => {
|
|
4789
3076
|
continuousPlayRef.current = continuousPlay;
|
|
4790
3077
|
}, [continuousPlay]);
|
|
4791
|
-
(0,
|
|
3078
|
+
(0, import_react18.useEffect)(() => {
|
|
4792
3079
|
isAutomaticScrollRef.current = isAutomaticScroll;
|
|
4793
3080
|
}, [isAutomaticScroll]);
|
|
4794
|
-
const setActiveAnnotationId = (0,
|
|
3081
|
+
const setActiveAnnotationId = (0, import_react18.useCallback)((value) => {
|
|
4795
3082
|
activeAnnotationIdRef.current = value;
|
|
4796
3083
|
setActiveAnnotationIdState(value);
|
|
4797
3084
|
}, []);
|
|
4798
|
-
const setContinuousPlay = (0,
|
|
3085
|
+
const setContinuousPlay = (0, import_react18.useCallback)((value) => {
|
|
4799
3086
|
continuousPlayRef.current = value;
|
|
4800
3087
|
setContinuousPlayState(value);
|
|
4801
3088
|
}, []);
|
|
4802
|
-
const setScrollContainer = (0,
|
|
3089
|
+
const setScrollContainer = (0, import_react18.useCallback)((element) => {
|
|
4803
3090
|
scrollContainerRef.current = element;
|
|
4804
3091
|
}, []);
|
|
4805
3092
|
const sampleRate = track.waveformData.sample_rate;
|
|
4806
|
-
(0,
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
3093
|
+
(0, import_react18.useEffect)(() => {
|
|
3094
|
+
let cancelled = false;
|
|
3095
|
+
let createdPlayout = null;
|
|
3096
|
+
(() => __async(null, null, function* () {
|
|
3097
|
+
var _a2, _b;
|
|
3098
|
+
try {
|
|
3099
|
+
const playout = yield resolveMediaElementPlayout({
|
|
3100
|
+
createPlayout,
|
|
3101
|
+
playbackRate: initialPlaybackRate,
|
|
3102
|
+
preservesPitch
|
|
3103
|
+
});
|
|
3104
|
+
if (cancelled) {
|
|
3105
|
+
playout.dispose();
|
|
3106
|
+
return;
|
|
3107
|
+
}
|
|
3108
|
+
createdPlayout = playout;
|
|
3109
|
+
playout.addTrack({
|
|
3110
|
+
source: track.source,
|
|
3111
|
+
peaks: track.waveformData,
|
|
3112
|
+
name: track.name,
|
|
3113
|
+
audioContext,
|
|
3114
|
+
fadeIn: track.fadeIn,
|
|
3115
|
+
fadeOut: track.fadeOut
|
|
3116
|
+
});
|
|
3117
|
+
const mediaTrack = playout.getTrack((_b = (_a2 = playout["track"]) == null ? void 0 : _a2.id) != null ? _b : "");
|
|
3118
|
+
if (mediaTrack) {
|
|
3119
|
+
mediaTrack.setOnTimeUpdateCallback((time) => {
|
|
3120
|
+
currentTimeRef.current = time;
|
|
3121
|
+
});
|
|
3122
|
+
}
|
|
3123
|
+
playout.setOnPlaybackComplete(() => {
|
|
3124
|
+
stopAnimationFrameLoop();
|
|
3125
|
+
setIsPlaying(false);
|
|
3126
|
+
setActiveAnnotationId(null);
|
|
3127
|
+
currentTimeRef.current = 0;
|
|
3128
|
+
setCurrentTime(0);
|
|
3129
|
+
});
|
|
3130
|
+
playoutRef.current = playout;
|
|
3131
|
+
setDuration(track.waveformData.duration);
|
|
3132
|
+
onReady == null ? void 0 : onReady();
|
|
3133
|
+
} catch (err) {
|
|
3134
|
+
console.warn("[waveform-playlist] MediaElement playout init failed: " + String(err));
|
|
3135
|
+
onError == null ? void 0 : onError(err instanceof Error ? err : new Error(String(err)));
|
|
3136
|
+
}
|
|
3137
|
+
}))();
|
|
4836
3138
|
return () => {
|
|
3139
|
+
cancelled = true;
|
|
4837
3140
|
stopAnimationFrameLoop();
|
|
4838
|
-
|
|
3141
|
+
if (createdPlayout) {
|
|
3142
|
+
createdPlayout.dispose();
|
|
3143
|
+
}
|
|
3144
|
+
playoutRef.current = null;
|
|
4839
3145
|
};
|
|
4840
3146
|
}, [
|
|
4841
3147
|
track.source,
|
|
@@ -4847,10 +3153,12 @@ var MediaElementPlaylistProvider = ({
|
|
|
4847
3153
|
initialPlaybackRate,
|
|
4848
3154
|
preservesPitch,
|
|
4849
3155
|
onReady,
|
|
3156
|
+
onError,
|
|
4850
3157
|
stopAnimationFrameLoop,
|
|
4851
|
-
setActiveAnnotationId
|
|
3158
|
+
setActiveAnnotationId,
|
|
3159
|
+
createPlayout
|
|
4852
3160
|
]);
|
|
4853
|
-
(0,
|
|
3161
|
+
(0, import_react18.useEffect)(() => {
|
|
4854
3162
|
var _a2;
|
|
4855
3163
|
try {
|
|
4856
3164
|
const extractedPeaks = extractPeaksFromWaveformData(
|
|
@@ -4879,7 +3187,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4879
3187
|
console.warn("[waveform-playlist] Failed to extract peaks from waveform data:", err);
|
|
4880
3188
|
}
|
|
4881
3189
|
}, [track.waveformData, track.name, samplesPerPixel, sampleRate]);
|
|
4882
|
-
const startAnimationLoop = (0,
|
|
3190
|
+
const startAnimationLoop = (0, import_react18.useCallback)(() => {
|
|
4883
3191
|
const updateTime = () => {
|
|
4884
3192
|
var _a2, _b, _c;
|
|
4885
3193
|
const time = (_b = (_a2 = playoutRef.current) == null ? void 0 : _a2.getCurrentTime()) != null ? _b : 0;
|
|
@@ -4922,7 +3230,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4922
3230
|
startAnimationFrameLoop(updateTime);
|
|
4923
3231
|
}, [setActiveAnnotationId, sampleRate, startAnimationFrameLoop]);
|
|
4924
3232
|
const stopAnimationLoop = stopAnimationFrameLoop;
|
|
4925
|
-
const play = (0,
|
|
3233
|
+
const play = (0, import_react18.useCallback)(
|
|
4926
3234
|
(startTime) => {
|
|
4927
3235
|
if (!playoutRef.current) return;
|
|
4928
3236
|
const actualStartTime = startTime != null ? startTime : currentTimeRef.current;
|
|
@@ -4932,14 +3240,14 @@ var MediaElementPlaylistProvider = ({
|
|
|
4932
3240
|
},
|
|
4933
3241
|
[startAnimationLoop]
|
|
4934
3242
|
);
|
|
4935
|
-
const pause = (0,
|
|
3243
|
+
const pause = (0, import_react18.useCallback)(() => {
|
|
4936
3244
|
if (!playoutRef.current) return;
|
|
4937
3245
|
playoutRef.current.pause();
|
|
4938
3246
|
setIsPlaying(false);
|
|
4939
3247
|
stopAnimationLoop();
|
|
4940
3248
|
setCurrentTime(playoutRef.current.getCurrentTime());
|
|
4941
3249
|
}, [stopAnimationLoop]);
|
|
4942
|
-
const stop = (0,
|
|
3250
|
+
const stop = (0, import_react18.useCallback)(() => {
|
|
4943
3251
|
if (!playoutRef.current) return;
|
|
4944
3252
|
playoutRef.current.stop();
|
|
4945
3253
|
setIsPlaying(false);
|
|
@@ -4948,7 +3256,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4948
3256
|
setCurrentTime(0);
|
|
4949
3257
|
setActiveAnnotationId(null);
|
|
4950
3258
|
}, [stopAnimationLoop, setActiveAnnotationId]);
|
|
4951
|
-
const seekTo = (0,
|
|
3259
|
+
const seekTo = (0, import_react18.useCallback)(
|
|
4952
3260
|
(time) => {
|
|
4953
3261
|
const clampedTime = Math.max(0, Math.min(time, duration));
|
|
4954
3262
|
currentTimeRef.current = clampedTime;
|
|
@@ -4959,7 +3267,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4959
3267
|
},
|
|
4960
3268
|
[duration]
|
|
4961
3269
|
);
|
|
4962
|
-
const setPlaybackRate = (0,
|
|
3270
|
+
const setPlaybackRate = (0, import_react18.useCallback)((rate) => {
|
|
4963
3271
|
const clampedRate = Math.max(0.5, Math.min(2, rate));
|
|
4964
3272
|
setPlaybackRateState(clampedRate);
|
|
4965
3273
|
if (playoutRef.current) {
|
|
@@ -4967,7 +3275,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4967
3275
|
}
|
|
4968
3276
|
}, []);
|
|
4969
3277
|
const timeScaleHeight = timescale ? 30 : 0;
|
|
4970
|
-
const animationValue = (0,
|
|
3278
|
+
const animationValue = (0, import_react18.useMemo)(
|
|
4971
3279
|
() => ({
|
|
4972
3280
|
isPlaying,
|
|
4973
3281
|
currentTime,
|
|
@@ -4975,7 +3283,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
4975
3283
|
}),
|
|
4976
3284
|
[isPlaying, currentTime]
|
|
4977
3285
|
);
|
|
4978
|
-
const stateValue = (0,
|
|
3286
|
+
const stateValue = (0, import_react18.useMemo)(
|
|
4979
3287
|
() => ({
|
|
4980
3288
|
continuousPlay,
|
|
4981
3289
|
annotations,
|
|
@@ -4985,9 +3293,9 @@ var MediaElementPlaylistProvider = ({
|
|
|
4985
3293
|
}),
|
|
4986
3294
|
[continuousPlay, annotations, activeAnnotationId, playbackRate, isAutomaticScroll]
|
|
4987
3295
|
);
|
|
4988
|
-
const onAnnotationsChangeRef = (0,
|
|
3296
|
+
const onAnnotationsChangeRef = (0, import_react18.useRef)(onAnnotationsChange);
|
|
4989
3297
|
onAnnotationsChangeRef.current = onAnnotationsChange;
|
|
4990
|
-
const setAnnotations = (0,
|
|
3298
|
+
const setAnnotations = (0, import_react18.useCallback)(
|
|
4991
3299
|
(action) => {
|
|
4992
3300
|
const updated = typeof action === "function" ? action(annotationsRef.current) : action;
|
|
4993
3301
|
if (!onAnnotationsChangeRef.current) {
|
|
@@ -5002,7 +3310,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
5002
3310
|
},
|
|
5003
3311
|
[]
|
|
5004
3312
|
);
|
|
5005
|
-
const controlsValue = (0,
|
|
3313
|
+
const controlsValue = (0, import_react18.useMemo)(
|
|
5006
3314
|
() => ({
|
|
5007
3315
|
play,
|
|
5008
3316
|
pause,
|
|
@@ -5030,7 +3338,7 @@ var MediaElementPlaylistProvider = ({
|
|
|
5030
3338
|
setScrollContainer
|
|
5031
3339
|
]
|
|
5032
3340
|
);
|
|
5033
|
-
const dataValue = (0,
|
|
3341
|
+
const dataValue = (0, import_react18.useMemo)(
|
|
5034
3342
|
() => ({
|
|
5035
3343
|
duration,
|
|
5036
3344
|
peaksDataArray,
|
|
@@ -5065,28 +3373,28 @@ var MediaElementPlaylistProvider = ({
|
|
|
5065
3373
|
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 }) }) }) }) });
|
|
5066
3374
|
};
|
|
5067
3375
|
var useMediaElementAnimation = () => {
|
|
5068
|
-
const context = (0,
|
|
3376
|
+
const context = (0, import_react18.useContext)(MediaElementAnimationContext);
|
|
5069
3377
|
if (!context) {
|
|
5070
3378
|
throw new Error("useMediaElementAnimation must be used within MediaElementPlaylistProvider");
|
|
5071
3379
|
}
|
|
5072
3380
|
return context;
|
|
5073
3381
|
};
|
|
5074
3382
|
var useMediaElementState = () => {
|
|
5075
|
-
const context = (0,
|
|
3383
|
+
const context = (0, import_react18.useContext)(MediaElementStateContext);
|
|
5076
3384
|
if (!context) {
|
|
5077
3385
|
throw new Error("useMediaElementState must be used within MediaElementPlaylistProvider");
|
|
5078
3386
|
}
|
|
5079
3387
|
return context;
|
|
5080
3388
|
};
|
|
5081
3389
|
var useMediaElementControls = () => {
|
|
5082
|
-
const context = (0,
|
|
3390
|
+
const context = (0, import_react18.useContext)(MediaElementControlsContext);
|
|
5083
3391
|
if (!context) {
|
|
5084
3392
|
throw new Error("useMediaElementControls must be used within MediaElementPlaylistProvider");
|
|
5085
3393
|
}
|
|
5086
3394
|
return context;
|
|
5087
3395
|
};
|
|
5088
3396
|
var useMediaElementData = () => {
|
|
5089
|
-
const context = (0,
|
|
3397
|
+
const context = (0, import_react18.useContext)(MediaElementDataContext);
|
|
5090
3398
|
if (!context) {
|
|
5091
3399
|
throw new Error("useMediaElementData must be used within MediaElementPlaylistProvider");
|
|
5092
3400
|
}
|
|
@@ -5094,7 +3402,7 @@ var useMediaElementData = () => {
|
|
|
5094
3402
|
};
|
|
5095
3403
|
|
|
5096
3404
|
// src/components/PlaybackControls.tsx
|
|
5097
|
-
var
|
|
3405
|
+
var import_react19 = require("react");
|
|
5098
3406
|
var import_ui_components4 = require("@waveform-playlist/ui-components");
|
|
5099
3407
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
5100
3408
|
var PlayButton = ({ className }) => {
|
|
@@ -5230,7 +3538,7 @@ var ClearAllButton = ({
|
|
|
5230
3538
|
className
|
|
5231
3539
|
}) => {
|
|
5232
3540
|
const { stop } = usePlaylistControls();
|
|
5233
|
-
const handleClick = (0,
|
|
3541
|
+
const handleClick = (0, import_react19.useCallback)(() => {
|
|
5234
3542
|
stop();
|
|
5235
3543
|
onClearAll();
|
|
5236
3544
|
}, [stop, onClearAll]);
|
|
@@ -5258,7 +3566,7 @@ var ZoomOutButton = ({
|
|
|
5258
3566
|
};
|
|
5259
3567
|
|
|
5260
3568
|
// src/components/ContextualControls.tsx
|
|
5261
|
-
var
|
|
3569
|
+
var import_react20 = require("react");
|
|
5262
3570
|
var import_ui_components6 = require("@waveform-playlist/ui-components");
|
|
5263
3571
|
var import_styled_components3 = __toESM(require("styled-components"));
|
|
5264
3572
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
@@ -5291,10 +3599,10 @@ var PositionDisplay = import_styled_components3.default.span`
|
|
|
5291
3599
|
`;
|
|
5292
3600
|
var AudioPosition = ({ className }) => {
|
|
5293
3601
|
var _a;
|
|
5294
|
-
const timeRef = (0,
|
|
3602
|
+
const timeRef = (0, import_react20.useRef)(null);
|
|
5295
3603
|
const { isPlaying, currentTimeRef, registerFrameCallback, unregisterFrameCallback } = usePlaybackAnimation();
|
|
5296
3604
|
const { timeFormat: format } = usePlaylistData();
|
|
5297
|
-
(0,
|
|
3605
|
+
(0, import_react20.useEffect)(() => {
|
|
5298
3606
|
const id = "audio-position";
|
|
5299
3607
|
if (isPlaying) {
|
|
5300
3608
|
registerFrameCallback(id, ({ time }) => {
|
|
@@ -5305,7 +3613,7 @@ var AudioPosition = ({ className }) => {
|
|
|
5305
3613
|
}
|
|
5306
3614
|
return () => unregisterFrameCallback(id);
|
|
5307
3615
|
}, [isPlaying, format, registerFrameCallback, unregisterFrameCallback]);
|
|
5308
|
-
(0,
|
|
3616
|
+
(0, import_react20.useEffect)(() => {
|
|
5309
3617
|
var _a2;
|
|
5310
3618
|
if (!isPlaying && timeRef.current) {
|
|
5311
3619
|
timeRef.current.textContent = (0, import_ui_components6.formatTime)((_a2 = currentTimeRef.current) != null ? _a2 : 0, format);
|
|
@@ -5340,11 +3648,11 @@ var AutomaticScrollCheckbox = ({ className }) => {
|
|
|
5340
3648
|
};
|
|
5341
3649
|
|
|
5342
3650
|
// src/AnnotationIntegrationContext.tsx
|
|
5343
|
-
var
|
|
5344
|
-
var AnnotationIntegrationContext = (0,
|
|
3651
|
+
var import_react21 = require("react");
|
|
3652
|
+
var AnnotationIntegrationContext = (0, import_react21.createContext)(null);
|
|
5345
3653
|
var AnnotationIntegrationProvider = AnnotationIntegrationContext.Provider;
|
|
5346
3654
|
function useAnnotationIntegration() {
|
|
5347
|
-
const context = (0,
|
|
3655
|
+
const context = (0, import_react21.useContext)(AnnotationIntegrationContext);
|
|
5348
3656
|
if (!context) {
|
|
5349
3657
|
throw new Error(
|
|
5350
3658
|
"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"
|
|
@@ -5382,73 +3690,25 @@ var DownloadAnnotationsButton = ({
|
|
|
5382
3690
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Base, { annotations, filename, className });
|
|
5383
3691
|
};
|
|
5384
3692
|
|
|
5385
|
-
// src/components/ExportControls.tsx
|
|
5386
|
-
var import_ui_components7 = require("@waveform-playlist/ui-components");
|
|
5387
|
-
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
5388
|
-
var ExportWavButton = ({
|
|
5389
|
-
label = "Export WAV",
|
|
5390
|
-
filename = "export",
|
|
5391
|
-
mode = "master",
|
|
5392
|
-
trackIndex,
|
|
5393
|
-
bitDepth = 16,
|
|
5394
|
-
applyEffects = true,
|
|
5395
|
-
effectsFunction,
|
|
5396
|
-
createOfflineTrackEffects,
|
|
5397
|
-
className,
|
|
5398
|
-
onExportComplete,
|
|
5399
|
-
onExportError
|
|
5400
|
-
}) => {
|
|
5401
|
-
const { tracks, trackStates } = usePlaylistData();
|
|
5402
|
-
const { exportWav, isExporting, progress } = useExportWav();
|
|
5403
|
-
const handleExport = () => __async(null, null, function* () {
|
|
5404
|
-
try {
|
|
5405
|
-
const result = yield exportWav(tracks, trackStates, {
|
|
5406
|
-
filename,
|
|
5407
|
-
mode,
|
|
5408
|
-
trackIndex,
|
|
5409
|
-
bitDepth,
|
|
5410
|
-
applyEffects,
|
|
5411
|
-
effectsFunction,
|
|
5412
|
-
createOfflineTrackEffects,
|
|
5413
|
-
autoDownload: true
|
|
5414
|
-
});
|
|
5415
|
-
onExportComplete == null ? void 0 : onExportComplete(result.blob);
|
|
5416
|
-
} catch (error) {
|
|
5417
|
-
onExportError == null ? void 0 : onExportError(error instanceof Error ? error : new Error("Export failed"));
|
|
5418
|
-
}
|
|
5419
|
-
});
|
|
5420
|
-
const buttonLabel = isExporting ? `Exporting ${Math.round(progress * 100)}%` : label;
|
|
5421
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
5422
|
-
import_ui_components7.BaseControlButton,
|
|
5423
|
-
{
|
|
5424
|
-
onClick: handleExport,
|
|
5425
|
-
disabled: isExporting || tracks.length === 0,
|
|
5426
|
-
className,
|
|
5427
|
-
children: buttonLabel
|
|
5428
|
-
}
|
|
5429
|
-
);
|
|
5430
|
-
};
|
|
5431
|
-
|
|
5432
3693
|
// src/contexts/ClipInteractionContext.tsx
|
|
5433
|
-
var
|
|
5434
|
-
var ClipInteractionContext = (0,
|
|
3694
|
+
var import_react22 = require("react");
|
|
3695
|
+
var ClipInteractionContext = (0, import_react22.createContext)(false);
|
|
5435
3696
|
var ClipInteractionContextProvider = ClipInteractionContext.Provider;
|
|
5436
3697
|
function useClipInteractionEnabled() {
|
|
5437
|
-
return (0,
|
|
3698
|
+
return (0, import_react22.useContext)(ClipInteractionContext);
|
|
5438
3699
|
}
|
|
5439
3700
|
|
|
5440
3701
|
// src/components/PlaylistVisualization.tsx
|
|
5441
|
-
var
|
|
3702
|
+
var import_react26 = require("react");
|
|
5442
3703
|
var import_react_dom = require("react-dom");
|
|
5443
3704
|
var import_styled_components6 = __toESM(require("styled-components"));
|
|
5444
|
-
var
|
|
5445
|
-
var
|
|
5446
|
-
var import_core8 = require("@waveform-playlist/core");
|
|
3705
|
+
var import_ui_components8 = require("@waveform-playlist/ui-components");
|
|
3706
|
+
var import_core4 = require("@waveform-playlist/core");
|
|
5447
3707
|
|
|
5448
3708
|
// src/components/AnimatedPlayhead.tsx
|
|
5449
|
-
var
|
|
3709
|
+
var import_react23 = require("react");
|
|
5450
3710
|
var import_styled_components4 = __toESM(require("styled-components"));
|
|
5451
|
-
var
|
|
3711
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
5452
3712
|
var PlayheadLine = import_styled_components4.default.div.attrs((props) => ({
|
|
5453
3713
|
style: {
|
|
5454
3714
|
width: `${props.$width}px`,
|
|
@@ -5464,7 +3724,7 @@ var PlayheadLine = import_styled_components4.default.div.attrs((props) => ({
|
|
|
5464
3724
|
will-change: transform;
|
|
5465
3725
|
`;
|
|
5466
3726
|
var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
5467
|
-
const playheadRef = (0,
|
|
3727
|
+
const playheadRef = (0, import_react23.useRef)(null);
|
|
5468
3728
|
const {
|
|
5469
3729
|
isPlaying,
|
|
5470
3730
|
currentTimeRef,
|
|
@@ -5473,7 +3733,7 @@ var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
|
5473
3733
|
unregisterFrameCallback
|
|
5474
3734
|
} = usePlaybackAnimation();
|
|
5475
3735
|
const { samplesPerPixel, sampleRate, progressBarWidth } = usePlaylistData();
|
|
5476
|
-
(0,
|
|
3736
|
+
(0, import_react23.useEffect)(() => {
|
|
5477
3737
|
const id = "playhead";
|
|
5478
3738
|
if (isPlaying) {
|
|
5479
3739
|
registerFrameCallback(id, ({ visualTime, sampleRate: sr, samplesPerPixel: spp }) => {
|
|
@@ -5485,7 +3745,7 @@ var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
|
5485
3745
|
}
|
|
5486
3746
|
return () => unregisterFrameCallback(id);
|
|
5487
3747
|
}, [isPlaying, registerFrameCallback, unregisterFrameCallback]);
|
|
5488
|
-
(0,
|
|
3748
|
+
(0, import_react23.useEffect)(() => {
|
|
5489
3749
|
var _a, _b;
|
|
5490
3750
|
if (!isPlaying && playheadRef.current) {
|
|
5491
3751
|
const time = (_b = (_a = visualTimeRef.current) != null ? _a : currentTimeRef.current) != null ? _b : 0;
|
|
@@ -5493,15 +3753,15 @@ var AnimatedPlayhead = ({ color = "#ff0000" }) => {
|
|
|
5493
3753
|
playheadRef.current.style.transform = `translate3d(${position}px, 0, 0)`;
|
|
5494
3754
|
}
|
|
5495
3755
|
});
|
|
5496
|
-
return /* @__PURE__ */ (0,
|
|
3756
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PlayheadLine, { ref: playheadRef, $color: color, $width: progressBarWidth, "data-playhead": true });
|
|
5497
3757
|
};
|
|
5498
3758
|
|
|
5499
3759
|
// src/components/ChannelWithProgress.tsx
|
|
5500
|
-
var
|
|
3760
|
+
var import_react24 = require("react");
|
|
5501
3761
|
var import_styled_components5 = __toESM(require("styled-components"));
|
|
5502
|
-
var
|
|
5503
|
-
var
|
|
5504
|
-
var
|
|
3762
|
+
var import_core3 = require("@waveform-playlist/core");
|
|
3763
|
+
var import_ui_components7 = require("@waveform-playlist/ui-components");
|
|
3764
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
5505
3765
|
var ChannelWrapper = import_styled_components5.default.div`
|
|
5506
3766
|
position: relative;
|
|
5507
3767
|
`;
|
|
@@ -5555,10 +3815,10 @@ var ChannelWithProgress = (_a) => {
|
|
|
5555
3815
|
"clipSampleRate",
|
|
5556
3816
|
"clipOffsetSeconds"
|
|
5557
3817
|
]);
|
|
5558
|
-
const progressRef = (0,
|
|
5559
|
-
const callbackId = (0,
|
|
5560
|
-
const theme = (0,
|
|
5561
|
-
const { waveHeight } = (0,
|
|
3818
|
+
const progressRef = (0, import_react24.useRef)(null);
|
|
3819
|
+
const callbackId = (0, import_react24.useId)();
|
|
3820
|
+
const theme = (0, import_ui_components7.useTheme)();
|
|
3821
|
+
const { waveHeight } = (0, import_ui_components7.usePlaylistInfo)();
|
|
5562
3822
|
const {
|
|
5563
3823
|
isPlaying,
|
|
5564
3824
|
currentTimeRef,
|
|
@@ -5568,12 +3828,12 @@ var ChannelWithProgress = (_a) => {
|
|
|
5568
3828
|
} = usePlaybackAnimation();
|
|
5569
3829
|
const { samplesPerPixel, sampleRate } = usePlaylistData();
|
|
5570
3830
|
const progressColor = (theme == null ? void 0 : theme.waveProgressColor) || "rgba(0, 0, 0, 0.1)";
|
|
5571
|
-
const clipPixelWidth = (0,
|
|
3831
|
+
const clipPixelWidth = (0, import_core3.clipPixelWidth)(
|
|
5572
3832
|
clipStartSample,
|
|
5573
3833
|
clipDurationSamples,
|
|
5574
3834
|
samplesPerPixel
|
|
5575
3835
|
);
|
|
5576
|
-
(0,
|
|
3836
|
+
(0, import_react24.useEffect)(() => {
|
|
5577
3837
|
if (isPlaying) {
|
|
5578
3838
|
registerFrameCallback(callbackId, ({ visualTime, sampleRate: sr }) => {
|
|
5579
3839
|
if (progressRef.current) {
|
|
@@ -5601,7 +3861,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5601
3861
|
registerFrameCallback,
|
|
5602
3862
|
unregisterFrameCallback
|
|
5603
3863
|
]);
|
|
5604
|
-
(0,
|
|
3864
|
+
(0, import_react24.useEffect)(() => {
|
|
5605
3865
|
var _a2, _b2;
|
|
5606
3866
|
if (!isPlaying && progressRef.current) {
|
|
5607
3867
|
const currentTime = (_b2 = (_a2 = visualTimeRef.current) != null ? _a2 : currentTimeRef.current) != null ? _b2 : 0;
|
|
@@ -5629,14 +3889,14 @@ var ChannelWithProgress = (_a) => {
|
|
|
5629
3889
|
const isSpectrogramMode = smartChannelProps.renderMode === "spectrogram" || smartChannelProps.renderMode === "both";
|
|
5630
3890
|
const isPianoRollMode = smartChannelProps.renderMode === "piano-roll";
|
|
5631
3891
|
const isBothMode = smartChannelProps.renderMode === "both";
|
|
5632
|
-
const backgroundCss = isSpectrogramMode ? "#000" : isPianoRollMode ? (theme == null ? void 0 : theme.pianoRollBackgroundColor) || "#1a1a2e" : (0,
|
|
3892
|
+
const backgroundCss = isSpectrogramMode ? "#000" : isPianoRollMode ? (theme == null ? void 0 : theme.pianoRollBackgroundColor) || "#1a1a2e" : (0, import_ui_components7.waveformColorToCss)(backgroundColor);
|
|
5633
3893
|
const halfHeight = Math.floor(waveHeight / 2);
|
|
5634
3894
|
const effectiveHeight = waveHeight;
|
|
5635
3895
|
const effectiveTop = isBothMode ? smartChannelProps.index * waveHeight : smartChannelProps.index * waveHeight;
|
|
5636
|
-
const waveformBackgroundCss = (0,
|
|
5637
|
-
return /* @__PURE__ */ (0,
|
|
5638
|
-
isBothMode ? /* @__PURE__ */ (0,
|
|
5639
|
-
/* @__PURE__ */ (0,
|
|
3896
|
+
const waveformBackgroundCss = (0, import_ui_components7.waveformColorToCss)(backgroundColor);
|
|
3897
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(ChannelWrapper, { children: [
|
|
3898
|
+
isBothMode ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
3899
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
5640
3900
|
Background,
|
|
5641
3901
|
{
|
|
5642
3902
|
$color: "#000",
|
|
@@ -5645,7 +3905,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5645
3905
|
$width: smartChannelProps.length
|
|
5646
3906
|
}
|
|
5647
3907
|
),
|
|
5648
|
-
/* @__PURE__ */ (0,
|
|
3908
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
5649
3909
|
Background,
|
|
5650
3910
|
{
|
|
5651
3911
|
$color: waveformBackgroundCss,
|
|
@@ -5654,7 +3914,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5654
3914
|
$width: smartChannelProps.length
|
|
5655
3915
|
}
|
|
5656
3916
|
)
|
|
5657
|
-
] }) : /* @__PURE__ */ (0,
|
|
3917
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
5658
3918
|
Background,
|
|
5659
3919
|
{
|
|
5660
3920
|
$color: backgroundCss,
|
|
@@ -5663,7 +3923,7 @@ var ChannelWithProgress = (_a) => {
|
|
|
5663
3923
|
$width: smartChannelProps.length
|
|
5664
3924
|
}
|
|
5665
3925
|
),
|
|
5666
|
-
!isPianoRollMode && /* @__PURE__ */ (0,
|
|
3926
|
+
!isPianoRollMode && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
5667
3927
|
ProgressOverlay,
|
|
5668
3928
|
{
|
|
5669
3929
|
ref: progressRef,
|
|
@@ -5673,8 +3933,8 @@ var ChannelWithProgress = (_a) => {
|
|
|
5673
3933
|
$width: clipPixelWidth
|
|
5674
3934
|
}
|
|
5675
3935
|
),
|
|
5676
|
-
/* @__PURE__ */ (0,
|
|
5677
|
-
|
|
3936
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ChannelContainer, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
3937
|
+
import_ui_components7.SmartChannel,
|
|
5678
3938
|
__spreadProps(__spreadValues({}, smartChannelProps), {
|
|
5679
3939
|
transparentBackground: true,
|
|
5680
3940
|
midiNotes,
|
|
@@ -5686,11 +3946,11 @@ var ChannelWithProgress = (_a) => {
|
|
|
5686
3946
|
};
|
|
5687
3947
|
|
|
5688
3948
|
// src/SpectrogramIntegrationContext.tsx
|
|
5689
|
-
var
|
|
5690
|
-
var SpectrogramIntegrationContext = (0,
|
|
3949
|
+
var import_react25 = require("react");
|
|
3950
|
+
var SpectrogramIntegrationContext = (0, import_react25.createContext)(null);
|
|
5691
3951
|
var SpectrogramIntegrationProvider = SpectrogramIntegrationContext.Provider;
|
|
5692
3952
|
function useSpectrogramIntegration() {
|
|
5693
|
-
const context = (0,
|
|
3953
|
+
const context = (0, import_react25.useContext)(SpectrogramIntegrationContext);
|
|
5694
3954
|
if (!context) {
|
|
5695
3955
|
throw new Error(
|
|
5696
3956
|
"useSpectrogramIntegration must be used within <SpectrogramProvider>. Install @waveform-playlist/spectrogram and wrap your app with <SpectrogramProvider>."
|
|
@@ -5700,7 +3960,7 @@ function useSpectrogramIntegration() {
|
|
|
5700
3960
|
}
|
|
5701
3961
|
|
|
5702
3962
|
// src/components/PlaylistVisualization.tsx
|
|
5703
|
-
var
|
|
3963
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
5704
3964
|
var DEFAULT_EMPTY_TRACK_DURATION = 60;
|
|
5705
3965
|
var ControlSlot = import_styled_components6.default.div.attrs((props) => ({
|
|
5706
3966
|
style: { height: `${props.$height}px` }
|
|
@@ -5719,7 +3979,8 @@ var CustomPlayhead = ({ renderPlayhead, color, samplesPerPixel, sampleRate }) =>
|
|
|
5719
3979
|
visualTimeRef,
|
|
5720
3980
|
playbackStartTimeRef,
|
|
5721
3981
|
audioStartPositionRef,
|
|
5722
|
-
getPlaybackTime
|
|
3982
|
+
getPlaybackTime,
|
|
3983
|
+
getAudioContextTime
|
|
5723
3984
|
} = usePlaybackAnimation();
|
|
5724
3985
|
const visualTime = (_b = (_a = visualTimeRef.current) != null ? _a : currentTimeRef.current) != null ? _b : 0;
|
|
5725
3986
|
return renderPlayhead({
|
|
@@ -5733,7 +3994,7 @@ var CustomPlayhead = ({ renderPlayhead, color, samplesPerPixel, sampleRate }) =>
|
|
|
5733
3994
|
samplesPerPixel,
|
|
5734
3995
|
sampleRate,
|
|
5735
3996
|
controlsOffset: 0,
|
|
5736
|
-
getAudioContextTime
|
|
3997
|
+
getAudioContextTime,
|
|
5737
3998
|
getPlaybackTime
|
|
5738
3999
|
});
|
|
5739
4000
|
};
|
|
@@ -5757,8 +4018,8 @@ var PlaylistVisualization = ({
|
|
|
5757
4018
|
recordingState
|
|
5758
4019
|
}) => {
|
|
5759
4020
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
5760
|
-
const theme = (0,
|
|
5761
|
-
const { isPlaying, getLookAhead } = usePlaybackAnimation();
|
|
4021
|
+
const theme = (0, import_ui_components8.useTheme)();
|
|
4022
|
+
const { isPlaying, getLookAhead, getOutputLatency } = usePlaybackAnimation();
|
|
5762
4023
|
const {
|
|
5763
4024
|
selectionStart,
|
|
5764
4025
|
selectionEnd,
|
|
@@ -5773,7 +4034,7 @@ var PlaylistVisualization = ({
|
|
|
5773
4034
|
isLoopEnabled,
|
|
5774
4035
|
indefinitePlayback
|
|
5775
4036
|
} = usePlaylistState();
|
|
5776
|
-
const annotationIntegration = (0,
|
|
4037
|
+
const annotationIntegration = (0, import_react26.useContext)(AnnotationIntegrationContext);
|
|
5777
4038
|
const {
|
|
5778
4039
|
setAnnotations: _setAnnotations,
|
|
5779
4040
|
setActiveAnnotationId,
|
|
@@ -5803,8 +4064,8 @@ var PlaylistVisualization = ({
|
|
|
5803
4064
|
isReady,
|
|
5804
4065
|
mono
|
|
5805
4066
|
} = usePlaylistData();
|
|
5806
|
-
const spectrogram = (0,
|
|
5807
|
-
const perTrackSpectrogramHelpers = (0,
|
|
4067
|
+
const spectrogram = (0, import_react26.useContext)(SpectrogramIntegrationContext);
|
|
4068
|
+
const perTrackSpectrogramHelpers = (0, import_react26.useMemo)(() => {
|
|
5808
4069
|
if (!spectrogram)
|
|
5809
4070
|
return /* @__PURE__ */ new Map();
|
|
5810
4071
|
const helpers = /* @__PURE__ */ new Map();
|
|
@@ -5823,11 +4084,11 @@ var PlaylistVisualization = ({
|
|
|
5823
4084
|
});
|
|
5824
4085
|
return helpers;
|
|
5825
4086
|
}, [tracks, spectrogram]);
|
|
5826
|
-
const [settingsModalTrackId, setSettingsModalTrackId] = (0,
|
|
5827
|
-
const [isSelecting, setIsSelecting] = (0,
|
|
5828
|
-
const mouseDownTimeRef = (0,
|
|
5829
|
-
const scrollContainerRef = (0,
|
|
5830
|
-
const handleScrollContainerRef = (0,
|
|
4087
|
+
const [settingsModalTrackId, setSettingsModalTrackId] = (0, import_react26.useState)(null);
|
|
4088
|
+
const [isSelecting, setIsSelecting] = (0, import_react26.useState)(false);
|
|
4089
|
+
const mouseDownTimeRef = (0, import_react26.useRef)(0);
|
|
4090
|
+
const scrollContainerRef = (0, import_react26.useRef)(null);
|
|
4091
|
+
const handleScrollContainerRef = (0, import_react26.useCallback)(
|
|
5831
4092
|
(element) => {
|
|
5832
4093
|
scrollContainerRef.current = element;
|
|
5833
4094
|
setScrollContainer(element);
|
|
@@ -5865,7 +4126,7 @@ var PlaylistVisualization = ({
|
|
|
5865
4126
|
);
|
|
5866
4127
|
}
|
|
5867
4128
|
});
|
|
5868
|
-
const selectTrack = (0,
|
|
4129
|
+
const selectTrack = (0, import_react26.useCallback)(
|
|
5869
4130
|
(trackIndex) => {
|
|
5870
4131
|
if (trackIndex >= 0 && trackIndex < tracks.length) {
|
|
5871
4132
|
const track = tracks[trackIndex];
|
|
@@ -5935,7 +4196,7 @@ var PlaylistVisualization = ({
|
|
|
5935
4196
|
};
|
|
5936
4197
|
const hasClips = tracks.some((track) => track.clips.length > 0);
|
|
5937
4198
|
if (hasClips && peaksDataArray.length === 0) {
|
|
5938
|
-
return /* @__PURE__ */ (0,
|
|
4199
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className, children: "Loading waveform..." });
|
|
5939
4200
|
}
|
|
5940
4201
|
const trackControlsSlots = controls.show ? peaksDataArray.map((trackClipPeaks, trackIndex) => {
|
|
5941
4202
|
var _a2, _b2, _c2;
|
|
@@ -5951,11 +4212,11 @@ var PlaylistVisualization = ({
|
|
|
5951
4212
|
const hasMidiNotes = track.clips.some((c) => c.midiNotes && c.midiNotes.length > 0);
|
|
5952
4213
|
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";
|
|
5953
4214
|
const maxChannels = getTrackChannelCount(trackClipPeaks, recordingState, track.id, mono);
|
|
5954
|
-
const slotHeight = waveHeight * maxChannels + (showClipHeaders ?
|
|
5955
|
-
const trackControlContent = renderTrackControls ? renderTrackControls(trackIndex) : /* @__PURE__ */ (0,
|
|
5956
|
-
/* @__PURE__ */ (0,
|
|
5957
|
-
onRemoveTrack && /* @__PURE__ */ (0,
|
|
5958
|
-
|
|
4215
|
+
const slotHeight = waveHeight * maxChannels + (showClipHeaders ? import_ui_components8.CLIP_HEADER_HEIGHT : 0);
|
|
4216
|
+
const trackControlContent = renderTrackControls ? renderTrackControls(trackIndex) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ui_components8.Controls, { onClick: () => selectTrack(trackIndex), children: [
|
|
4217
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ui_components8.Header, { style: { justifyContent: "center", position: "relative" }, children: [
|
|
4218
|
+
onRemoveTrack && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4219
|
+
import_ui_components8.CloseButton,
|
|
5959
4220
|
{
|
|
5960
4221
|
onClick: (e) => {
|
|
5961
4222
|
e.stopPropagation();
|
|
@@ -5963,7 +4224,7 @@ var PlaylistVisualization = ({
|
|
|
5963
4224
|
}
|
|
5964
4225
|
}
|
|
5965
4226
|
),
|
|
5966
|
-
/* @__PURE__ */ (0,
|
|
4227
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
5967
4228
|
"span",
|
|
5968
4229
|
{
|
|
5969
4230
|
style: {
|
|
@@ -5976,8 +4237,8 @@ var PlaylistVisualization = ({
|
|
|
5976
4237
|
children: trackState.name || `Track ${trackIndex + 1}`
|
|
5977
4238
|
}
|
|
5978
4239
|
),
|
|
5979
|
-
(spectrogram == null ? void 0 : spectrogram.renderMenuItems) && /* @__PURE__ */ (0,
|
|
5980
|
-
|
|
4240
|
+
(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)(
|
|
4241
|
+
import_ui_components8.TrackMenu,
|
|
5981
4242
|
{
|
|
5982
4243
|
items: (onClose) => spectrogram.renderMenuItems({
|
|
5983
4244
|
renderMode: effectiveRenderMode,
|
|
@@ -5988,17 +4249,17 @@ var PlaylistVisualization = ({
|
|
|
5988
4249
|
}
|
|
5989
4250
|
) })
|
|
5990
4251
|
] }),
|
|
5991
|
-
/* @__PURE__ */ (0,
|
|
5992
|
-
/* @__PURE__ */ (0,
|
|
5993
|
-
|
|
4252
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ui_components8.ButtonGroup, { children: [
|
|
4253
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4254
|
+
import_ui_components8.Button,
|
|
5994
4255
|
{
|
|
5995
4256
|
$variant: trackState.muted ? "danger" : "outline",
|
|
5996
4257
|
onClick: () => setTrackMute(trackIndex, !trackState.muted),
|
|
5997
4258
|
children: "Mute"
|
|
5998
4259
|
}
|
|
5999
4260
|
),
|
|
6000
|
-
/* @__PURE__ */ (0,
|
|
6001
|
-
|
|
4261
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4262
|
+
import_ui_components8.Button,
|
|
6002
4263
|
{
|
|
6003
4264
|
$variant: trackState.soloed ? "info" : "outline",
|
|
6004
4265
|
onClick: () => setTrackSolo(trackIndex, !trackState.soloed),
|
|
@@ -6006,10 +4267,10 @@ var PlaylistVisualization = ({
|
|
|
6006
4267
|
}
|
|
6007
4268
|
)
|
|
6008
4269
|
] }),
|
|
6009
|
-
/* @__PURE__ */ (0,
|
|
6010
|
-
/* @__PURE__ */ (0,
|
|
6011
|
-
/* @__PURE__ */ (0,
|
|
6012
|
-
|
|
4270
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ui_components8.SliderWrapper, { children: [
|
|
4271
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ui_components8.VolumeDownIcon, {}),
|
|
4272
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4273
|
+
import_ui_components8.Slider,
|
|
6013
4274
|
{
|
|
6014
4275
|
min: "0",
|
|
6015
4276
|
max: "1",
|
|
@@ -6018,12 +4279,12 @@ var PlaylistVisualization = ({
|
|
|
6018
4279
|
onChange: (e) => setTrackVolume(trackIndex, parseFloat(e.target.value))
|
|
6019
4280
|
}
|
|
6020
4281
|
),
|
|
6021
|
-
/* @__PURE__ */ (0,
|
|
4282
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ui_components8.VolumeUpIcon, {})
|
|
6022
4283
|
] }),
|
|
6023
|
-
/* @__PURE__ */ (0,
|
|
6024
|
-
/* @__PURE__ */ (0,
|
|
6025
|
-
/* @__PURE__ */ (0,
|
|
6026
|
-
|
|
4284
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ui_components8.SliderWrapper, { children: [
|
|
4285
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "L" }),
|
|
4286
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4287
|
+
import_ui_components8.Slider,
|
|
6027
4288
|
{
|
|
6028
4289
|
min: "-1",
|
|
6029
4290
|
max: "1",
|
|
@@ -6032,10 +4293,10 @@ var PlaylistVisualization = ({
|
|
|
6032
4293
|
onChange: (e) => setTrackPan(trackIndex, parseFloat(e.target.value))
|
|
6033
4294
|
}
|
|
6034
4295
|
),
|
|
6035
|
-
/* @__PURE__ */ (0,
|
|
4296
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "R" })
|
|
6036
4297
|
] })
|
|
6037
4298
|
] });
|
|
6038
|
-
return /* @__PURE__ */ (0,
|
|
4299
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6039
4300
|
ControlSlot,
|
|
6040
4301
|
{
|
|
6041
4302
|
$height: slotHeight,
|
|
@@ -6045,9 +4306,9 @@ var PlaylistVisualization = ({
|
|
|
6045
4306
|
track.id
|
|
6046
4307
|
);
|
|
6047
4308
|
}) : void 0;
|
|
6048
|
-
return /* @__PURE__ */ (0,
|
|
6049
|
-
/* @__PURE__ */ (0,
|
|
6050
|
-
|
|
4309
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_ui_components8.DevicePixelRatioProvider, { children: [
|
|
4310
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4311
|
+
import_ui_components8.PlaylistInfoContext.Provider,
|
|
6051
4312
|
{
|
|
6052
4313
|
value: {
|
|
6053
4314
|
samplesPerPixel,
|
|
@@ -6060,11 +4321,11 @@ var PlaylistVisualization = ({
|
|
|
6060
4321
|
barWidth,
|
|
6061
4322
|
barGap
|
|
6062
4323
|
},
|
|
6063
|
-
children: /* @__PURE__ */ (0,
|
|
6064
|
-
|
|
4324
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4325
|
+
import_ui_components8.Playlist,
|
|
6065
4326
|
{
|
|
6066
4327
|
theme,
|
|
6067
|
-
backgroundColor: theme.playlistBackgroundColor || (0,
|
|
4328
|
+
backgroundColor: theme.playlistBackgroundColor || (0, import_ui_components8.waveformColorToCss)(theme.waveOutlineColor),
|
|
6068
4329
|
timescaleBackgroundColor: theme.timescaleBackgroundColor,
|
|
6069
4330
|
timescaleWidth: tracksFullWidth,
|
|
6070
4331
|
tracksWidth: tracksFullWidth,
|
|
@@ -6077,10 +4338,10 @@ var PlaylistVisualization = ({
|
|
|
6077
4338
|
"data-playlist-state": isReady ? "ready" : "loading",
|
|
6078
4339
|
trackControlsSlots,
|
|
6079
4340
|
timescaleGapHeight: timeScaleHeight > 0 ? timeScaleHeight + 1 : 0,
|
|
6080
|
-
timescale: timeScaleHeight > 0 ? /* @__PURE__ */ (0,
|
|
6081
|
-
/* @__PURE__ */ (0,
|
|
6082
|
-
isLoopEnabled && /* @__PURE__ */ (0,
|
|
6083
|
-
|
|
4341
|
+
timescale: timeScaleHeight > 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
4342
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ui_components8.SmartScale, { renderTick }),
|
|
4343
|
+
isLoopEnabled && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4344
|
+
import_ui_components8.TimescaleLoopRegion,
|
|
6084
4345
|
{
|
|
6085
4346
|
startPosition: Math.min(loopStart, loopEnd) * sampleRate / samplesPerPixel,
|
|
6086
4347
|
endPosition: Math.max(loopStart, loopEnd) * sampleRate / samplesPerPixel,
|
|
@@ -6096,7 +4357,7 @@ var PlaylistVisualization = ({
|
|
|
6096
4357
|
}
|
|
6097
4358
|
)
|
|
6098
4359
|
] }) : void 0,
|
|
6099
|
-
children: /* @__PURE__ */ (0,
|
|
4360
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
6100
4361
|
peaksDataArray.map((trackClipPeaks, trackIndex) => {
|
|
6101
4362
|
var _a2, _b2, _c2, _d2;
|
|
6102
4363
|
const track = tracks[trackIndex];
|
|
@@ -6109,11 +4370,11 @@ var PlaylistVisualization = ({
|
|
|
6109
4370
|
track.id,
|
|
6110
4371
|
mono
|
|
6111
4372
|
);
|
|
6112
|
-
return /* @__PURE__ */ (0,
|
|
6113
|
-
|
|
4373
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
4374
|
+
import_ui_components8.Track,
|
|
6114
4375
|
{
|
|
6115
4376
|
numChannels: maxChannels,
|
|
6116
|
-
backgroundColor: effectiveRenderMode === "piano-roll" ? theme.pianoRollBackgroundColor || "#1a1a2e" : (0,
|
|
4377
|
+
backgroundColor: effectiveRenderMode === "piano-roll" ? theme.pianoRollBackgroundColor || "#1a1a2e" : (0, import_ui_components8.waveformColorToCss)(theme.waveOutlineColor),
|
|
6117
4378
|
offset: 0,
|
|
6118
4379
|
width: tracksFullWidth,
|
|
6119
4380
|
hasClipHeaders: showClipHeaders,
|
|
@@ -6125,8 +4386,8 @@ var PlaylistVisualization = ({
|
|
|
6125
4386
|
const helpers = perTrackSpectrogramHelpers.get(track.id);
|
|
6126
4387
|
const trackCfg = helpers == null ? void 0 : helpers.config;
|
|
6127
4388
|
if (!(trackCfg == null ? void 0 : trackCfg.labels) || !helpers) return null;
|
|
6128
|
-
return /* @__PURE__ */ (0,
|
|
6129
|
-
|
|
4389
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4390
|
+
import_ui_components8.SpectrogramLabels,
|
|
6130
4391
|
{
|
|
6131
4392
|
waveHeight,
|
|
6132
4393
|
numChannels: maxChannels,
|
|
@@ -6143,8 +4404,8 @@ var PlaylistVisualization = ({
|
|
|
6143
4404
|
trackClipPeaks.map((clip, clipIndex) => {
|
|
6144
4405
|
const peaksData = clip.peaks;
|
|
6145
4406
|
const width = peaksData.length;
|
|
6146
|
-
return /* @__PURE__ */ (0,
|
|
6147
|
-
|
|
4407
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4408
|
+
import_ui_components8.Clip,
|
|
6148
4409
|
{
|
|
6149
4410
|
clipId: clip.clipId,
|
|
6150
4411
|
trackIndex,
|
|
@@ -6173,7 +4434,7 @@ var PlaylistVisualization = ({
|
|
|
6173
4434
|
selectTrack(trackIndex);
|
|
6174
4435
|
},
|
|
6175
4436
|
children: peaksData.data.map((channelPeaks, channelIndex) => {
|
|
6176
|
-
return /* @__PURE__ */ (0,
|
|
4437
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6177
4438
|
ChannelWithProgress,
|
|
6178
4439
|
{
|
|
6179
4440
|
index: channelIndex,
|
|
@@ -6200,10 +4461,9 @@ var PlaylistVisualization = ({
|
|
|
6200
4461
|
);
|
|
6201
4462
|
}),
|
|
6202
4463
|
(recordingState == null ? void 0 : recordingState.isRecording) && recordingState.trackId === track.id && ((_d2 = recordingState.peaks[0]) == null ? void 0 : _d2.length) > 0 && (() => {
|
|
6203
|
-
const
|
|
6204
|
-
const outputLatency = "outputLatency" in audioCtx ? audioCtx.outputLatency : 0;
|
|
4464
|
+
const outputLatency = getOutputLatency();
|
|
6205
4465
|
const lookAhead = getLookAhead();
|
|
6206
|
-
const latencyOffsetSamples = (0,
|
|
4466
|
+
const latencyOffsetSamples = (0, import_core4.audibleLatencySamples)(
|
|
6207
4467
|
outputLatency,
|
|
6208
4468
|
lookAhead,
|
|
6209
4469
|
sampleRate
|
|
@@ -6217,8 +4477,8 @@ var PlaylistVisualization = ({
|
|
|
6217
4477
|
const previewChannels = (mono ? recordingState.peaks.slice(0, 1) : recordingState.peaks).map(
|
|
6218
4478
|
(channelPeaks) => skipPeakElements > 0 && skipPeakElements < channelPeaks.length ? channelPeaks.subarray(skipPeakElements) : channelPeaks
|
|
6219
4479
|
);
|
|
6220
|
-
return /* @__PURE__ */ (0,
|
|
6221
|
-
|
|
4480
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4481
|
+
import_ui_components8.Clip,
|
|
6222
4482
|
{
|
|
6223
4483
|
clipId: "recording-preview",
|
|
6224
4484
|
trackIndex,
|
|
@@ -6231,7 +4491,7 @@ var PlaylistVisualization = ({
|
|
|
6231
4491
|
disableHeaderDrag: true,
|
|
6232
4492
|
isSelected: track.id === selectedTrackId,
|
|
6233
4493
|
trackId: track.id,
|
|
6234
|
-
children: previewChannels.map((channelPeaks, chIdx) => /* @__PURE__ */ (0,
|
|
4494
|
+
children: previewChannels.map((channelPeaks, chIdx) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6235
4495
|
ChannelWithProgress,
|
|
6236
4496
|
{
|
|
6237
4497
|
index: chIdx,
|
|
@@ -6253,11 +4513,11 @@ var PlaylistVisualization = ({
|
|
|
6253
4513
|
track.id
|
|
6254
4514
|
);
|
|
6255
4515
|
}),
|
|
6256
|
-
annotations.length > 0 && annotationIntegration && /* @__PURE__ */ (0,
|
|
4516
|
+
annotations.length > 0 && annotationIntegration && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(annotationIntegration.AnnotationBoxesWrapper, { height: 30, width: tracksFullWidth, children: annotations.map((annotation, index) => {
|
|
6257
4517
|
const startPosition = annotation.start * sampleRate / samplesPerPixel;
|
|
6258
4518
|
const endPosition = annotation.end * sampleRate / samplesPerPixel;
|
|
6259
4519
|
const label = getAnnotationBoxLabel ? getAnnotationBoxLabel(annotation, index) : annotation.id;
|
|
6260
|
-
return /* @__PURE__ */ (0,
|
|
4520
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6261
4521
|
annotationIntegration.AnnotationBox,
|
|
6262
4522
|
{
|
|
6263
4523
|
annotationId: annotation.id,
|
|
@@ -6273,15 +4533,15 @@ var PlaylistVisualization = ({
|
|
|
6273
4533
|
annotation.id
|
|
6274
4534
|
);
|
|
6275
4535
|
}) }),
|
|
6276
|
-
selectionStart !== selectionEnd && /* @__PURE__ */ (0,
|
|
6277
|
-
|
|
4536
|
+
selectionStart !== selectionEnd && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4537
|
+
import_ui_components8.Selection,
|
|
6278
4538
|
{
|
|
6279
4539
|
startPosition: Math.min(selectionStart, selectionEnd) * sampleRate / samplesPerPixel,
|
|
6280
4540
|
endPosition: Math.max(selectionStart, selectionEnd) * sampleRate / samplesPerPixel,
|
|
6281
4541
|
color: theme.selectionColor
|
|
6282
4542
|
}
|
|
6283
4543
|
),
|
|
6284
|
-
(isPlaying || selectionStart === selectionEnd) && (renderPlayhead ? /* @__PURE__ */ (0,
|
|
4544
|
+
(isPlaying || selectionStart === selectionEnd) && (renderPlayhead ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6285
4545
|
CustomPlayhead,
|
|
6286
4546
|
{
|
|
6287
4547
|
renderPlayhead,
|
|
@@ -6289,14 +4549,14 @@ var PlaylistVisualization = ({
|
|
|
6289
4549
|
samplesPerPixel,
|
|
6290
4550
|
sampleRate
|
|
6291
4551
|
}
|
|
6292
|
-
) : /* @__PURE__ */ (0,
|
|
4552
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AnimatedPlayhead, { color: theme.playheadColor }))
|
|
6293
4553
|
] })
|
|
6294
4554
|
}
|
|
6295
4555
|
)
|
|
6296
4556
|
}
|
|
6297
4557
|
),
|
|
6298
4558
|
(spectrogram == null ? void 0 : spectrogram.SettingsModal) && typeof document !== "undefined" && (0, import_react_dom.createPortal)(
|
|
6299
|
-
/* @__PURE__ */ (0,
|
|
4559
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
6300
4560
|
spectrogram.SettingsModal,
|
|
6301
4561
|
{
|
|
6302
4562
|
open: settingsModalTrackId !== null,
|
|
@@ -6316,8 +4576,8 @@ var PlaylistVisualization = ({
|
|
|
6316
4576
|
};
|
|
6317
4577
|
|
|
6318
4578
|
// src/components/PlaylistAnnotationList.tsx
|
|
6319
|
-
var
|
|
6320
|
-
var
|
|
4579
|
+
var import_react27 = require("react");
|
|
4580
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
6321
4581
|
var PlaylistAnnotationList = ({
|
|
6322
4582
|
height,
|
|
6323
4583
|
renderAnnotationItem,
|
|
@@ -6331,7 +4591,7 @@ var PlaylistAnnotationList = ({
|
|
|
6331
4591
|
const integration = useAnnotationIntegration();
|
|
6332
4592
|
const { setAnnotations } = usePlaylistControls();
|
|
6333
4593
|
const resolvedConfig = annotationListConfig != null ? annotationListConfig : { linkEndpoints, continuousPlay };
|
|
6334
|
-
const handleAnnotationUpdate = (0,
|
|
4594
|
+
const handleAnnotationUpdate = (0, import_react27.useCallback)(
|
|
6335
4595
|
(updatedAnnotations) => {
|
|
6336
4596
|
setAnnotations(updatedAnnotations);
|
|
6337
4597
|
onAnnotationUpdate == null ? void 0 : onAnnotationUpdate(updatedAnnotations);
|
|
@@ -6339,7 +4599,7 @@ var PlaylistAnnotationList = ({
|
|
|
6339
4599
|
[setAnnotations, onAnnotationUpdate]
|
|
6340
4600
|
);
|
|
6341
4601
|
const { AnnotationText } = integration;
|
|
6342
|
-
return /* @__PURE__ */ (0,
|
|
4602
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
6343
4603
|
AnnotationText,
|
|
6344
4604
|
{
|
|
6345
4605
|
annotations,
|
|
@@ -6358,7 +4618,7 @@ var PlaylistAnnotationList = ({
|
|
|
6358
4618
|
};
|
|
6359
4619
|
|
|
6360
4620
|
// src/components/Waveform.tsx
|
|
6361
|
-
var
|
|
4621
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
6362
4622
|
var Waveform = ({
|
|
6363
4623
|
renderTrackControls,
|
|
6364
4624
|
renderTick,
|
|
@@ -6382,8 +4642,8 @@ var Waveform = ({
|
|
|
6382
4642
|
const { annotations } = usePlaylistState();
|
|
6383
4643
|
const clipInteractionEnabled = useClipInteractionEnabled();
|
|
6384
4644
|
const effectiveInteractiveClips = interactiveClips || clipInteractionEnabled;
|
|
6385
|
-
return /* @__PURE__ */ (0,
|
|
6386
|
-
/* @__PURE__ */ (0,
|
|
4645
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
4646
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
6387
4647
|
PlaylistVisualization,
|
|
6388
4648
|
{
|
|
6389
4649
|
renderTrackControls,
|
|
@@ -6400,7 +4660,7 @@ var Waveform = ({
|
|
|
6400
4660
|
recordingState
|
|
6401
4661
|
}
|
|
6402
4662
|
),
|
|
6403
|
-
annotations.length > 0 && /* @__PURE__ */ (0,
|
|
4663
|
+
annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
6404
4664
|
PlaylistAnnotationList,
|
|
6405
4665
|
{
|
|
6406
4666
|
height: annotationTextHeight,
|
|
@@ -6415,10 +4675,10 @@ var Waveform = ({
|
|
|
6415
4675
|
};
|
|
6416
4676
|
|
|
6417
4677
|
// src/components/MediaElementPlaylist.tsx
|
|
6418
|
-
var
|
|
6419
|
-
var
|
|
4678
|
+
var import_react30 = require("react");
|
|
4679
|
+
var import_react31 = require("@dnd-kit/react");
|
|
6420
4680
|
var import_modifiers = require("@dnd-kit/abstract/modifiers");
|
|
6421
|
-
var
|
|
4681
|
+
var import_ui_components10 = require("@waveform-playlist/ui-components");
|
|
6422
4682
|
|
|
6423
4683
|
// src/plugins/noDropAnimationPlugins.ts
|
|
6424
4684
|
var import_dom2 = require("@dnd-kit/dom");
|
|
@@ -6440,9 +4700,9 @@ var noDropAnimationPlugins = (defaults) => {
|
|
|
6440
4700
|
};
|
|
6441
4701
|
|
|
6442
4702
|
// src/components/AnimatedMediaElementPlayhead.tsx
|
|
6443
|
-
var
|
|
4703
|
+
var import_react28 = require("react");
|
|
6444
4704
|
var import_styled_components7 = __toESM(require("styled-components"));
|
|
6445
|
-
var
|
|
4705
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
6446
4706
|
var PlayheadLine2 = import_styled_components7.default.div`
|
|
6447
4707
|
position: absolute;
|
|
6448
4708
|
top: 0;
|
|
@@ -6457,11 +4717,11 @@ var PlayheadLine2 = import_styled_components7.default.div`
|
|
|
6457
4717
|
var AnimatedMediaElementPlayhead = ({
|
|
6458
4718
|
color = "#ff0000"
|
|
6459
4719
|
}) => {
|
|
6460
|
-
const playheadRef = (0,
|
|
6461
|
-
const animationFrameRef = (0,
|
|
4720
|
+
const playheadRef = (0, import_react28.useRef)(null);
|
|
4721
|
+
const animationFrameRef = (0, import_react28.useRef)(null);
|
|
6462
4722
|
const { isPlaying, currentTimeRef } = useMediaElementAnimation();
|
|
6463
4723
|
const { samplesPerPixel, sampleRate, progressBarWidth } = useMediaElementData();
|
|
6464
|
-
(0,
|
|
4724
|
+
(0, import_react28.useEffect)(() => {
|
|
6465
4725
|
const updatePosition = () => {
|
|
6466
4726
|
var _a;
|
|
6467
4727
|
if (playheadRef.current) {
|
|
@@ -6485,7 +4745,7 @@ var AnimatedMediaElementPlayhead = ({
|
|
|
6485
4745
|
}
|
|
6486
4746
|
};
|
|
6487
4747
|
}, [isPlaying, sampleRate, samplesPerPixel, currentTimeRef]);
|
|
6488
|
-
(0,
|
|
4748
|
+
(0, import_react28.useEffect)(() => {
|
|
6489
4749
|
var _a;
|
|
6490
4750
|
if (!isPlaying && playheadRef.current) {
|
|
6491
4751
|
const time = (_a = currentTimeRef.current) != null ? _a : 0;
|
|
@@ -6493,14 +4753,14 @@ var AnimatedMediaElementPlayhead = ({
|
|
|
6493
4753
|
playheadRef.current.style.transform = `translate3d(${position}px, 0, 0)`;
|
|
6494
4754
|
}
|
|
6495
4755
|
});
|
|
6496
|
-
return /* @__PURE__ */ (0,
|
|
4756
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PlayheadLine2, { ref: playheadRef, $color: color, $width: progressBarWidth, "data-playhead": true });
|
|
6497
4757
|
};
|
|
6498
4758
|
|
|
6499
4759
|
// src/components/ChannelWithMediaElementProgress.tsx
|
|
6500
|
-
var
|
|
4760
|
+
var import_react29 = require("react");
|
|
6501
4761
|
var import_styled_components8 = __toESM(require("styled-components"));
|
|
6502
|
-
var
|
|
6503
|
-
var
|
|
4762
|
+
var import_ui_components9 = require("@waveform-playlist/ui-components");
|
|
4763
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
6504
4764
|
var ChannelWrapper2 = import_styled_components8.default.div`
|
|
6505
4765
|
position: relative;
|
|
6506
4766
|
`;
|
|
@@ -6537,14 +4797,14 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6537
4797
|
"clipStartSample",
|
|
6538
4798
|
"clipDurationSamples"
|
|
6539
4799
|
]);
|
|
6540
|
-
const progressRef = (0,
|
|
6541
|
-
const animationFrameRef = (0,
|
|
6542
|
-
const theme = (0,
|
|
6543
|
-
const { waveHeight } = (0,
|
|
4800
|
+
const progressRef = (0, import_react29.useRef)(null);
|
|
4801
|
+
const animationFrameRef = (0, import_react29.useRef)(null);
|
|
4802
|
+
const theme = (0, import_ui_components9.useTheme)();
|
|
4803
|
+
const { waveHeight } = (0, import_ui_components9.usePlaylistInfo)();
|
|
6544
4804
|
const { isPlaying, currentTimeRef } = useMediaElementAnimation();
|
|
6545
4805
|
const { samplesPerPixel, sampleRate } = useMediaElementData();
|
|
6546
4806
|
const progressColor = (theme == null ? void 0 : theme.waveProgressColor) || "rgba(0, 0, 0, 0.1)";
|
|
6547
|
-
(0,
|
|
4807
|
+
(0, import_react29.useEffect)(() => {
|
|
6548
4808
|
const updateProgress = () => {
|
|
6549
4809
|
var _a2;
|
|
6550
4810
|
if (progressRef.current) {
|
|
@@ -6586,7 +4846,7 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6586
4846
|
smartChannelProps.length,
|
|
6587
4847
|
currentTimeRef
|
|
6588
4848
|
]);
|
|
6589
|
-
(0,
|
|
4849
|
+
(0, import_react29.useEffect)(() => {
|
|
6590
4850
|
var _a2;
|
|
6591
4851
|
if (!isPlaying && progressRef.current) {
|
|
6592
4852
|
const currentTime = (_a2 = currentTimeRef.current) != null ? _a2 : 0;
|
|
@@ -6611,9 +4871,9 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6611
4871
|
} else {
|
|
6612
4872
|
backgroundColor = (theme == null ? void 0 : theme.selectedWaveOutlineColor) || (theme == null ? void 0 : theme.waveOutlineColor) || "grey";
|
|
6613
4873
|
}
|
|
6614
|
-
const backgroundCss = (0,
|
|
6615
|
-
return /* @__PURE__ */ (0,
|
|
6616
|
-
/* @__PURE__ */ (0,
|
|
4874
|
+
const backgroundCss = (0, import_ui_components9.waveformColorToCss)(backgroundColor);
|
|
4875
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(ChannelWrapper2, { children: [
|
|
4876
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
6617
4877
|
Background2,
|
|
6618
4878
|
{
|
|
6619
4879
|
$color: backgroundCss,
|
|
@@ -6622,7 +4882,7 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6622
4882
|
$width: smartChannelProps.length
|
|
6623
4883
|
}
|
|
6624
4884
|
),
|
|
6625
|
-
/* @__PURE__ */ (0,
|
|
4885
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
6626
4886
|
ProgressOverlay2,
|
|
6627
4887
|
{
|
|
6628
4888
|
ref: progressRef,
|
|
@@ -6631,12 +4891,12 @@ var ChannelWithMediaElementProgress = (_a) => {
|
|
|
6631
4891
|
$top: smartChannelProps.index * waveHeight
|
|
6632
4892
|
}
|
|
6633
4893
|
),
|
|
6634
|
-
/* @__PURE__ */ (0,
|
|
4894
|
+
/* @__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 })) })
|
|
6635
4895
|
] });
|
|
6636
4896
|
};
|
|
6637
4897
|
|
|
6638
4898
|
// src/components/MediaElementPlaylist.tsx
|
|
6639
|
-
var
|
|
4899
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
6640
4900
|
var ZERO_REF = { current: 0 };
|
|
6641
4901
|
var CustomMediaElementPlayhead = ({ renderPlayhead, color, samplesPerPixel, sampleRate }) => {
|
|
6642
4902
|
var _a;
|
|
@@ -6662,10 +4922,10 @@ var MediaElementPlaylist = ({
|
|
|
6662
4922
|
showFades = false,
|
|
6663
4923
|
className
|
|
6664
4924
|
}) => {
|
|
6665
|
-
const theme = (0,
|
|
4925
|
+
const theme = (0, import_ui_components10.useTheme)();
|
|
6666
4926
|
const { isPlaying } = useMediaElementAnimation();
|
|
6667
4927
|
const { annotations, activeAnnotationId } = useMediaElementState();
|
|
6668
|
-
const annotationIntegration = (0,
|
|
4928
|
+
const annotationIntegration = (0, import_react30.useContext)(AnnotationIntegrationContext);
|
|
6669
4929
|
const { play, seekTo, setActiveAnnotationId, setAnnotations, setScrollContainer } = useMediaElementControls();
|
|
6670
4930
|
const {
|
|
6671
4931
|
duration,
|
|
@@ -6681,11 +4941,11 @@ var MediaElementPlaylist = ({
|
|
|
6681
4941
|
fadeIn,
|
|
6682
4942
|
fadeOut
|
|
6683
4943
|
} = useMediaElementData();
|
|
6684
|
-
const [selectionStart, setSelectionStart] = (0,
|
|
6685
|
-
const [selectionEnd, setSelectionEnd] = (0,
|
|
6686
|
-
const [isSelecting, setIsSelecting] = (0,
|
|
6687
|
-
const scrollContainerRef = (0,
|
|
6688
|
-
const handleScrollContainerRef = (0,
|
|
4944
|
+
const [selectionStart, setSelectionStart] = (0, import_react30.useState)(0);
|
|
4945
|
+
const [selectionEnd, setSelectionEnd] = (0, import_react30.useState)(0);
|
|
4946
|
+
const [isSelecting, setIsSelecting] = (0, import_react30.useState)(false);
|
|
4947
|
+
const scrollContainerRef = (0, import_react30.useRef)(null);
|
|
4948
|
+
const handleScrollContainerRef = (0, import_react30.useCallback)(
|
|
6689
4949
|
(el) => {
|
|
6690
4950
|
scrollContainerRef.current = el;
|
|
6691
4951
|
setScrollContainer(el);
|
|
@@ -6693,7 +4953,7 @@ var MediaElementPlaylist = ({
|
|
|
6693
4953
|
[setScrollContainer]
|
|
6694
4954
|
);
|
|
6695
4955
|
const tracksFullWidth = Math.floor(duration * sampleRate / samplesPerPixel);
|
|
6696
|
-
const handleAnnotationClick = (0,
|
|
4956
|
+
const handleAnnotationClick = (0, import_react30.useCallback)(
|
|
6697
4957
|
(annotation) => __async(null, null, function* () {
|
|
6698
4958
|
setActiveAnnotationId(annotation.id);
|
|
6699
4959
|
try {
|
|
@@ -6708,7 +4968,7 @@ var MediaElementPlaylist = ({
|
|
|
6708
4968
|
}),
|
|
6709
4969
|
[setActiveAnnotationId, play]
|
|
6710
4970
|
);
|
|
6711
|
-
const handleAnnotationUpdate = (0,
|
|
4971
|
+
const handleAnnotationUpdate = (0, import_react30.useCallback)(
|
|
6712
4972
|
(updatedAnnotations) => {
|
|
6713
4973
|
setAnnotations(updatedAnnotations);
|
|
6714
4974
|
onAnnotationUpdate == null ? void 0 : onAnnotationUpdate(updatedAnnotations);
|
|
@@ -6722,8 +4982,8 @@ var MediaElementPlaylist = ({
|
|
|
6722
4982
|
duration,
|
|
6723
4983
|
linkEndpoints: linkEndpointsProp
|
|
6724
4984
|
});
|
|
6725
|
-
const mouseDownTimeRef = (0,
|
|
6726
|
-
const handleMouseDown = (0,
|
|
4985
|
+
const mouseDownTimeRef = (0, import_react30.useRef)(0);
|
|
4986
|
+
const handleMouseDown = (0, import_react30.useCallback)(
|
|
6727
4987
|
(e) => {
|
|
6728
4988
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
6729
4989
|
const x = e.clientX - rect.left;
|
|
@@ -6735,7 +4995,7 @@ var MediaElementPlaylist = ({
|
|
|
6735
4995
|
},
|
|
6736
4996
|
[samplesPerPixel, sampleRate]
|
|
6737
4997
|
);
|
|
6738
|
-
const handleMouseMove = (0,
|
|
4998
|
+
const handleMouseMove = (0, import_react30.useCallback)(
|
|
6739
4999
|
(e) => {
|
|
6740
5000
|
if (!isSelecting) return;
|
|
6741
5001
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
@@ -6745,7 +5005,7 @@ var MediaElementPlaylist = ({
|
|
|
6745
5005
|
},
|
|
6746
5006
|
[isSelecting, samplesPerPixel, sampleRate]
|
|
6747
5007
|
);
|
|
6748
|
-
const handleMouseUp = (0,
|
|
5008
|
+
const handleMouseUp = (0, import_react30.useCallback)(
|
|
6749
5009
|
(e) => {
|
|
6750
5010
|
if (!isSelecting) return;
|
|
6751
5011
|
setIsSelecting(false);
|
|
@@ -6775,10 +5035,10 @@ var MediaElementPlaylist = ({
|
|
|
6775
5035
|
[isSelecting, selectionStart, samplesPerPixel, sampleRate, seekTo, isPlaying, playoutRef, play]
|
|
6776
5036
|
);
|
|
6777
5037
|
if (peaksDataArray.length === 0) {
|
|
6778
|
-
return /* @__PURE__ */ (0,
|
|
5038
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className, children: "Loading waveform..." });
|
|
6779
5039
|
}
|
|
6780
|
-
return /* @__PURE__ */ (0,
|
|
6781
|
-
|
|
5040
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ui_components10.DevicePixelRatioProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5041
|
+
import_ui_components10.PlaylistInfoContext.Provider,
|
|
6782
5042
|
{
|
|
6783
5043
|
value: {
|
|
6784
5044
|
samplesPerPixel,
|
|
@@ -6791,11 +5051,11 @@ var MediaElementPlaylist = ({
|
|
|
6791
5051
|
barWidth,
|
|
6792
5052
|
barGap
|
|
6793
5053
|
},
|
|
6794
|
-
children: /* @__PURE__ */ (0,
|
|
6795
|
-
|
|
5054
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5055
|
+
import_ui_components10.Playlist,
|
|
6796
5056
|
{
|
|
6797
5057
|
theme,
|
|
6798
|
-
backgroundColor: (0,
|
|
5058
|
+
backgroundColor: (0, import_ui_components10.waveformColorToCss)(theme.waveOutlineColor),
|
|
6799
5059
|
timescaleBackgroundColor: theme.timescaleBackgroundColor,
|
|
6800
5060
|
timescaleWidth: tracksFullWidth,
|
|
6801
5061
|
tracksWidth: tracksFullWidth,
|
|
@@ -6805,15 +5065,15 @@ var MediaElementPlaylist = ({
|
|
|
6805
5065
|
onTracksMouseUp: handleMouseUp,
|
|
6806
5066
|
scrollContainerRef: handleScrollContainerRef,
|
|
6807
5067
|
isSelecting,
|
|
6808
|
-
timescale: timeScaleHeight > 0 ? /* @__PURE__ */ (0,
|
|
6809
|
-
children: /* @__PURE__ */ (0,
|
|
5068
|
+
timescale: timeScaleHeight > 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_ui_components10.SmartScale, {}) : void 0,
|
|
5069
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
6810
5070
|
peaksDataArray.map((trackClipPeaks, trackIndex) => {
|
|
6811
5071
|
const maxChannels = trackClipPeaks.length > 0 ? Math.max(...trackClipPeaks.map((clip) => clip.peaks.data.length)) : 1;
|
|
6812
|
-
return /* @__PURE__ */ (0,
|
|
6813
|
-
|
|
5072
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5073
|
+
import_ui_components10.Track,
|
|
6814
5074
|
{
|
|
6815
5075
|
numChannels: maxChannels,
|
|
6816
|
-
backgroundColor: (0,
|
|
5076
|
+
backgroundColor: (0, import_ui_components10.waveformColorToCss)(theme.waveOutlineColor),
|
|
6817
5077
|
offset: 0,
|
|
6818
5078
|
width: tracksFullWidth,
|
|
6819
5079
|
hasClipHeaders: false,
|
|
@@ -6822,8 +5082,8 @@ var MediaElementPlaylist = ({
|
|
|
6822
5082
|
children: trackClipPeaks.map((clip, clipIndex) => {
|
|
6823
5083
|
const peaksData = clip.peaks;
|
|
6824
5084
|
const width = peaksData.length;
|
|
6825
|
-
return /* @__PURE__ */ (0,
|
|
6826
|
-
|
|
5085
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
5086
|
+
import_ui_components10.Clip,
|
|
6827
5087
|
{
|
|
6828
5088
|
clipId: clip.clipId,
|
|
6829
5089
|
trackIndex,
|
|
@@ -6837,7 +5097,7 @@ var MediaElementPlaylist = ({
|
|
|
6837
5097
|
isSelected: true,
|
|
6838
5098
|
trackId: `media-element-track-${trackIndex}`,
|
|
6839
5099
|
children: [
|
|
6840
|
-
peaksData.data.map((channelPeaks, channelIndex) => /* @__PURE__ */ (0,
|
|
5100
|
+
peaksData.data.map((channelPeaks, channelIndex) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
6841
5101
|
ChannelWithMediaElementProgress,
|
|
6842
5102
|
{
|
|
6843
5103
|
index: channelIndex,
|
|
@@ -6849,8 +5109,8 @@ var MediaElementPlaylist = ({
|
|
|
6849
5109
|
},
|
|
6850
5110
|
`${trackIndex}-${clipIndex}-${channelIndex}`
|
|
6851
5111
|
)),
|
|
6852
|
-
showFades && fadeIn && fadeIn.duration > 0 && /* @__PURE__ */ (0,
|
|
6853
|
-
|
|
5112
|
+
showFades && fadeIn && fadeIn.duration > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5113
|
+
import_ui_components10.FadeOverlay,
|
|
6854
5114
|
{
|
|
6855
5115
|
left: 0,
|
|
6856
5116
|
width: Math.floor(fadeIn.duration * sampleRate / samplesPerPixel),
|
|
@@ -6858,8 +5118,8 @@ var MediaElementPlaylist = ({
|
|
|
6858
5118
|
curveType: fadeIn.type
|
|
6859
5119
|
}
|
|
6860
5120
|
),
|
|
6861
|
-
showFades && fadeOut && fadeOut.duration > 0 && /* @__PURE__ */ (0,
|
|
6862
|
-
|
|
5121
|
+
showFades && fadeOut && fadeOut.duration > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5122
|
+
import_ui_components10.FadeOverlay,
|
|
6863
5123
|
{
|
|
6864
5124
|
left: width - Math.floor(fadeOut.duration * sampleRate / samplesPerPixel),
|
|
6865
5125
|
width: Math.floor(fadeOut.duration * sampleRate / samplesPerPixel),
|
|
@@ -6876,19 +5136,19 @@ var MediaElementPlaylist = ({
|
|
|
6876
5136
|
trackIndex
|
|
6877
5137
|
);
|
|
6878
5138
|
}),
|
|
6879
|
-
annotations.length > 0 && annotationIntegration && /* @__PURE__ */ (0,
|
|
6880
|
-
|
|
5139
|
+
annotations.length > 0 && annotationIntegration && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5140
|
+
import_react31.DragDropProvider,
|
|
6881
5141
|
{
|
|
6882
5142
|
onDragStart,
|
|
6883
5143
|
onDragMove,
|
|
6884
5144
|
onDragEnd,
|
|
6885
5145
|
modifiers: editable ? [import_modifiers.RestrictToHorizontalAxis] : [],
|
|
6886
5146
|
plugins: noDropAnimationPlugins,
|
|
6887
|
-
children: /* @__PURE__ */ (0,
|
|
5147
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(annotationIntegration.AnnotationBoxesWrapper, { height: 30, width: tracksFullWidth, children: annotations.map((annotation, index) => {
|
|
6888
5148
|
const startPosition = annotation.start * sampleRate / samplesPerPixel;
|
|
6889
5149
|
const endPosition = annotation.end * sampleRate / samplesPerPixel;
|
|
6890
5150
|
const label = getAnnotationBoxLabel ? getAnnotationBoxLabel(annotation, index) : annotation.id;
|
|
6891
|
-
return /* @__PURE__ */ (0,
|
|
5151
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
6892
5152
|
annotationIntegration.AnnotationBox,
|
|
6893
5153
|
{
|
|
6894
5154
|
annotationId: annotation.id,
|
|
@@ -6906,15 +5166,15 @@ var MediaElementPlaylist = ({
|
|
|
6906
5166
|
}) })
|
|
6907
5167
|
}
|
|
6908
5168
|
),
|
|
6909
|
-
selectionStart !== selectionEnd && /* @__PURE__ */ (0,
|
|
6910
|
-
|
|
5169
|
+
selectionStart !== selectionEnd && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5170
|
+
import_ui_components10.Selection,
|
|
6911
5171
|
{
|
|
6912
5172
|
startPosition: Math.min(selectionStart, selectionEnd) * sampleRate / samplesPerPixel,
|
|
6913
5173
|
endPosition: Math.max(selectionStart, selectionEnd) * sampleRate / samplesPerPixel,
|
|
6914
5174
|
color: theme.selectionColor
|
|
6915
5175
|
}
|
|
6916
5176
|
),
|
|
6917
|
-
renderPlayhead ? /* @__PURE__ */ (0,
|
|
5177
|
+
renderPlayhead ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
6918
5178
|
CustomMediaElementPlayhead,
|
|
6919
5179
|
{
|
|
6920
5180
|
renderPlayhead,
|
|
@@ -6922,7 +5182,7 @@ var MediaElementPlaylist = ({
|
|
|
6922
5182
|
samplesPerPixel,
|
|
6923
5183
|
sampleRate
|
|
6924
5184
|
}
|
|
6925
|
-
) : /* @__PURE__ */ (0,
|
|
5185
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(AnimatedMediaElementPlayhead, { color: theme.playheadColor })
|
|
6926
5186
|
] })
|
|
6927
5187
|
}
|
|
6928
5188
|
)
|
|
@@ -6931,8 +5191,8 @@ var MediaElementPlaylist = ({
|
|
|
6931
5191
|
};
|
|
6932
5192
|
|
|
6933
5193
|
// src/components/MediaElementAnnotationList.tsx
|
|
6934
|
-
var
|
|
6935
|
-
var
|
|
5194
|
+
var import_react32 = require("react");
|
|
5195
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
6936
5196
|
var MediaElementAnnotationList = ({
|
|
6937
5197
|
height,
|
|
6938
5198
|
renderAnnotationItem,
|
|
@@ -6947,7 +5207,7 @@ var MediaElementAnnotationList = ({
|
|
|
6947
5207
|
const integration = useAnnotationIntegration();
|
|
6948
5208
|
const { setAnnotations } = useMediaElementControls();
|
|
6949
5209
|
const resolvedConfig = annotationListConfig != null ? annotationListConfig : { linkEndpoints: false, continuousPlay };
|
|
6950
|
-
const handleAnnotationUpdate = (0,
|
|
5210
|
+
const handleAnnotationUpdate = (0, import_react32.useCallback)(
|
|
6951
5211
|
(updatedAnnotations) => {
|
|
6952
5212
|
setAnnotations(updatedAnnotations);
|
|
6953
5213
|
onAnnotationUpdate == null ? void 0 : onAnnotationUpdate(updatedAnnotations);
|
|
@@ -6955,7 +5215,7 @@ var MediaElementAnnotationList = ({
|
|
|
6955
5215
|
[setAnnotations, onAnnotationUpdate]
|
|
6956
5216
|
);
|
|
6957
5217
|
const { AnnotationText } = integration;
|
|
6958
|
-
return /* @__PURE__ */ (0,
|
|
5218
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
6959
5219
|
AnnotationText,
|
|
6960
5220
|
{
|
|
6961
5221
|
annotations,
|
|
@@ -6974,7 +5234,7 @@ var MediaElementAnnotationList = ({
|
|
|
6974
5234
|
};
|
|
6975
5235
|
|
|
6976
5236
|
// src/components/MediaElementWaveform.tsx
|
|
6977
|
-
var
|
|
5237
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
6978
5238
|
var MediaElementWaveform = ({
|
|
6979
5239
|
annotationTextHeight,
|
|
6980
5240
|
getAnnotationBoxLabel,
|
|
@@ -6989,8 +5249,8 @@ var MediaElementWaveform = ({
|
|
|
6989
5249
|
className
|
|
6990
5250
|
}) => {
|
|
6991
5251
|
const { annotations } = useMediaElementState();
|
|
6992
|
-
return /* @__PURE__ */ (0,
|
|
6993
|
-
/* @__PURE__ */ (0,
|
|
5252
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
5253
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
6994
5254
|
MediaElementPlaylist,
|
|
6995
5255
|
{
|
|
6996
5256
|
getAnnotationBoxLabel,
|
|
@@ -7002,7 +5262,7 @@ var MediaElementWaveform = ({
|
|
|
7002
5262
|
className
|
|
7003
5263
|
}
|
|
7004
5264
|
),
|
|
7005
|
-
annotations.length > 0 && /* @__PURE__ */ (0,
|
|
5265
|
+
annotations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
7006
5266
|
MediaElementAnnotationList,
|
|
7007
5267
|
{
|
|
7008
5268
|
height: annotationTextHeight,
|
|
@@ -7077,11 +5337,11 @@ var KeyboardShortcuts = ({
|
|
|
7077
5337
|
};
|
|
7078
5338
|
|
|
7079
5339
|
// src/components/ClipInteractionProvider.tsx
|
|
7080
|
-
var
|
|
7081
|
-
var
|
|
5340
|
+
var import_react33 = __toESM(require("react"));
|
|
5341
|
+
var import_react34 = require("@dnd-kit/react");
|
|
7082
5342
|
var import_modifiers2 = require("@dnd-kit/abstract/modifiers");
|
|
7083
|
-
var
|
|
7084
|
-
var
|
|
5343
|
+
var import_core6 = require("@waveform-playlist/core");
|
|
5344
|
+
var import_ui_components11 = require("@waveform-playlist/ui-components");
|
|
7085
5345
|
|
|
7086
5346
|
// src/modifiers/ClipCollisionModifier.ts
|
|
7087
5347
|
var import_abstract = require("@dnd-kit/abstract");
|
|
@@ -7109,7 +5369,7 @@ var ClipCollisionModifier = _ClipCollisionModifier;
|
|
|
7109
5369
|
|
|
7110
5370
|
// src/modifiers/SnapToGridModifier.ts
|
|
7111
5371
|
var import_abstract2 = require("@dnd-kit/abstract");
|
|
7112
|
-
var
|
|
5372
|
+
var import_core5 = require("@waveform-playlist/core");
|
|
7113
5373
|
var _SnapToGridModifier = class _SnapToGridModifier extends import_abstract2.Modifier {
|
|
7114
5374
|
apply(operation) {
|
|
7115
5375
|
const { transform, source } = operation;
|
|
@@ -7130,18 +5390,18 @@ var _SnapToGridModifier = class _SnapToGridModifier extends import_abstract2.Mod
|
|
|
7130
5390
|
}
|
|
7131
5391
|
const { snapTo, bpm, timeSignature, sampleRate } = this.options;
|
|
7132
5392
|
if (snapTo === "off") return transform;
|
|
7133
|
-
const gridTicks = snapTo === "bar" ? (0,
|
|
5393
|
+
const gridTicks = snapTo === "bar" ? (0, import_core5.ticksPerBar)(timeSignature) : (0, import_core5.ticksPerBeat)(timeSignature);
|
|
7134
5394
|
if (startSample !== void 0) {
|
|
7135
5395
|
const proposedSamples = startSample + transform.x * samplesPerPixel;
|
|
7136
|
-
const proposedTicks = (0,
|
|
7137
|
-
const snappedTicks2 = (0,
|
|
7138
|
-
const snappedSamples2 = (0,
|
|
5396
|
+
const proposedTicks = (0, import_core5.samplesToTicks)(proposedSamples, bpm, sampleRate);
|
|
5397
|
+
const snappedTicks2 = (0, import_core5.snapToGrid)(proposedTicks, gridTicks);
|
|
5398
|
+
const snappedSamples2 = (0, import_core5.ticksToSamples)(snappedTicks2, bpm, sampleRate);
|
|
7139
5399
|
return { x: (snappedSamples2 - startSample) / samplesPerPixel, y: 0 };
|
|
7140
5400
|
}
|
|
7141
5401
|
const deltaSamples = transform.x * samplesPerPixel;
|
|
7142
|
-
const deltaTicks = (0,
|
|
7143
|
-
const snappedTicks = (0,
|
|
7144
|
-
const snappedSamples = (0,
|
|
5402
|
+
const deltaTicks = (0, import_core5.samplesToTicks)(deltaSamples, bpm, sampleRate);
|
|
5403
|
+
const snappedTicks = (0, import_core5.snapToGrid)(deltaTicks, gridTicks);
|
|
5404
|
+
const snappedSamples = (0, import_core5.ticksToSamples)(snappedTicks, bpm, sampleRate);
|
|
7145
5405
|
return { x: snappedSamples / samplesPerPixel, y: 0 };
|
|
7146
5406
|
}
|
|
7147
5407
|
};
|
|
@@ -7149,7 +5409,7 @@ _SnapToGridModifier.configure = (0, import_abstract2.configurator)(_SnapToGridMo
|
|
|
7149
5409
|
var SnapToGridModifier = _SnapToGridModifier;
|
|
7150
5410
|
|
|
7151
5411
|
// src/components/ClipInteractionProvider.tsx
|
|
7152
|
-
var
|
|
5412
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
7153
5413
|
var NOOP_TRACKS_CHANGE = () => {
|
|
7154
5414
|
};
|
|
7155
5415
|
var ClipInteractionProvider = ({
|
|
@@ -7159,28 +5419,28 @@ var ClipInteractionProvider = ({
|
|
|
7159
5419
|
}) => {
|
|
7160
5420
|
const { tracks, samplesPerPixel, sampleRate, playoutRef, isDraggingRef, onTracksChange } = usePlaylistData();
|
|
7161
5421
|
const { setSelectedTrackId } = usePlaylistControls();
|
|
7162
|
-
const beatsAndBars = (0,
|
|
5422
|
+
const beatsAndBars = (0, import_ui_components11.useBeatsAndBars)();
|
|
7163
5423
|
const useBeatsSnap = snap && beatsAndBars != null && beatsAndBars.scaleMode === "beats" && beatsAndBars.snapTo !== "off";
|
|
7164
5424
|
const useTimescaleSnap = snap && !useBeatsSnap;
|
|
7165
|
-
(0,
|
|
5425
|
+
(0, import_react33.useEffect)(() => {
|
|
7166
5426
|
if (onTracksChange == null) {
|
|
7167
5427
|
console.warn(
|
|
7168
5428
|
"[waveform-playlist] ClipInteractionProvider: onTracksChange is not set on WaveformPlaylistProvider. Drag and trim edits will not be persisted."
|
|
7169
5429
|
);
|
|
7170
5430
|
}
|
|
7171
5431
|
}, [onTracksChange]);
|
|
7172
|
-
const snapSamplePosition = (0,
|
|
5432
|
+
const snapSamplePosition = (0, import_react33.useMemo)(() => {
|
|
7173
5433
|
if (useBeatsSnap && beatsAndBars) {
|
|
7174
5434
|
const { bpm, timeSignature, snapTo } = beatsAndBars;
|
|
7175
|
-
const gridTicks = snapTo === "bar" ? (0,
|
|
5435
|
+
const gridTicks = snapTo === "bar" ? (0, import_core6.ticksPerBar)(timeSignature) : (0, import_core6.ticksPerBeat)(timeSignature);
|
|
7176
5436
|
return (samplePos) => {
|
|
7177
|
-
const ticks = (0,
|
|
7178
|
-
const snapped = (0,
|
|
7179
|
-
return (0,
|
|
5437
|
+
const ticks = (0, import_core6.samplesToTicks)(samplePos, bpm, sampleRate);
|
|
5438
|
+
const snapped = (0, import_core6.snapToGrid)(ticks, gridTicks);
|
|
5439
|
+
return (0, import_core6.ticksToSamples)(snapped, bpm, sampleRate);
|
|
7180
5440
|
};
|
|
7181
5441
|
}
|
|
7182
5442
|
if (useTimescaleSnap) {
|
|
7183
|
-
const gridSamples = Math.round((0,
|
|
5443
|
+
const gridSamples = Math.round((0, import_ui_components11.getScaleInfo)(samplesPerPixel).smallStep / 1e3 * sampleRate);
|
|
7184
5444
|
return (samplePos) => Math.round(samplePos / gridSamples) * gridSamples;
|
|
7185
5445
|
}
|
|
7186
5446
|
return void 0;
|
|
@@ -7198,7 +5458,7 @@ var ClipInteractionProvider = ({
|
|
|
7198
5458
|
isDraggingRef,
|
|
7199
5459
|
snapSamplePosition
|
|
7200
5460
|
});
|
|
7201
|
-
const onDragStart =
|
|
5461
|
+
const onDragStart = import_react33.default.useCallback(
|
|
7202
5462
|
(event) => {
|
|
7203
5463
|
var _a, _b, _c;
|
|
7204
5464
|
const trackIndex = (_c = (_b = (_a = event.operation) == null ? void 0 : _a.source) == null ? void 0 : _b.data) == null ? void 0 : _c.trackIndex;
|
|
@@ -7209,7 +5469,7 @@ var ClipInteractionProvider = ({
|
|
|
7209
5469
|
},
|
|
7210
5470
|
[handleDragStart, tracks, setSelectedTrackId]
|
|
7211
5471
|
);
|
|
7212
|
-
const modifiers = (0,
|
|
5472
|
+
const modifiers = (0, import_react33.useMemo)(() => {
|
|
7213
5473
|
const mods = [import_modifiers2.RestrictToHorizontalAxis];
|
|
7214
5474
|
if (useBeatsSnap && beatsAndBars) {
|
|
7215
5475
|
mods.push(
|
|
@@ -7226,7 +5486,7 @@ var ClipInteractionProvider = ({
|
|
|
7226
5486
|
mods.push(
|
|
7227
5487
|
SnapToGridModifier.configure({
|
|
7228
5488
|
mode: "timescale",
|
|
7229
|
-
gridSamples: Math.round((0,
|
|
5489
|
+
gridSamples: Math.round((0, import_ui_components11.getScaleInfo)(samplesPerPixel).smallStep / 1e3 * sampleRate),
|
|
7230
5490
|
samplesPerPixel
|
|
7231
5491
|
})
|
|
7232
5492
|
);
|
|
@@ -7234,8 +5494,8 @@ var ClipInteractionProvider = ({
|
|
|
7234
5494
|
mods.push(ClipCollisionModifier.configure({ tracks, samplesPerPixel }));
|
|
7235
5495
|
return mods;
|
|
7236
5496
|
}, [useBeatsSnap, useTimescaleSnap, beatsAndBars, tracks, samplesPerPixel, sampleRate]);
|
|
7237
|
-
return /* @__PURE__ */ (0,
|
|
7238
|
-
|
|
5497
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ClipInteractionContextProvider, { value: true, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5498
|
+
import_react34.DragDropProvider,
|
|
7239
5499
|
{
|
|
7240
5500
|
sensors,
|
|
7241
5501
|
onDragStart,
|
|
@@ -7258,7 +5518,6 @@ var ClipInteractionProvider = ({
|
|
|
7258
5518
|
ContinuousPlayCheckbox,
|
|
7259
5519
|
DownloadAnnotationsButton,
|
|
7260
5520
|
EditableCheckbox,
|
|
7261
|
-
ExportWavButton,
|
|
7262
5521
|
FastForwardButton,
|
|
7263
5522
|
KeyboardShortcuts,
|
|
7264
5523
|
LinkEndpointsCheckbox,
|
|
@@ -7281,17 +5540,10 @@ var ClipInteractionProvider = ({
|
|
|
7281
5540
|
SpectrogramIntegrationProvider,
|
|
7282
5541
|
StopButton,
|
|
7283
5542
|
TimeFormatSelect,
|
|
7284
|
-
Tone,
|
|
7285
5543
|
Waveform,
|
|
7286
5544
|
WaveformPlaylistProvider,
|
|
7287
5545
|
ZoomInButton,
|
|
7288
5546
|
ZoomOutButton,
|
|
7289
|
-
createEffectChain,
|
|
7290
|
-
createEffectInstance,
|
|
7291
|
-
effectCategories,
|
|
7292
|
-
effectDefinitions,
|
|
7293
|
-
getEffectDefinition,
|
|
7294
|
-
getEffectsByCategory,
|
|
7295
5547
|
getShortcutLabel,
|
|
7296
5548
|
getWaveformDataMetadata,
|
|
7297
5549
|
loadPeaksFromWaveformData,
|
|
@@ -7300,30 +5552,24 @@ var ClipInteractionProvider = ({
|
|
|
7300
5552
|
useAnnotationDragHandlers,
|
|
7301
5553
|
useAnnotationIntegration,
|
|
7302
5554
|
useAnnotationKeyboardControls,
|
|
7303
|
-
useAudioTracks,
|
|
7304
5555
|
useClipDragHandlers,
|
|
7305
5556
|
useClipInteractionEnabled,
|
|
7306
5557
|
useClipSplitting,
|
|
7307
5558
|
useDragSensors,
|
|
7308
|
-
useDynamicEffects,
|
|
7309
|
-
useDynamicTracks,
|
|
7310
|
-
useExportWav,
|
|
7311
5559
|
useKeyboardShortcuts,
|
|
7312
|
-
useMasterAnalyser,
|
|
7313
5560
|
useMasterVolume,
|
|
7314
5561
|
useMediaElementAnimation,
|
|
7315
5562
|
useMediaElementControls,
|
|
7316
5563
|
useMediaElementData,
|
|
7317
5564
|
useMediaElementState,
|
|
7318
|
-
useOutputMeter,
|
|
7319
5565
|
usePlaybackAnimation,
|
|
7320
5566
|
usePlaybackShortcuts,
|
|
7321
5567
|
usePlaylistControls,
|
|
7322
5568
|
usePlaylistData,
|
|
5569
|
+
usePlaylistDataOptional,
|
|
7323
5570
|
usePlaylistState,
|
|
7324
5571
|
useSpectrogramIntegration,
|
|
7325
5572
|
useTimeFormat,
|
|
7326
|
-
useTrackDynamicEffects,
|
|
7327
5573
|
useZoomControls,
|
|
7328
5574
|
waveformDataToPeaks
|
|
7329
5575
|
});
|