1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
4#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
5pub enum AudioFormat {
6 PcmS16le,
7 PcmS24le,
8 PcmS24le4,
9 PcmS32le,
10 PcmF32le,
11 DsdU8,
12 DsdU16le,
13 DsdU32le,
14 Flac,
15 Opus,
16}
17
18impl AudioFormat {
19 pub fn wire_id(self) -> u8 {
20 match self {
21 Self::PcmS16le => 0x01,
22 Self::PcmS24le => 0x02,
23 Self::PcmS24le4 => 0x03,
24 Self::PcmS32le => 0x04,
25 Self::PcmF32le => 0x05,
26 Self::DsdU8 => 0x10,
27 Self::DsdU16le => 0x11,
28 Self::DsdU32le => 0x12,
29 Self::Flac => 0x20,
30 Self::Opus => 0x21,
31 }
32 }
33
34 pub fn from_wire_id(id: u8) -> Option<Self> {
35 match id {
36 0x01 => Some(Self::PcmS16le),
37 0x02 => Some(Self::PcmS24le),
38 0x03 => Some(Self::PcmS24le4),
39 0x04 => Some(Self::PcmS32le),
40 0x05 => Some(Self::PcmF32le),
41 0x10 => Some(Self::DsdU8),
42 0x11 => Some(Self::DsdU16le),
43 0x12 => Some(Self::DsdU32le),
44 0x20 => Some(Self::Flac),
45 0x21 => Some(Self::Opus),
46 _ => None,
47 }
48 }
49
50 pub fn is_pcm(self) -> bool {
51 matches!(
52 self,
53 Self::PcmS16le | Self::PcmS24le | Self::PcmS24le4 | Self::PcmS32le | Self::PcmF32le
54 )
55 }
56
57 pub fn is_dsd(self) -> bool {
58 matches!(self, Self::DsdU8 | Self::DsdU16le | Self::DsdU32le)
59 }
60
61 pub fn is_compressed(self) -> bool {
62 matches!(self, Self::Flac | Self::Opus)
63 }
64
65 pub fn bytes_per_sample(self) -> Option<usize> {
66 match self {
67 Self::PcmS16le => Some(2),
68 Self::PcmS24le => Some(3),
69 Self::PcmS24le4 | Self::PcmS32le | Self::PcmF32le => Some(4),
70 _ => None,
71 }
72 }
73}
74
75impl std::fmt::Display for AudioFormat {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 match self {
78 Self::PcmS16le => write!(f, "PCM_S16LE"),
79 Self::PcmS24le => write!(f, "PCM_S24LE"),
80 Self::PcmS24le4 => write!(f, "PCM_S24LE4"),
81 Self::PcmS32le => write!(f, "PCM_S32LE"),
82 Self::PcmF32le => write!(f, "PCM_F32LE"),
83 Self::DsdU8 => write!(f, "DSD_U8"),
84 Self::DsdU16le => write!(f, "DSD_U16LE"),
85 Self::DsdU32le => write!(f, "DSD_U32LE"),
86 Self::Flac => write!(f, "FLAC"),
87 Self::Opus => write!(f, "OPUS"),
88 }
89 }
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
93#[serde(rename_all = "snake_case")]
94pub enum ChannelLayout {
95 Mono,
96 Stereo,
97 #[serde(rename = "2.1")]
98 TwoPointOne,
99 Quad,
100 #[serde(rename = "5.1")]
101 FivePointOne,
102 #[serde(rename = "7.1")]
103 SevenPointOne,
104}
105
106impl ChannelLayout {
107 pub fn channel_count(self) -> u8 {
108 match self {
109 Self::Mono => 1,
110 Self::Stereo => 2,
111 Self::TwoPointOne => 3,
112 Self::Quad => 4,
113 Self::FivePointOne => 6,
114 Self::SevenPointOne => 8,
115 }
116 }
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
120pub enum DsdRate {
121 Dsd64 = 64,
122 Dsd128 = 128,
123 Dsd256 = 256,
124 Dsd512 = 512,
125}
126
127impl DsdRate {
128 pub fn bitstream_rate_hz(self) -> u64 {
129 match self {
130 Self::Dsd64 => 2_822_400,
131 Self::Dsd128 => 5_644_800,
132 Self::Dsd256 => 11_289_600,
133 Self::Dsd512 => 22_579_200,
134 }
135 }
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139pub enum SampleRateFamily {
140 F44100,
141 F48000,
142}
143
144impl SampleRateFamily {
145 pub fn of(rate: u32) -> Option<Self> {
146 const F441: [u32; 5] = [44100, 88200, 176400, 352800, 705600];
147 const F480: [u32; 5] = [48000, 96000, 192000, 384000, 768000];
148 if F441.contains(&rate) {
149 Some(Self::F44100)
150 } else if F480.contains(&rate) {
151 Some(Self::F48000)
152 } else {
153 None
154 }
155 }
156
157 pub fn rates(self) -> &'static [u32] {
158 match self {
159 Self::F44100 => &[44100, 88200, 176400, 352800, 705600],
160 Self::F48000 => &[48000, 96000, 192000, 384000, 768000],
161 }
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn wire_id_roundtrip() {
171 for fmt in [
172 AudioFormat::PcmS16le,
173 AudioFormat::PcmS24le,
174 AudioFormat::PcmS24le4,
175 AudioFormat::PcmS32le,
176 AudioFormat::PcmF32le,
177 AudioFormat::DsdU8,
178 AudioFormat::DsdU16le,
179 AudioFormat::DsdU32le,
180 AudioFormat::Flac,
181 AudioFormat::Opus,
182 ] {
183 assert_eq!(AudioFormat::from_wire_id(fmt.wire_id()), Some(fmt));
184 }
185 }
186
187 #[test]
188 fn sample_rate_family() {
189 assert_eq!(SampleRateFamily::of(44100), Some(SampleRateFamily::F44100));
190 assert_eq!(SampleRateFamily::of(192000), Some(SampleRateFamily::F48000));
191 assert_eq!(SampleRateFamily::of(50000), None);
192 }
193}