feat(dock): TRAX gets its own ladder — measured at the player's output

Creator: "why is there no meter for when trax is playing?"

Routing answer: TRAX rides the desktop loopback, so it already moved the GAME ladder — there was no
separate TRAX signal in the mix. But that ladder cannot answer the question a deaf creator actually
has: "is the music producing sound at all?" The play glyph cannot either — an open file with a dead
decoder still reports Playing.

So the player now measures its own output: \`MusicPlayer\` wraps the volume stage in an NAudio
\`MeteringSampleProvider\` and exposes \`Level\`; \`ITraxPlayer.Level\` keeps the fake honest. The VM maps
it through the same display scale (\`TraxMeterFraction\`), zeroed when not playing, and the TRAX bay
carries a 24-segment ladder above its fader.

This reverses my earlier "no ladder, nothing honest to show" — the honest thing arrived with a real
measurement. TraxBayTests flipped accordingly (it now asserts the ladder AND its source).
This commit is contained in:
2026-10-30 13:22:13 -07:00
parent 8aa483f933
commit a54149bd7c
7 changed files with 32 additions and 5 deletions
+6 -3
View File
@@ -21,17 +21,20 @@ public class TraxBayTests
Assert.Contains("Binding=\"{Binding IsMusicPlaying}\" Value=\"True\"", dock);
Assert.Contains("Click=\"TraxPlayPause_Click\"", dock);
// No ladder in the TRAX bay: nothing measures the bed, so there is nothing honest to show.
// The bay DOES carry a ladder now — the player measures its own output, so "is music making
// sound" is answerable without hearing it (a play glyph cannot answer that).
var traxBay = dock[dock.IndexOf("Text=\"TRAX\"", System.StringComparison.Ordinal)
..dock.IndexOf("Text=\"LIP-SYNC\"", System.StringComparison.Ordinal)];
Assert.Contains("TraxTrackLabel", traxBay);
Assert.DoesNotContain("SegmentMeter", traxBay);
Assert.Contains("SegmentMeter", traxBay);
Assert.Contains("TraxMeterFraction", traxBay);
foreach (var name in new[] { "TraxVolumeDb", "TraxVolumeDbLabel", "TraxTrackLabel", "IsTraxDucking" })
foreach (var name in new[] { "TraxVolumeDb", "TraxVolumeDbLabel", "TraxTrackLabel", "IsTraxDucking", "TraxMeterFraction" })
Assert.NotNull(typeof(MainViewModel).GetProperty(name));
// The player gained a real user level, separate from the mute-follow LocalGain.
Assert.NotNull(typeof(ITraxPlayer).GetProperty("UserGain"));
Assert.NotNull(typeof(ITraxPlayer).GetProperty("Level"));
Assert.NotNull(typeof(MusicPlayer).GetProperty("UserGain"));
// Unity means the bed's design level, and the fader's scale is the same one as the others.