feat(dock): the GAME bay — dB fader, measured ladder, mute, real duck badge

Unit 6. Mirrors the mic bay for the desktop/game bed, plus the badge that matters to a creator who
cannot hear the duck: it shows while the ducker is actually attenuating, and it prints the gain the
mixer applied (−12.0 DUCK by design).

- `AudioMixer.DuckGain` exposes `AutoDucker.CurrentGain` instead of leaving it internal.
- VM: `GameVolumeDb` / `GameVolumeDbLabel` (fader face), `GameMeterFraction` (measured level),
  `IsGameDucking` + `GameDuckLabel` refreshed on the level tick — the same moment the ducker runs,
  so the badge cannot lag behind the mix.
- The bay: header chip + source, ladder, mute dot (uses the meter band, so mute reads at a glance),
  dB readout, fader.

Guard: GameBayTests — the dock binds all four, `AutoDucker.DuckGain` is −12.04 dB and the label is
produced through the same dB scale as the faders, and the mixer property exists so the badge cannot
become a hardcoded number.
This commit is contained in:
2026-10-30 13:12:10 -07:00
parent 3524ede480
commit a1d8e761ea
4 changed files with 122 additions and 4 deletions
+33
View File
@@ -0,0 +1,33 @@
using Xunit;
using ytLive.Helpers;
using ytLive.Services.Audio;
using ytLive.ViewModels;
namespace ytLive.Tests;
/// <summary>The GAME bay's badge must carry the gain the mixer actually applied — a duck indicator
/// that is not the real value is decoration, and this creator cannot hear whether it happened.
/// </summary>
public class GameBayTests
{
[Fact]
public void The_game_bay_binds_the_db_fader_and_a_real_duck_readout()
{
var dock = SourceAssert.Text("Controls", "AudioDock.xaml");
Assert.Contains("Value=\"{Binding GameVolumeDb, Mode=TwoWay}\"", dock);
Assert.Contains("Level=\"{Binding GameMeterFraction}\"", dock);
Assert.Contains("Text=\"{Binding GameDuckLabel}\"", dock);
Assert.Contains("Visibility=\"{Binding IsGameDucking, Converter={StaticResource BoolToVis}}\"", dock);
foreach (var name in new[] { "GameVolumeDb", "GameVolumeDbLabel", "GameMeterFraction", "IsGameDucking", "GameDuckLabel" })
Assert.NotNull(typeof(MainViewModel).GetProperty(name));
// The badge's number is the mixer's ducker, not a copy: the duck is −12.04 dB by design,
// and the label is produced from the live gain through the same dB scale as the faders.
Assert.Equal(-12.04, GainDb.ToDb(AutoDucker.DuckGain), 1);
Assert.Equal("-12.0 DUCK", GainDb.Label(GainDb.ToDb(AutoDucker.DuckGain)) + " DUCK");
// And the mixer exposes that gain rather than hiding it.
Assert.NotNull(typeof(AudioMixer).GetProperty("DuckGain"));
}
}