fix: timeline waveforms of near-silent clips no longer drawn full scale

Waveforms are normalised to the source's peak so quiet recordings stay readable, but the
boost was unbounded: an empty audio stream at -52 dBFS (silent archive film) was drawn as
loud as dialogue. The normalisation is now capped at +12 dB.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas 2026-10-01 11:05:30 -04:00
parent c14fc8e1b7
commit f0eb8cc9a0
1 changed files with 34 additions and 2 deletions

View File

@ -509,8 +509,8 @@ fn draw_waveform(app: &mut FilmcraftApp, p: &egui::Painter, body: Rect, it: &Tra
if clip.width() <= 0.0 {
return;
}
let peak = peaks.iter().fold(0f32, |m, (a, b)| m.max(a.abs()).max(b.abs())).max(1e-4);
let gain = filmcraft_render::audio::db_to_gain(it.gain_db) / peak;
let peak = peaks.iter().fold(0f32, |m, (a, b)| m.max(a.abs()).max(b.abs()));
let gain = waveform_display_gain(peak, it.gain_db);
let mut mesh = egui::Mesh::default();
let dur_px = body.width().max(1.0);
for x in (clip.min.x.floor() as i32)..(clip.max.x.ceil() as i32) {
@ -550,6 +550,15 @@ fn draw_waveform(app: &mut FilmcraftApp, p: &egui::Painter, body: Rect, it: &Tra
}
}
/// Display gain for a clip's waveform: clip gain, plus normalisation of the source to full scale
/// so quiet recordings stay readable, but by at most +12 dB, so a near-silent track (room tone at
/// −50 dBFS, a silent film's empty audio stream) does not look like a loud one.
fn waveform_display_gain(source_peak: f32, clip_gain_db: f64) -> f32 {
const MAX_BOOST: f32 = 3.981_072; // +12 dB
let boost = (1.0 / source_peak.max(1e-9)).min(MAX_BOOST);
filmcraft_render::audio::db_to_gain(clip_gain_db) * boost
}
fn request_peaks(app: &mut FilmcraftApp, item: ItemId) -> Option<Arc<Vec<(f32, f32)>>> {
if let Some(p) = app.tl.peaks.lock().unwrap_or_else(|e| e.into_inner()).get(&item) {
return Some(p.clone());
@ -1611,3 +1620,26 @@ fn interact(app: &mut FilmcraftApp, ui: &mut egui::Ui, seq: &Sequence, layout: &
}
app.auto.add("timeline.tracks", layout.content, "tracks");
}
#[cfg(test)]
mod waveform_tests {
use super::waveform_display_gain;
fn db(g: f32) -> f32 {
20.0 * g.log10()
}
#[test]
fn normalisation_is_capped_for_near_silent_sources() {
// a −14 dBFS recording is normalised to full scale (+12 dB cap reached: −2 dBFS)
assert!((db(0.2 * waveform_display_gain(0.2, 0.0)) - (-2.0)).abs() < 0.1);
// a −3 dBFS recording is normalised exactly
assert!((db(0.708 * waveform_display_gain(0.708, 0.0))).abs() < 0.1);
// a −52 dBFS "silent" stream stays near the floor of the −48 dB display range
assert!(db(0.0025 * waveform_display_gain(0.0025, 0.0)) < -39.0);
// digital silence does not blow up
assert!(waveform_display_gain(0.0, 0.0).is_finite());
// clip gain still applies
assert!((db(waveform_display_gain(1.0, -6.0)) - (-6.0)).abs() < 0.1);
}
}