port: duration confirmed at 0.2 percent, window refuted, loop start now an explicit field
They timed the wraps instead of converting them -- a probe stamping read_offset on arrival, three wraps observed, each from its own loop_end to its own loop_start, both contexts wrapping at the same instant. Cycle 61.81 s against the 61.93 authored here: 0.2 percent, from a wall clock between decoder events versus an autocorrelation that never touched the wave. The window is wrong: loop_start is 11.6 percent into the stream, about ten seconds, so this export has the right duration over the wrong window -- replaying the intro every cycle and omitting the tail the game plays. Not re-cut, on their instruction: the exact start is unmeasured and linearity is refuted by a 4.4 percent rate variation within one stream. But loop_end_s alone silently asserted a start of zero, so the entry gains loop_start_s, authored as 0.0 and flagged wrong, with -ss applied before -t so the pair is (start, duration). Proved before it is needed: loop_start_s=10 yields -ss 10 -t 61.93 and a 61.930 s output. Restored to 0.0, export byte-unchanged. My smooth-join check gains a use I could not have anticipated: it explains why a wrong ten-second window went unheard, because a cut near a zero crossing is smooth wherever it falls. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF
This commit is contained in:
@@ -98,6 +98,15 @@ pub struct BgmSpec {
|
||||
/// exporter therefore trims to this length rather than carrying a loop
|
||||
/// point the runtime could not honour, and the trimmed tail is content the
|
||||
/// game never reaches.
|
||||
/// Seconds into the summed bank where the loop window BEGINS.
|
||||
///
|
||||
/// 🔴 Split out from `loop_end_s` on 2026-08-30 because carrying only an end
|
||||
/// silently asserted a start of zero, and that start is now known to be
|
||||
/// WRONG — the measured window begins about ten seconds in. An assumption
|
||||
/// that has to be inferred from the absence of a field is not one a reader
|
||||
/// can weigh.
|
||||
#[serde(default)]
|
||||
pub loop_start_s: Option<f64>,
|
||||
#[serde(default)]
|
||||
pub loop_end_s: Option<f64>,
|
||||
#[serde(default)]
|
||||
@@ -515,7 +524,13 @@ pub fn export_bgm<S: DiscSource + ?Sized>(
|
||||
// 🔴 TRIM TO THE MEASURED LOOP REGION. Godot loops a whole file, so the
|
||||
// region has to be the file; carrying a loop point the runtime cannot
|
||||
// honour would leave the fade-out playing every cycle.
|
||||
if let Some(start) = spec.loop_start_s.filter(|v| *v > 0.0) {
|
||||
argv.push("-ss".into());
|
||||
argv.push(format!("{start}"));
|
||||
}
|
||||
if let Some(end) = spec.loop_end_s {
|
||||
// A LENGTH, applied after any `-ss`, so the pair is (start, duration)
|
||||
// and moving the start does not silently change how much is kept.
|
||||
argv.push("-t".into());
|
||||
argv.push(format!("{end}"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user