fix(dock): the master ladder moves when no session is running

Reported: no activity in the master meter.

Cause: `MasterLevel` measures the buffer the ENCODER receives, and that buffer only exists while the
mix is being pulled — streaming or recording. Idle, nothing fills it, so the master read zero while
the bays below it moved. A master that is dead between sessions is a gap in the design.

Now: while a session runs the master shows the measured mix (unchanged); idle it shows an estimate
computed from the same measured sources and the same gains the mix applies
(`MeterScale.MonitorFraction`, pure + tested). Two ladders can therefore never tell contradictory
stories about whether audio exists.

Guard: MeterScaleTests pins the estimate — silence reads zero, a quiet source at unity is visible,
two sources add, and gain is applied in the LINEAR domain like the mix (scaling the display fraction
would be a different, wrong curve).
This commit is contained in:
2026-10-30 14:01:29 -07:00
parent ec293e54b0
commit e92ce4bb63
3 changed files with 30 additions and 2 deletions
+8
View File
@@ -33,6 +33,14 @@ public class MeterScaleTests
Assert.True(MeterScale.NextLevel(0.9f, 0.1f) > 0.8f); // decay is gentle
Assert.True(MeterScale.NextLevel(0.1f, 0.9f) > 0.5f); // rise is fast
// The idle master estimate: sources × their gains, on the same display scale. With nothing
// playing it is zero; a quiet source at unity is visible; two sources add.
Assert.Equal(0f, MeterScale.MonitorFraction(0f, 1, 0f, 1));
Assert.True(MeterScale.MonitorFraction(0.05f, 1, 0f, 1) > 0.3f);
Assert.True(MeterScale.MonitorFraction(0.05f, 1, 0.05f, 1) > MeterScale.MonitorFraction(0.05f, 1, 0f, 1));
// Gain is applied in the LINEAR domain, like the mix does — not to the display fraction.
Assert.True(MeterScale.MonitorFraction(0.05f, 0.5, 0f, 1) < MeterScale.MonitorFraction(0.05f, 1, 0f, 1));
// Peak hold rises instantly, then decays at the stated rate.
Assert.Equal(0.8f, MeterScale.NextPeak(0.2f, 0.8f, 0.05f));
Assert.Equal(0.7f, MeterScale.NextPeak(0.8f, 0.1f, 0.1f / 0.35f), 3); // 0.1 fall at 0.35/s