From 4d4b08db07811e2c248f9e1bd45de457cee76e35 Mon Sep 17 00:00:00 2001 From: Enriquefft Date: Thu, 16 Apr 2026 14:31:51 -0500 Subject: [PATCH] fix: skip chained initial trims before recording starts Startup trim-skip only consulted the first active region at t=0, so back-to-back or overlapping trims starting at zero (e.g. [0,500ms] followed by [500ms,1000ms]) left the second region un-skipped. The in-flight tick loop would catch it, but MediaRecorder was already running by then, capturing up to one rAF frame of trimmed audio into the blob and shifting the downstream timeline. Loop findActiveTrimRegion from the advancing startPosition until no region matches or startPosition >= effectiveEnd, bounded by trimRegions.length for safety. Recompute initialSpeedRegion from the final startPosition so playbackRate reflects the true start point. --- src/lib/exporter/audioEncoder.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/lib/exporter/audioEncoder.ts b/src/lib/exporter/audioEncoder.ts index 611ef5b..64d46d0 100644 --- a/src/lib/exporter/audioEncoder.ts +++ b/src/lib/exporter/audioEncoder.ts @@ -227,15 +227,18 @@ export class AudioProcessor { await audioContext.resume(); } - // Skip past any initial trim region before recording starts - // to avoid capturing trimmed audio during the first frames. + // Skip past any initial trim region(s) before recording starts to avoid + // capturing trimmed audio during the first rAF frames of playback. + // Loops to handle back-to-back or overlapping trims at t=0. + const effectiveEnd = validatedDurationSec ?? media.duration; let startPosition = 0; - const initialTrim = this.findActiveTrimRegion(0, trimRegions); - if (initialTrim) { - startPosition = initialTrim.endMs / 1000; + for (let i = 0; i <= trimRegions.length; i++) { + const activeTrim = this.findActiveTrimRegion(startPosition * 1000, trimRegions); + if (!activeTrim) break; + startPosition = activeTrim.endMs / 1000; + if (startPosition >= effectiveEnd) break; } - const effectiveEnd = validatedDurationSec ?? media.duration; if (startPosition >= effectiveEnd) { // All content is trimmed — return silent blob return new Blob([], { type: "audio/webm" });