using System; namespace ytLive.Helpers; /// Which colour band a level falls in (DESIGN.md meter thresholds). public enum MeterBand { Nominal, Caution, Peak, } /// The mathematics of the dock's segment meter, kept out of the control so it can be /// tested: a segment ladder is only honest if the band it paints is the level it measured. /// /// Bands follow DESIGN.md: nominal to −12 dB, caution to −3 dB, peak above. The display /// fraction spreads −60…0 dBFS across 0…1 — the same scale AudioLevelMeter.ToDisplay uses, /// so the ladder and the old bars cannot disagree. public static class MeterScale { public const float FloorDb = -60f; public const float CautionDb = -12f; public const float PeakDb = -3f; /// dBFS → 0…1 across the whole ladder. public static float ToFraction(float dbfs) => Math.Clamp(1f + Math.Clamp(dbfs, FloorDb, 0f) / 60f, 0f, 1f); /// The band boundaries are INCLUSIVE at the bottom edge (a meter reading exactly /// −12.0 dB is cautious, exactly −3.0 is peaking), matching the ranges as DESIGN.md states /// them: "−12 … −3" and "−3 … 0+". public static MeterBand BandFor(float dbfs) => dbfs >= PeakDb ? MeterBand.Peak : dbfs >= CautionDb ? MeterBand.Caution : MeterBand.Nominal; /// Ballistics for a level: reach a new peak quickly, fall back gently. Raw per-block /// peaks sampled by a UI timer look like a stutter; this is what makes the mic feel fluid, and /// TRAX gets the same curve so the two ladders move alike. public static float NextLevel(float current, float incoming, float attack = 0.6f, float decay = 0.12f) { var alpha = incoming > current ? attack : decay; return current + (incoming - current) * alpha; } /// Peak hold: jumps up instantly to a new maximum and falls back at /// — a moment-to-moment bar hides clipping, which is the one /// audio fault that cannot be fixed afterwards. public static float NextPeak(float held, float incoming, float seconds, float decayPerSecond = 0.35f) { if (incoming >= held) return incoming; return Math.Max(0f, held - decayPerSecond * Math.Max(0f, seconds)); } }