1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
bitflags::bitflags! {
/// Speaker channel presence flags, byte 1 of the Speaker Allocation Data Block.
///
/// | Bit | Mask | Channels |
/// |-----|--------|---------------------------------|
/// | 7 | `0x80` | FLW/FRW (Front Left/Right Wide) |
/// | 6 | `0x40` | RLC/RRC (Rear Left/Right Center)|
/// | 5 | `0x20` | FLC/FRC (Front Left/Right Ctr) |
/// | 4 | `0x10` | BC (Back Center) |
/// | 3 | `0x08` | BL/BR (Back Left/Right) |
/// | 2 | `0x04` | FC (Front Center) |
/// | 1 | `0x02` | LFE1 (Low-Frequency Effects 1) |
/// | 0 | `0x01` | FL/FR (Front Left/Right) |
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SpeakerAllocationFlags: u8 {
/// Front Left / Front Right channels.
const FL_FR = 0x01;
/// Low-Frequency Effects channel 1.
const LFE1 = 0x02;
/// Front Center channel.
const FC = 0x04;
/// Back Left / Back Right channels.
const BL_BR = 0x08;
/// Back Center channel.
const BC = 0x10;
/// Front Left Center / Front Right Center channels.
const FLC_FRC = 0x20;
/// Rear Left Center / Rear Right Center channels.
const RLC_RRC = 0x40;
/// Front Left Wide / Front Right Wide channels.
const FLW_FRW = 0x80;
}
}
bitflags::bitflags! {
/// Speaker channel presence flags, byte 2 of the Speaker Allocation Data Block.
///
/// | Bit | Mask | Channels |
/// |-----|--------|------------------------------------|
/// | 7 | `0x80` | TpSiL/TpSiR (Top Side Left/Right) |
/// | 6 | `0x40` | SiL/SiR (Side Left/Right) |
/// | 5 | `0x20` | TpBC (Top Back Center) |
/// | 4 | `0x10` | LFE2 (Low-Frequency Effects 2) |
/// | 3 | `0x08` | LS/RS (Left/Right Surround) |
/// | 2 | `0x04` | TpFC (Top Front Center) |
/// | 1 | `0x02` | TpC (Top Center) |
/// | 0 | `0x01` | TpFL/TpFR (Top Front Left/Right) |
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SpeakerAllocationFlags2: u8 {
/// Top Front Left / Top Front Right channels.
const TP_FL_FR = 0x01;
/// Top Center channel.
const TP_C = 0x02;
/// Top Front Center channel.
const TP_FC = 0x04;
/// Left Surround / Right Surround channels.
const LS_RS = 0x08;
/// Low-Frequency Effects channel 2.
const LFE2 = 0x10;
/// Top Back Center channel.
const TP_BC = 0x20;
/// Side Left / Side Right channels.
const SI_L_SI_R = 0x40;
/// Top Side Left / Top Side Right channels.
const TP_SI_L_TP_SI_R = 0x80;
}
}
bitflags::bitflags! {
/// Speaker channel presence flags, byte 3 of the Speaker Allocation Data Block.
///
/// | Bit | Mask | Channels |
/// |-----|--------|---------------------------------------|
/// | 3 | `0x08` | TpLS/TpRS (Top Left/Right Surround) |
/// | 2 | `0x04` | BtFL/BtFR (Bottom Front Left/Right) |
/// | 1 | `0x02` | BtFC (Bottom Front Center) |
/// | 0 | `0x01` | TpBL/TpBR (Top Back Left/Right) |
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SpeakerAllocationFlags3: u8 {
/// Top Back Left / Top Back Right channels.
const TP_BL_TP_BR = 0x01;
/// Bottom Front Center channel.
const BT_FC = 0x02;
/// Bottom Front Left / Bottom Front Right channels.
const BT_FL_BT_FR = 0x04;
/// Top Left Surround / Top Right Surround channels.
const TP_LS_TP_RS = 0x08;
}
}
/// Decoded Speaker Allocation Data Block (standard tag `0x04`).
#[non_exhaustive]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SpeakerAllocation {
/// Channels from byte 1 (core speaker channels).
pub channels: SpeakerAllocationFlags,
/// Channels from byte 2 (extended — top/surround/LFE2).
pub channels_2: SpeakerAllocationFlags2,
/// Channels from byte 3 (extended — top-back/bottom-front).
pub channels_3: SpeakerAllocationFlags3,
}
impl SpeakerAllocation {
/// Constructs a `SpeakerAllocation`.
pub fn new(
channels: SpeakerAllocationFlags,
channels_2: SpeakerAllocationFlags2,
channels_3: SpeakerAllocationFlags3,
) -> Self {
Self {
channels,
channels_2,
channels_3,
}
}
}
/// Decoded Room Configuration Data Block (extended tag `0x13`).
///
/// Describes the number of loudspeakers in the listening room and whether
/// individual speaker locations are provided in an accompanying
/// Speaker Location Data Block (extended tag `0x14`).
#[non_exhaustive]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RoomConfigurationBlock {
/// Number of loudspeakers in the room (bits 4:0). `0` means not specified.
pub speaker_count: u8,
/// If `true`, individual speaker location entries are present in an
/// accompanying Speaker Location Data Block (extended tag `0x14`).
pub has_speaker_locations: bool,
}
impl RoomConfigurationBlock {
/// Constructs a `RoomConfigurationBlock`.
pub fn new(speaker_count: u8, has_speaker_locations: bool) -> Self {
Self {
speaker_count,
has_speaker_locations,
}
}
}
/// A single speaker location entry from the Speaker Location Data Block
/// (extended tag `0x14`).
///
/// Each entry is two bytes: a channel assignment and a normalized distance
/// from the listener (0 = closest, 255 = furthest).
#[non_exhaustive]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SpeakerLocationEntry {
/// Channel assignment code (speaker role).
///
/// Values follow the CTA-861-I Table 49 channel assignment codes
/// (e.g. `0x00` = FL/FR, `0x01` = LFE1, `0x02` = FC, etc.).
pub channel_assignment: u8,
/// Normalized distance from the listener position.
///
/// `0` = at or very close to the listener; `255` = furthest.
/// The absolute distance is not encoded.
pub distance: u8,
}
impl SpeakerLocationEntry {
/// Constructs a `SpeakerLocationEntry`.
pub fn new(channel_assignment: u8, distance: u8) -> Self {
Self {
channel_assignment,
distance,
}
}
}