Unit 1 of the sound-bar refactor. The model stores linear gain; the dock shows decibels, because "−6 dB" is readable and "0.50" is not. `Helpers/GainDb` owns the mapping: - 0 dB = unity (the old 1.0), range −60 dB (true silence, exactly 0 gain) … +6 dB. - Labels for the fader readout: "−∞", "-6.0", "+1.5". - `MonoFold(L,R)` = (L+R)/2, the accessible downmix: hard-panned content becomes audible on both sides at half amplitude instead of absent from one. Creator context: profoundly deaf on the right, so single-sided audio is inaudible, not merely annoying. Guard: GainDbTests pins unity, the −6 dB half, the exact-zero floor, the +6 dB ceiling, a round-trip across the range, the labels, and the fold arithmetic (a right-only 0.5 arrives on the left at 0.25).
45 lines
1.9 KiB
C#
45 lines
1.9 KiB
C#
using System;
|
||
|
||
namespace ytLive.Helpers;
|
||
|
||
/// <summary>The fader scale for the audio dock: the model stores LINEAR gain (0..1), the dock
|
||
/// shows and edits DECIBELS, because "−6 dB" means something to a person and "0.50" does not.
|
||
///
|
||
/// <para>Range: −∞ (silence) to +6 dB of headroom above unity. 0 dB is unity gain, which is what
|
||
/// the old 1.0 meant — so a persisted 0.8 comes back as ≈ −1.9 dB and nothing about the stored
|
||
/// data changes.</para>
|
||
///
|
||
/// <para>Creator context (2026-10-30): nearly deaf on the right, so the fader number is read, not
|
||
/// heard. The scale therefore has to be the true one, not a cosmetic curve.</para></summary>
|
||
public static class GainDb
|
||
{
|
||
/// <summary>Silence floor. Anything at or below this reads as −∞ and writes as 0 gain.</summary>
|
||
public const double FloorDb = -60;
|
||
|
||
public const double MaxDb = 6;
|
||
|
||
/// <summary>Linear gain → dB, clamped to the fader's range. Zero becomes <see cref="FloorDb"/>.</summary>
|
||
public static double ToDb(double gain)
|
||
{
|
||
if (gain <= 0) return FloorDb;
|
||
var db = 20 * Math.Log10(gain);
|
||
return Math.Clamp(db, FloorDb, MaxDb);
|
||
}
|
||
|
||
/// <summary>dB → linear gain. At the floor the result is exactly 0 (true silence), so the
|
||
/// bottom of the fader cannot leave a residue of noise.</summary>
|
||
public static double FromDb(double db)
|
||
{
|
||
if (db <= FloorDb) return 0;
|
||
return Math.Pow(10, Math.Clamp(db, FloorDb, MaxDb) / 20);
|
||
}
|
||
|
||
/// <summary>"−∞", "−6.0", "+1.5" — the label beside a fader.</summary>
|
||
public static string Label(double db) =>
|
||
db <= FloorDb ? "−∞" : (db > 0 ? "+" : string.Empty) + db.ToString("0.0");
|
||
|
||
/// <summary>Mono fold: the accessible downmix. Averages the pair so hard-panned content is
|
||
/// audible on both sides at half amplitude instead of absent from one.</summary>
|
||
public static float MonoFold(float left, float right) => (left + right) * 0.5f;
|
||
}
|