1use crate::Result;
2use orfail::Failure;
3
4#[derive(Debug, Default)]
5pub struct AudioData<B = Vec<u8>> {
6 spec: AudioSpec,
7 data: B,
8}
9
10impl AudioData<Vec<u8>> {
11 pub fn new(spec: AudioSpec) -> Self {
12 Self {
13 spec,
14 data: vec![0; spec.data_samples * spec.sample_format.bytes()],
15 }
16 }
17
18 #[inline]
19 pub fn write_sample(&mut self, i: usize, sample: impl Into<Sample>) {
20 let sample = sample.into();
21 match self.spec.sample_format {
22 SampleFormat::I16Be => {
23 self.data[i * 2..][..2].copy_from_slice(&sample.to_i16().to_be_bytes());
24 }
25 SampleFormat::I16Le => {
26 self.data[i * 2..][..2].copy_from_slice(&sample.to_i16().to_le_bytes());
27 }
28 SampleFormat::F32Be => {
29 self.data[i * 4..][..4].copy_from_slice(&sample.to_f32().to_be_bytes());
30 }
31 SampleFormat::F32Le => {
32 self.data[i * 4..][..4].copy_from_slice(&sample.to_f32().to_le_bytes());
33 }
34 }
35 }
36
37 pub fn bytes_mut(&mut self) -> &mut [u8] {
38 self.data.as_mut()
39 }
40
41 pub fn as_ref(&self) -> AudioData<&[u8]> {
42 AudioData {
43 spec: self.spec,
44 data: &self.data,
45 }
46 }
47}
48
49impl<B: AsRef<[u8]>> AudioData<B> {
50 pub fn spec(&self) -> AudioSpec {
51 self.spec
52 }
53
54 pub fn samples(&self) -> Samples {
55 Samples {
56 spec: self.spec,
57 data: self.data.as_ref(),
58 }
59 }
60
61 pub fn bytes(&self) -> &[u8] {
62 self.data.as_ref()
63 }
64}
65
66#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
67#[cfg_attr(
68 feature = "serde",
69 derive(serde::Serialize, serde::Deserialize),
70 serde(rename_all = "camelCase")
71)]
72pub struct AudioSpec {
73 pub sample_format: SampleFormat,
74 pub sample_rate: u16,
75 pub data_samples: usize,
76}
77
78impl AudioSpec {
79 pub const CHANNELS: u8 = 1;
80}
81
82#[derive(Debug)]
83pub struct Samples<'a> {
84 spec: AudioSpec,
85 data: &'a [u8],
86}
87
88impl<'a> Samples<'a> {
89 pub fn len(&self) -> usize {
90 self.spec.data_samples
91 }
92
93 pub fn is_empty(&self) -> bool {
94 self.len() == 0
95 }
96}
97
98impl<'a> Iterator for Samples<'a> {
99 type Item = Sample;
100
101 fn next(&mut self) -> Option<Self::Item> {
102 if self.data.is_empty() {
103 return None;
104 }
105
106 match self.spec.sample_format {
107 SampleFormat::I16Be => {
108 let v = i16::from_be_bytes([self.data[0], self.data[1]]);
109 self.data = &self.data[2..];
110 Some(Sample::I16(v))
111 }
112 SampleFormat::I16Le => {
113 let v = i16::from_le_bytes([self.data[0], self.data[1]]);
114 self.data = &self.data[2..];
115 Some(Sample::I16(v))
116 }
117 SampleFormat::F32Be => {
118 let v =
119 f32::from_be_bytes([self.data[0], self.data[1], self.data[2], self.data[3]]);
120 self.data = &self.data[4..];
121 Some(Sample::F32(v))
122 }
123 SampleFormat::F32Le => {
124 let v =
125 f32::from_le_bytes([self.data[0], self.data[1], self.data[2], self.data[3]]);
126 self.data = &self.data[4..];
127 Some(Sample::F32(v))
128 }
129 }
130 }
131}
132
133#[derive(Debug, Clone, Default, Copy, PartialEq, Eq, Hash)]
134#[cfg_attr(
135 feature = "serde",
136 derive(serde::Serialize, serde::Deserialize),
137 serde(rename_all = "UPPERCASE")
138)]
139pub enum SampleFormat {
140 #[default]
141 I16Be = 0,
142 I16Le = 1,
143 F32Be = 2,
144 F32Le = 3,
145}
146
147impl SampleFormat {
148 pub const fn bytes(self) -> usize {
149 match self {
150 SampleFormat::I16Be => 2,
151 SampleFormat::I16Le => 2,
152 SampleFormat::F32Be => 4,
153 SampleFormat::F32Le => 4,
154 }
155 }
156
157 pub const fn as_u8(self) -> u8 {
158 self as u8
159 }
160
161 pub fn from_u8(x: u8) -> Result<Self> {
162 match x {
163 0 => Ok(Self::I16Be),
164 1 => Ok(Self::I16Le),
165 2 => Ok(Self::F32Be),
166 3 => Ok(Self::F32Le),
167 _ => Err(Failure::new(format!("unknown audio sample format: {x}"))),
168 }
169 }
170}
171
172#[derive(Debug, Clone, Copy)]
173pub enum Sample {
174 I16(i16),
175 F32(f32),
176}
177
178impl Sample {
179 #[inline]
180 pub fn to_i16(self) -> i16 {
181 match self {
182 Sample::I16(v) => v,
183 Sample::F32(v) => {
184 let v = v.clamp(-1.0, 1.0);
185 if v < 0.0 {
186 (-v * f32::from(i16::MIN)) as i16
187 } else {
188 (v * f32::from(i16::MAX)) as i16
189 }
190 }
191 }
192 }
193
194 #[inline]
195 pub fn to_f32(self) -> f32 {
196 match self {
197 Sample::F32(v) => v,
198 Sample::I16(v) => {
199 if v < 0 {
200 -f32::from(v) / f32::from(i16::MIN)
201 } else {
202 f32::from(v) / f32::from(i16::MAX)
203 }
204 }
205 }
206 }
207}
208
209impl From<i16> for Sample {
210 fn from(value: i16) -> Self {
211 Self::I16(value)
212 }
213}
214
215impl From<f32> for Sample {
216 fn from(value: f32) -> Self {
217 Self::F32(value)
218 }
219}