Unit 7. The bay shows the track name (left-click toggles playback, right-click opens the picker — the label stays the control), a play/pause button, the duck badge, and a dB level. No ladder here, deliberately: nothing measures the music bed, and a decorative ladder would break the measured-not-painted rule. A test asserts the bay has no SegmentMeter. The level is real: `ITraxPlayer.UserGain` is a new creator gain multiplied onto the fixed design volume, separate from `LocalGain` (which follows the desktop mute). The VM's `TraxVolumeDb` is the same dB scale as the other faders, so unity means the bed's design level.
190 lines
13 KiB
XML
190 lines
13 KiB
XML
<UserControl x:Class="ytLive.Controls.AudioDock"
|
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
xmlns:controls="clr-namespace:ytLive.Controls">
|
|
<!-- The sound bars. Replaces the empty bottom-bar spacer; collapses to the telemetry strip
|
|
on short windows (AudioDockLayout decides the height, not this file). -->
|
|
<Border x:Name="DockRoot" Background="{StaticResource Brush.SurfaceContainer}"
|
|
BorderBrush="{StaticResource Brush.Outline}" BorderThickness="0,1,0,0">
|
|
<Grid>
|
|
<Grid.RowDefinitions>
|
|
<!-- Master FIRST: during a live session attention is on the preview, so the
|
|
master strip sits against it and the bays hang below (creator, 2026-10-30). -->
|
|
<RowDefinition Height="36"/>
|
|
<RowDefinition Height="*"/>
|
|
</Grid.RowDefinitions>
|
|
|
|
<!-- Four bays: MIC | GAME | TRAX | SYNC. Filled in by the bay units. -->
|
|
<Grid x:Name="Bays" Grid.Row="1" Margin="8,4,8,6">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="*"/>
|
|
</Grid.ColumnDefinitions>
|
|
|
|
<Border Grid.Column="0" Background="{StaticResource Brush.SurfaceContainerLow}" CornerRadius="{StaticResource Radius.Sm}" Margin="0,0,4,0" Padding="10,6">
|
|
<Grid>
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="*"/>
|
|
</Grid.RowDefinitions>
|
|
|
|
<!-- Clicking the name opens the mic picker: the label is the control. -->
|
|
<Grid Grid.Row="0" Cursor="Hand" ToolTip="Change microphone"
|
|
MouseLeftButtonUp="MicLabel_MouseLeftButtonUp">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="Auto"/>
|
|
<ColumnDefinition Width="*"/>
|
|
</Grid.ColumnDefinitions>
|
|
<Border Background="{StaticResource Brush.SurfaceContainerHighest}" CornerRadius="{StaticResource Radius.Sm}" Padding="5,1">
|
|
<TextBlock Text="MIC 1" FontSize="9" FontWeight="Bold" Foreground="{StaticResource Brush.OnSurfaceVariant}"/>
|
|
</Border>
|
|
<TextBlock Grid.Column="1" Margin="6,0,0,0" FontSize="11" VerticalAlignment="Center"
|
|
TextTrimming="CharacterEllipsis"
|
|
Text="{Binding MicSourceName, TargetNullValue='No microphone'}"
|
|
Foreground="{StaticResource Brush.OnSurface}"/>
|
|
</Grid>
|
|
|
|
<controls:SegmentMeter Grid.Row="1" Height="10" Margin="0,6,0,0" Orientation="Horizontal"
|
|
Level="{Binding MicMeterFraction}" Segments="24"/>
|
|
|
|
<DockPanel Grid.Row="2" Margin="0,6,0,0" VerticalAlignment="Bottom">
|
|
<Button DockPanel.Dock="Left" Width="24" Height="20" Margin="0,0,6,0"
|
|
Style="{StaticResource YtButtonSecondary}" Padding="0"
|
|
Command="{Binding ToggleMicMuteCommand}" ToolTip="{Binding MicMuteText}">
|
|
<Ellipse Width="9" Height="9" Fill="{Binding MicStatusBrush}"/>
|
|
</Button>
|
|
<TextBlock DockPanel.Dock="Right" Width="56" TextAlignment="Right" FontSize="10"
|
|
FontFamily="{StaticResource FontFamily.Mono}" VerticalAlignment="Center"
|
|
Foreground="{StaticResource Brush.OnSurfaceVariant}"
|
|
Text="{Binding MicVolumeDbLabel}"/>
|
|
<Slider Minimum="-60" Maximum="6" SmallChange="0.5" LargeChange="3"
|
|
Value="{Binding MicVolumeDb, Mode=TwoWay}" VerticalAlignment="Center"/>
|
|
</DockPanel>
|
|
</Grid>
|
|
</Border>
|
|
<Border Grid.Column="1" Background="{StaticResource Brush.SurfaceContainerLow}" CornerRadius="{StaticResource Radius.Sm}" Margin="4,0" Padding="10,6">
|
|
<Grid>
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="*"/>
|
|
</Grid.RowDefinitions>
|
|
|
|
<Grid Grid.Row="0">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="Auto"/>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
</Grid.ColumnDefinitions>
|
|
<Border Background="{StaticResource Brush.SurfaceContainerHighest}" CornerRadius="{StaticResource Radius.Sm}" Padding="5,1">
|
|
<TextBlock Text="GAME / PC" FontSize="9" FontWeight="Bold" Foreground="{StaticResource Brush.OnSurfaceVariant}"/>
|
|
</Border>
|
|
<TextBlock Grid.Column="1" Margin="6,0,0,0" FontSize="11" VerticalAlignment="Center"
|
|
TextTrimming="CharacterEllipsis" Foreground="{StaticResource Brush.OnSurfaceVariant}"
|
|
Text="Desktop loopback"/>
|
|
<!-- The duck badge only exists while the duck is happening, and it carries
|
|
the gain the mixer actually applied. -->
|
|
<Border Grid.Column="2" Background="{StaticResource Brush.SurfaceContainerHighest}"
|
|
CornerRadius="{StaticResource Radius.Sm}" Padding="5,1"
|
|
Visibility="{Binding IsGameDucking, Converter={StaticResource BoolToVis}}">
|
|
<TextBlock FontSize="9" FontWeight="Bold" FontFamily="{StaticResource FontFamily.Mono}"
|
|
Foreground="{StaticResource Brush.Secondary}" Text="{Binding GameDuckLabel}"/>
|
|
</Border>
|
|
</Grid>
|
|
|
|
<controls:SegmentMeter Grid.Row="1" Height="10" Margin="0,6,0,0" Orientation="Horizontal"
|
|
Level="{Binding GameMeterFraction}" Segments="24"/>
|
|
|
|
<DockPanel Grid.Row="2" Margin="0,6,0,0" VerticalAlignment="Bottom">
|
|
<Button DockPanel.Dock="Left" Width="24" Height="20" Margin="0,0,6,0"
|
|
Style="{StaticResource YtButtonSecondary}" Padding="0"
|
|
Command="{Binding ToggleGameMuteCommand}" ToolTip="Mute desktop audio">
|
|
<Ellipse Width="9" Height="9" Fill="{Binding GameMeterBrush}"/>
|
|
</Button>
|
|
<TextBlock DockPanel.Dock="Right" Width="56" TextAlignment="Right" FontSize="10"
|
|
FontFamily="{StaticResource FontFamily.Mono}" VerticalAlignment="Center"
|
|
Foreground="{StaticResource Brush.OnSurfaceVariant}"
|
|
Text="{Binding GameVolumeDbLabel}"/>
|
|
<Slider Minimum="-60" Maximum="6" SmallChange="0.5" LargeChange="3"
|
|
Value="{Binding GameVolumeDb, Mode=TwoWay}" VerticalAlignment="Center"/>
|
|
</DockPanel>
|
|
</Grid>
|
|
</Border>
|
|
<Border Grid.Column="2" Background="{StaticResource Brush.SurfaceContainerLow}" CornerRadius="{StaticResource Radius.Sm}" Margin="4,0" Padding="10,6">
|
|
<Grid>
|
|
<Grid.RowDefinitions>
|
|
<RowDefinition Height="Auto"/>
|
|
<RowDefinition Height="*"/>
|
|
</Grid.RowDefinitions>
|
|
|
|
<Grid Grid.Row="0">
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width="Auto"/>
|
|
<ColumnDefinition Width="*"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
<ColumnDefinition Width="Auto"/>
|
|
</Grid.ColumnDefinitions>
|
|
<Border Background="{StaticResource Brush.SurfaceContainerHighest}" CornerRadius="{StaticResource Radius.Sm}" Padding="5,1">
|
|
<TextBlock Text="TRAX" FontSize="9" FontWeight="Bold" Foreground="{StaticResource Brush.OnSurfaceVariant}"/>
|
|
</Border>
|
|
<!-- The name is the control: left-click toggles play, right-click picks (§TRAX). -->
|
|
<TextBlock Grid.Column="1" Margin="6,0,0,0" FontSize="11" VerticalAlignment="Center"
|
|
TextTrimming="CharacterEllipsis" Foreground="{StaticResource Brush.OnSurface}"
|
|
Text="{Binding TraxTrackLabel}"
|
|
MouseLeftButtonUp="TraxLabel_MouseLeftButtonUp"
|
|
MouseRightButtonUp="TraxLabel_MouseRightButtonUp" Cursor="Hand"/>
|
|
<Button Grid.Column="2" Width="22" Height="18" Style="{StaticResource YtButtonSecondary}" Padding="0"
|
|
Margin="4,0,0,0" Click="TraxPlayPause_Click" ToolTip="{Binding TraxToolTip}">
|
|
<TextBlock FontSize="10" Foreground="{StaticResource Brush.OnSurface}">
|
|
<TextBlock.Style>
|
|
<Style TargetType="TextBlock">
|
|
<Setter Property="Text" Value="▶"/>
|
|
<Style.Triggers>
|
|
<DataTrigger Binding="{Binding IsMusicPlaying}" Value="True">
|
|
<Setter Property="Text" Value="❚❚"/>
|
|
</DataTrigger>
|
|
</Style.Triggers>
|
|
</Style>
|
|
</TextBlock.Style>
|
|
</TextBlock>
|
|
</Button>
|
|
<Border Grid.Column="3" Margin="4,0,0,0" Background="{StaticResource Brush.SurfaceContainerHighest}"
|
|
CornerRadius="{StaticResource Radius.Sm}" Padding="5,1"
|
|
Visibility="{Binding IsTraxDucking, Converter={StaticResource BoolToVis}}">
|
|
<TextBlock FontSize="9" FontWeight="Bold" FontFamily="{StaticResource FontFamily.Mono}"
|
|
Foreground="{StaticResource Brush.Secondary}" Text="DUCK"/>
|
|
</Border>
|
|
</Grid>
|
|
|
|
<DockPanel Grid.Row="1" Margin="0,6,0,0" VerticalAlignment="Bottom">
|
|
<TextBlock DockPanel.Dock="Right" Width="56" TextAlignment="Right" FontSize="10"
|
|
FontFamily="{StaticResource FontFamily.Mono}" VerticalAlignment="Center"
|
|
Foreground="{StaticResource Brush.OnSurfaceVariant}"
|
|
Text="{Binding TraxVolumeDbLabel}"/>
|
|
<Slider Minimum="-60" Maximum="6" SmallChange="0.5" LargeChange="3"
|
|
Value="{Binding TraxVolumeDb, Mode=TwoWay}" VerticalAlignment="Center"/>
|
|
</DockPanel>
|
|
</Grid>
|
|
</Border>
|
|
<Border Grid.Column="3" Background="{StaticResource Brush.SurfaceContainerLow}" CornerRadius="{StaticResource Radius.Sm}" Margin="4,0,0,0" Padding="10,6">
|
|
<StackPanel>
|
|
<TextBlock Text="LIP-SYNC" FontSize="10" FontWeight="SemiBold" Foreground="{StaticResource Brush.OnSurfaceVariant}"/>
|
|
<TextBlock x:Name="SyncBayBody" Text="—" FontSize="11" Foreground="{StaticResource Brush.OnSurfaceDisabled}"/>
|
|
</StackPanel>
|
|
</Border>
|
|
</Grid>
|
|
|
|
<!-- Master strip: always visible, even collapsed — it is the telemetry line. -->
|
|
<Border x:Name="MasterStrip" Grid.Row="0" Background="{StaticResource Brush.SurfaceContainerLowest}" Padding="12,0">
|
|
<DockPanel VerticalAlignment="Center">
|
|
<TextBlock DockPanel.Dock="Left" Text="MASTER" FontSize="10" FontWeight="SemiBold"
|
|
Foreground="{StaticResource Brush.OnSurfaceVariant}" VerticalAlignment="Center"/>
|
|
</DockPanel>
|
|
</Border>
|
|
</Grid>
|
|
</Border>
|
|
</UserControl>
|