Skip to content

Commit de7cc43

Browse files
committed
Fix looped music sync and persist hook sound layers
1 parent 07ab7f6 commit de7cc43

4 files changed

Lines changed: 68 additions & 4 deletions

File tree

src/components/video-editor/VideoEditor.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ export default function VideoEditor() {
307307
setGifFrameRate(normalizedEditor.gifFrameRate);
308308
setGifLoop(normalizedEditor.gifLoop);
309309
setGifSizePreset(normalizedEditor.gifSizePreset);
310+
setHookSoundLayers(normalizedEditor.hookSoundLayers);
310311

311312
setSelectedZoomId(null);
312313
setSelectedTrimId(null);
@@ -369,6 +370,7 @@ export default function VideoEditor() {
369370
backgroundMusicRegions,
370371
backgroundMusicVolume,
371372
audioHooks,
373+
hookSoundLayers,
372374
audioHooksVolume,
373375
shadowIntensity,
374376
showBlur,
@@ -398,6 +400,7 @@ export default function VideoEditor() {
398400
backgroundMusicRegions,
399401
backgroundMusicVolume,
400402
audioHooks,
403+
hookSoundLayers,
401404
audioHooksVolume,
402405
shadowIntensity,
403406
showBlur,
@@ -524,6 +527,7 @@ export default function VideoEditor() {
524527
backgroundMusicRegions,
525528
backgroundMusicVolume,
526529
audioHooks,
530+
hookSoundLayers,
527531
audioHooksVolume,
528532
shadowIntensity,
529533
showBlur,
@@ -586,6 +590,7 @@ export default function VideoEditor() {
586590
backgroundMusicRegions,
587591
backgroundMusicVolume,
588592
audioHooks,
593+
hookSoundLayers,
589594
audioHooksVolume,
590595
shadowIntensity,
591596
showBlur,

src/components/video-editor/VideoPlayback.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,12 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
11991199
return;
12001200
}
12011201

1202+
const backgroundDuration = backgroundMusic.duration;
1203+
const hasValidDuration = Number.isFinite(backgroundDuration) && backgroundDuration > 0;
1204+
const loopedCurrentTime = hasValidDuration
1205+
? ((currentTime % backgroundDuration) + backgroundDuration) % backgroundDuration
1206+
: currentTime;
1207+
12021208
const isInRegion =
12031209
backgroundMusicRegions.length === 0 ||
12041210
backgroundMusicRegions.some(
@@ -1209,14 +1215,14 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
12091215

12101216
if (!isPlaying) {
12111217
backgroundMusic.pause();
1212-
if (Math.abs(backgroundMusic.currentTime - currentTime) > 0.05) {
1213-
backgroundMusic.currentTime = currentTime;
1218+
if (Math.abs(backgroundMusic.currentTime - loopedCurrentTime) > 0.05) {
1219+
backgroundMusic.currentTime = loopedCurrentTime;
12141220
}
12151221
return;
12161222
}
12171223

1218-
if (Math.abs(backgroundMusic.currentTime - currentTime) > 0.2) {
1219-
backgroundMusic.currentTime = currentTime;
1224+
if (Math.abs(backgroundMusic.currentTime - loopedCurrentTime) > 0.2) {
1225+
backgroundMusic.currentTime = loopedCurrentTime;
12201226
}
12211227

12221228
backgroundMusic.play().catch(() => {

src/components/video-editor/projectPersistence.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ describe("projectPersistence media compatibility", () => {
4141
annotation: false,
4242
blur: false,
4343
},
44+
hookSoundLayers: {
45+
zoom: [],
46+
trim: [],
47+
speed: [],
48+
annotation: [],
49+
blur: [],
50+
},
4451
audioHooksVolume: 0.35,
4552
shadowIntensity: 0,
4653
showBlur: false,
@@ -122,6 +129,13 @@ it("creates stable snapshots for identical project state", () => {
122129
annotation: false,
123130
blur: false,
124131
},
132+
hookSoundLayers: {
133+
zoom: [],
134+
trim: [],
135+
speed: [],
136+
annotation: [],
137+
blur: [],
138+
},
125139
audioHooksVolume: 0.35,
126140
shadowIntensity: 0,
127141
showBlur: false,

src/components/video-editor/projectPersistence.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export interface ProjectEditorState {
5353
backgroundMusicRegions: TrimRegion[];
5454
backgroundMusicVolume: number;
5555
audioHooks: AudioHooksConfig;
56+
hookSoundLayers: Record<AudioHookType, string[]>;
5657
audioHooksVolume: number;
5758
shadowIntensity: number;
5859
showBlur: boolean;
@@ -137,6 +138,41 @@ function normalizeAudioHooks(value: unknown): AudioHooksConfig {
137138
};
138139
}
139140

141+
function normalizeHookSoundLayers(value: unknown): Record<AudioHookType, string[]> {
142+
const defaults: Record<AudioHookType, string[]> = {
143+
zoom: [],
144+
trim: [],
145+
speed: [],
146+
annotation: [],
147+
blur: [],
148+
};
149+
150+
if (!value || typeof value !== "object") {
151+
return defaults;
152+
}
153+
154+
const raw = value as Partial<Record<AudioHookType, unknown>>;
155+
return {
156+
zoom: Array.isArray(raw.zoom)
157+
? raw.zoom.filter((entry): entry is string => typeof entry === "string" && entry.length > 0)
158+
: [],
159+
trim: Array.isArray(raw.trim)
160+
? raw.trim.filter((entry): entry is string => typeof entry === "string" && entry.length > 0)
161+
: [],
162+
speed: Array.isArray(raw.speed)
163+
? raw.speed.filter((entry): entry is string => typeof entry === "string" && entry.length > 0)
164+
: [],
165+
annotation: Array.isArray(raw.annotation)
166+
? raw.annotation.filter(
167+
(entry): entry is string => typeof entry === "string" && entry.length > 0,
168+
)
169+
: [],
170+
blur: Array.isArray(raw.blur)
171+
? raw.blur.filter((entry): entry is string => typeof entry === "string" && entry.length > 0)
172+
: [],
173+
};
174+
}
175+
140176
function isFileUrl(value: string): boolean {
141177
return /^file:\/\//i.test(value);
142178
}
@@ -513,6 +549,9 @@ export function normalizeProjectEditor(editor: Partial<ProjectEditorState>): Pro
513549
? clamp((editor as { backgroundMusicVolume: number }).backgroundMusicVolume, 0, 1)
514550
: 0.35,
515551
audioHooks: normalizeAudioHooks((editor as { audioHooks?: unknown }).audioHooks),
552+
hookSoundLayers: normalizeHookSoundLayers(
553+
(editor as { hookSoundLayers?: unknown }).hookSoundLayers,
554+
),
516555
audioHooksVolume: isFiniteNumber((editor as { audioHooksVolume?: unknown }).audioHooksVolume)
517556
? clamp((editor as { audioHooksVolume: number }).audioHooksVolume, 0, 1)
518557
: 0.35,

0 commit comments

Comments
 (0)