Files
LlamaCasty/Helpers/AudioFold.cs
T
gramps 5889d71db6 feat(dock): master strip + MONO output (the accessibility switch)
Unit 9, the one that matters most for this creator.

MASTER STRIP (top, nearest the preview):
- one ladder fed by the MEASURED mix — `AudioMixer` now measures the buffer the encoder receives
  (`MasterLevel`, `MasterImbalanceDb`), so the master cannot show a source instead of the output
- `-12.4 dB` readout, and ONE L/R flag that appears above a 6 dB gap instead of a second ladder
- bitrate / FPS / dropped / duration from the existing health poll

MONO OUTPUT:
- `AudioFold.ToMono` averages each stereo pair into both channels, applied after the limiter and
  the sync delay, so the stream AND the recording get what was folded
- `MonoOutput` is persisted (`Audio.MonoOutput`) and restored at startup: an accessibility switch
  that resets each session is an accessibility failure
- one click in the strip, remembered forever

Guard: AudioFoldTests (hard-left reaches the right at half amplitude, hard-right — the inaudible
case — reaches the left, centred material keeps its level, mono buffers untouched) and
MasterStripTests (the strip binds the measured mix + the switch, the store round-trips it, and the
fold is the tested helper rather than new arithmetic). 33 audio tests green.
2026-10-30 13:18:23 -07:00

28 lines
1.2 KiB
C#

using System;
namespace ytLive.Helpers;
/// <summary>The accessible mono fold: average each stereo pair into both channels.
///
/// <para>Creator context (2026-10-30): profoundly deaf on the right. Hard-panned content is not
/// quieter to them, it is ABSENT, so a single-sided game or clip is unusable. Folding to mono puts
/// everything on both sides — the loudness cost is honest (a one-sided signal arrives at half
/// amplitude) and speech is unaffected because the mic is already centred.</para></summary>
public static class AudioFold
{
/// <summary>Folds an interleaved buffer in place. Mono buffers are left untouched: there is
/// nothing to combine, and rewriting them would be a silent no-op that hides a caller's bug.</summary>
public static void ToMono(Span<float> interleaved, int channels)
{
if (channels < 2) return;
var frames = interleaved.Length / channels;
for (var frame = 0; frame < frames; frame++)
{
var offset = frame * channels;
var mono = (interleaved[offset] + interleaved[offset + 1]) * 0.5f;
interleaved[offset] = mono;
interleaved[offset + 1] = mono;
}
}
}