feat(dock): TRAX becomes a background level, not a channel strip

Creator ruling (2026-10-30): TRAX is background music and is controlled separately from desktop and
mic — so KISS it:

- TRAX loses its own ladder and slider. It is one number plus ±5 dB buttons, disabled at the ends
  (−60 dB floor, +6 dB ceiling).
- It STARTS at −50 dB, taken from the creator's own meter readings, and moves in 5 dB clicks. If that
  proves inaudible on their setup, six clicks lands at −20 — the buttons exist for exactly that, and
  `TraxDefaultDb` is one constant.
- Layout follows: Desktop's volume now sits directly beneath its ladder, and the TRAX row (name,
  play/pause, level) sits beneath that, inside the GAME bay. The bays are MIC | GAME+TRAX | LIP-SYNC.
- The metering tap on the player stays (it is how "is the music producing sound" is answered) but has
  no ladder of its own; the desktop bed already shows the music.

Guards updated: TraxBayTests now asserts the stepper wiring and that the row has NO SegmentMeter;
GameBayTests asserts the desktop fader sits below the desktop ladder.
This commit is contained in:
2026-10-30 13:46:05 -07:00
parent 93dc6592ac
commit ec293e54b0
6 changed files with 112 additions and 97 deletions
+4
View File
@@ -15,6 +15,10 @@ public class GameBayTests
{
var dock = SourceAssert.Text("Controls", "AudioDock.xaml");
Assert.Contains("Value=\"{Binding GameVolumeDb, Mode=TwoWay}\"", dock);
// Desktop volume sits directly beneath its meter (creator's layout ruling).
var desktopMeter = dock.IndexOf("Level=\"{Binding GameMeterFraction}\"", System.StringComparison.Ordinal);
var desktopFader = dock.IndexOf("Value=\"{Binding GameVolumeDb, Mode=TwoWay}\"", System.StringComparison.Ordinal);
Assert.True(desktopFader > desktopMeter, "the desktop fader belongs under the desktop ladder");
Assert.Contains("Level=\"{Binding GameMeterFraction}\"", dock);
Assert.Contains("Text=\"{Binding GameDuckLabel}\"", dock);
Assert.Contains("Visibility=\"{Binding IsGameDucking, Converter={StaticResource BoolToVis}}\"", dock);
+14 -7
View File
@@ -16,20 +16,25 @@ public class TraxBayTests
{
var dock = SourceAssert.Text("Controls", "AudioDock.xaml");
Assert.Contains("Text=\"{Binding TraxTrackLabel}\"", dock);
Assert.Contains("Value=\"{Binding TraxVolumeDb, Mode=TwoWay}\"", dock);
// KISS (creator 2026-10-30): background music is one number and two ±5 dB buttons, not a
// channel strip — and it has no ladder of its own, because the desktop bed already carries it.
Assert.Contains("Click=\"TraxStepDown_Click\"", dock);
Assert.Contains("Click=\"TraxStepUp_Click\"", dock);
Assert.Contains("IsEnabled=\"{Binding CanLowerTrax}\"", dock);
Assert.Contains("IsEnabled=\"{Binding CanRaiseTrax}\"", dock);
Assert.Contains("Text=\"{Binding TraxVolumeDbLabel}\"", dock);
Assert.Contains("Binding=\"{Binding IsMusicPlaying}\" Value=\"True\"", dock);
Assert.Contains("Click=\"TraxPlayPause_Click\"", dock);
// 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)
// The TRAX row lives under the desktop volume, inside the GAME bay.
var traxRow = dock[dock.IndexOf("Text=\"TRAX\"", System.StringComparison.Ordinal)
..dock.IndexOf("Text=\"LIP-SYNC\"", System.StringComparison.Ordinal)];
Assert.Contains("TraxTrackLabel", traxBay);
Assert.Contains("SegmentMeter", traxBay);
Assert.Contains("TraxMeterFraction", traxBay);
Assert.Contains("TraxTrackLabel", traxRow);
Assert.DoesNotContain("SegmentMeter", traxRow);
foreach (var name in new[] { "TraxVolumeDb", "TraxVolumeDbLabel", "TraxTrackLabel", "IsTraxDucking", "TraxMeterFraction" })
foreach (var name in new[] { "TraxVolumeDb", "TraxVolumeDbLabel", "TraxTrackLabel", "CanRaiseTrax", "CanLowerTrax" })
Assert.NotNull(typeof(MainViewModel).GetProperty(name));
// The player gained a real user level, separate from the mute-follow LocalGain.
@@ -37,7 +42,9 @@ public class TraxBayTests
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.
// It starts as background: −50 dB, and the ±5 dB steps are how it moves.
Assert.Equal(-50, MainViewModel.TraxDefaultDb);
Assert.Equal(5, MainViewModel.TraxStepDb);
Assert.Equal(0, GainDb.ToDb(1f), 6);
Assert.Contains("∞", GainDb.Label(GainDb.FloorDb)); // true silence, not "-60.0"
}