broadcast_loudness/channel_layout.rs
1//! Channel layout and per-channel weighting (ITU-R BS.1770-5 §Annex 1, Table 3).
2//!
3//! Each layout carries the BS.1770 channel-weighting coefficients G_i.
4//! The LFE channel is always excluded from measurement (weight = 0.0).
5
6use broadcast_common::impl_spec_display;
7
8/// Channel layout defining the set of channels to measure and their
9/// BS.1770-5 per-channel weighting coefficients G_i.
10///
11/// See ITU-R BS.1770-5 Annex 1 Table 3.
12#[derive(Debug, Clone, Copy, PartialEq)]
13#[non_exhaustive]
14pub enum ChannelLayout {
15 /// Mono (centre channel): 1 channel, G = 1.0.
16 Mono,
17 /// Stereo (left, right): 2 channels, G_L = 1.0, G_R = 1.0.
18 Stereo,
19 /// 5.1 surround (L, R, C, LFE, Ls, Rs): 6 channels, LFE excluded.
20 /// G_L=1.0, G_R=1.0, G_C=1.0, G_Ls=1.41, G_Rs=1.41, G_LFE=0.0.
21 Surround51,
22 /// Custom channel count with explicit per-channel weights.
23 /// `weights[i]` is G_i for channel `i`.
24 Custom {
25 /// Per-channel weighting coefficients (length = channel count).
26 weights: &'static [f64],
27 },
28}
29
30impl ChannelLayout {
31 /// Number of audio channels (including LFE if present).
32 #[must_use]
33 pub fn channel_count(&self) -> usize {
34 match self {
35 Self::Mono => 1,
36 Self::Stereo => 2,
37 Self::Surround51 => 6,
38 Self::Custom { weights } => weights.len(),
39 }
40 }
41
42 /// BS.1770-5 weighting coefficient G_i for channel `index`.
43 ///
44 /// Returns 0.0 for LFE channels (excluded from measurement).
45 #[must_use]
46 pub fn weight(&self, index: usize) -> f64 {
47 match self {
48 Self::Mono => 1.0,
49 Self::Stereo => {
50 match index {
51 0 => 1.0, // L
52 1 => 1.0, // R
53 _ => 0.0,
54 }
55 }
56 Self::Surround51 => {
57 match index {
58 0 => 1.0, // L
59 1 => 1.0, // R
60 2 => 1.0, // C
61 3 => 0.0, // LFE (excluded)
62 4 => 1.41, // Ls
63 5 => 1.41, // Rs
64 _ => 0.0,
65 }
66 }
67 Self::Custom { weights } => weights.get(index).copied().unwrap_or(0.0),
68 }
69 }
70
71 /// Display name for this layout.
72 #[must_use]
73 pub fn name(&self) -> &'static str {
74 match self {
75 Self::Mono => "Mono",
76 Self::Stereo => "Stereo",
77 Self::Surround51 => "5.1 Surround",
78 Self::Custom { .. } => "Custom",
79 }
80 }
81}
82
83impl_spec_display!(ChannelLayout);