diff --git a/src/Dragon-ISO.Engine/Pipeline/AudioPeakComputer.cs b/src/Dragon-ISO.Engine/Pipeline/AudioPeakComputer.cs index c011ff8..fc7b599 100644 --- a/src/Dragon-ISO.Engine/Pipeline/AudioPeakComputer.cs +++ b/src/Dragon-ISO.Engine/Pipeline/AudioPeakComputer.cs @@ -5,29 +5,34 @@ namespace DragonISO.Engine.Pipeline; /// /// Computes a single peak amplitude (in [0.0, 1.0]) from one NDI audio frame. /// -/// NDI 6's preferred audio format is NDIlib_FourCC_audio_type_FLTP — +/// NDI 6's preferred audio format is NDIlib_FourCC_audio_type_FLTP — /// 32-bit IEEE float, planar (one contiguous chunk per channel). Values are /// nominally normalized to [-1, 1]; brief excursions past 1 during transient /// clipping are clamped here. We compute a max-absolute peak across every /// sample of every channel rather than RMS so the UI VU bar reads -/// "loudest part of the buffer" — the same convention OBS / Resolve / Studio +/// "loudest part of the buffer" — the same convention OBS / Resolve / Studio /// Monitor use for their meters. /// /// Pulled out of so the math is unit-testable /// without an NDI runtime; the heavy work (FLTP decode) runs entirely on /// managed memory the caller has already copied across the P/Invoke /// boundary, so tests exercise the same code path that production does. +/// +/// FourCC values are packed little-endian, matching the NDI SDK and +/// 's video FourCCs: the first ASCII +/// character occupies the least-significant byte. So 'P','C','M','s' +/// is 0x73('s')4D('M')43('C')50('P') = 0x734D4350. /// public static class AudioPeakComputer { - /// FourCC for FLTP — 32-bit float, planar layout. 'F','L','T','p'. + /// FourCC for FLTP — 32-bit float, planar layout. 'F','L','T','p'. public const uint FourCC_FLTP = 0x70544c46; - /// FourCC for FLT — 32-bit float, interleaved. 'F','L','T',' '. Rarely seen but cheap to handle. + /// FourCC for FLT — 32-bit float, interleaved. 'F','L','T',' '. Rarely seen but cheap to handle. public const uint FourCC_FLT = 0x20544c46; /// FourCC for PCM 16-bit signed integer, interleaved. Some legacy senders use this. 'P','C','M','s'. - public const uint FourCC_PCMs16 = 0x73334d50; + public const uint FourCC_PCMs16 = 0x734D4350; /// /// Returns the largest absolute sample value found in the buffer, @@ -38,7 +43,7 @@ public static class AudioPeakComputer /// The NDI audio FourCC (see the constants on this class). /// /// Total sample count across all channels (e.g. no_samples * no_channels - /// for FLTP — channels are concatenated planes, but every sample contributes). + /// for FLTP — channels are concatenated planes, but every sample contributes). /// public static double ComputePeak(ReadOnlySpan data, uint fourCC, int totalSamples) { @@ -48,7 +53,7 @@ public static class AudioPeakComputer { FourCC_FLTP or FourCC_FLT => ComputePeakFloat32(data, totalSamples), FourCC_PCMs16 => ComputePeakInt16(data, totalSamples), - _ => 0.0, // unknown format — surface silence rather than throw + _ => 0.0, // unknown format — surface silence rather than throw }; } @@ -56,7 +61,7 @@ public static class AudioPeakComputer { // 4 bytes per sample. Cap by what's actually in the buffer in case // the caller's totalSamples disagrees with the byte length (defensive - // — a misreporting source shouldn't take down the receiver loop). + // — a misreporting source shouldn't take down the receiver loop). var available = Math.Min(totalSamples, data.Length / 4); if (available <= 0) return 0.0;