Files
LlamaCasty/ytLive.Tests/MeterScaleTests.cs
T
gramps 0f62e55474 feat(audio): the segment meter control (unit 3 of the dock)
`Controls/SegmentMeter` draws a 24-segment ladder in ONE OnRender pass — no per-segment elements
updating on the UI thread, which is the difference between a meter and a UI thread tax. Level and
peak are display fractions (what was MEASURED), never gain settings; vertical for the bay ladders,
horizontal for the master strip.

Bands come from `Helpers/MeterScale` (nominal/caution/peak, DESIGN.md thresholds) and live as
dependencies of the control, so the painting logic is pure and testable: the band a segment paints
is the level it measured. Brushes resolve from the theme tokens via SetResourceReference, so the
ladder cannot drift from DESIGN.md.

Peak-hold is the reason the header exists: a bar that follows the moment hides clipping, and
clipping is the one audio fault that cannot be fixed after the stream.

Guard: MeterScaleTests — band edges (inclusive at −12 and −3, as the standard states the ranges),
the −60…0 display scale, and peak-hold rising instantly then decaying at 0.35/s.
2026-10-30 12:36:05 -07:00

36 lines
1.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Xunit;
using ytLive.Helpers;
namespace ytLive.Tests;
/// <summary>A segment ladder is only useful if the band it paints is the level it measured. The
/// thresholds are DESIGN.md's (nominal / caution / peak), and peak-hold is what makes clipping
/// visible — a bar that follows the moment hides the one audio fault that cannot be fixed later.
/// </summary>
public class MeterScaleTests
{
[Fact]
public void Bands_peak_hold_and_the_display_scale_follow_the_standard()
{
// Bands at the documented thresholds.
Assert.Equal(MeterBand.Nominal, MeterScale.BandFor(-30f));
Assert.Equal(MeterBand.Nominal, MeterScale.BandFor(-12.1f));
Assert.Equal(MeterBand.Caution, MeterScale.BandFor(-12f));
Assert.Equal(MeterBand.Caution, MeterScale.BandFor(-6f));
Assert.Equal(MeterBand.Peak, MeterScale.BandFor(-3f));
Assert.Equal(MeterBand.Peak, MeterScale.BandFor(0f));
// Display fraction: −60 dBFS is empty, 0 dBFS is full, −30 is halfway, and nothing escapes.
Assert.Equal(0f, MeterScale.ToFraction(-60f));
Assert.Equal(1f, MeterScale.ToFraction(0f));
Assert.Equal(0.5f, MeterScale.ToFraction(-30f), 4);
Assert.Equal(1f, MeterScale.ToFraction(+12f));
Assert.Equal(0f, MeterScale.ToFraction(-120f));
// 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
Assert.Equal(0f, MeterScale.NextPeak(0.1f, 0f, 10f)); // never negative
}
}