1use serde::Serialize;
4
5#[derive(Clone, Debug, PartialEq)]
7pub struct AudioBuffer {
8 pub sample_rate: u32,
9 pub data: Vec<Vec<f32>>,
10}
11
12impl AudioBuffer {
13 pub fn new(sample_rate: u32, channels: usize, frames: usize) -> Self {
15 AudioBuffer { sample_rate, data: vec![vec![0.0; frames]; channels.max(1)] }
16 }
17
18 pub fn from_planar(sample_rate: u32, mut data: Vec<Vec<f32>>) -> Self {
20 if data.is_empty() {
21 data.push(Vec::new());
22 }
23 let n = data.iter().map(|c| c.len()).max().unwrap_or(0);
24 for c in &mut data {
25 c.resize(n, 0.0);
26 }
27 AudioBuffer { sample_rate, data }
28 }
29
30 pub fn from_mono(sample_rate: u32, samples: Vec<f32>) -> Self {
31 AudioBuffer { sample_rate, data: vec![samples] }
32 }
33
34 pub fn from_interleaved(sample_rate: u32, channels: usize, samples: &[f32]) -> Self {
35 let channels = channels.max(1);
36 let frames = samples.len() / channels;
37 let mut data = vec![Vec::with_capacity(frames); channels];
38 for f in 0..frames {
39 for (c, ch) in data.iter_mut().enumerate() {
40 ch.push(samples[f * channels + c]);
41 }
42 }
43 AudioBuffer { sample_rate, data }
44 }
45
46 pub fn to_interleaved(&self) -> Vec<f32> {
47 let ch = self.channels();
48 let n = self.frames();
49 let mut out = Vec::with_capacity(ch * n);
50 for f in 0..n {
51 for c in 0..ch {
52 out.push(self.data[c][f]);
53 }
54 }
55 out
56 }
57
58 pub fn channels(&self) -> usize {
59 self.data.len()
60 }
61
62 pub fn frames(&self) -> usize {
63 self.data.first().map(|c| c.len()).unwrap_or(0)
64 }
65
66 pub fn duration_s(&self) -> f64 {
67 if self.sample_rate == 0 {
68 0.0
69 } else {
70 self.frames() as f64 / self.sample_rate as f64
71 }
72 }
73
74 pub fn is_empty(&self) -> bool {
75 self.frames() == 0
76 }
77
78 pub fn mono_mix(&self) -> Vec<f32> {
80 let n = self.frames();
81 let ch = self.channels() as f32;
82 let mut out = vec![0.0f32; n];
83 for c in &self.data {
84 for (o, s) in out.iter_mut().zip(c) {
85 *o += *s;
86 }
87 }
88 if ch > 1.0 {
89 for o in &mut out {
90 *o /= ch;
91 }
92 }
93 out
94 }
95
96 pub fn slice(&self, start: usize, end: usize) -> AudioBuffer {
98 let n = self.frames();
99 let s = start.min(n);
100 let e = end.clamp(s, n);
101 AudioBuffer { sample_rate: self.sample_rate, data: self.data.iter().map(|c| c[s..e].to_vec()).collect() }
102 }
103
104 pub fn append(&mut self, other: &AudioBuffer) {
107 let ch = self.channels();
108 for c in 0..ch {
109 let src = other.data.get(c).or(other.data.last());
110 if let Some(src) = src {
111 self.data[c].extend_from_slice(src);
112 }
113 }
114 }
115
116 pub fn peak(&self) -> f32 {
117 self.data.iter().flat_map(|c| c.iter()).fold(0.0f32, |m, s| m.max(s.abs()))
118 }
119
120 pub fn rms(&self) -> f32 {
121 let n = (self.frames() * self.channels()).max(1);
122 let sum: f64 = self.data.iter().flat_map(|c| c.iter()).map(|s| (*s as f64) * (*s as f64)).sum();
123 (sum / n as f64).sqrt() as f32
124 }
125
126 pub fn scale(&mut self, g: f32) {
128 for c in &mut self.data {
129 for s in c.iter_mut() {
130 *s *= g;
131 }
132 }
133 }
134
135 pub fn with_channels(&self, n: usize) -> AudioBuffer {
138 let n = n.max(1);
139 let cur = self.channels();
140 if n == cur {
141 return self.clone();
142 }
143 let data = if n == 1 {
144 vec![self.mono_mix()]
145 } else if cur == 1 {
146 vec![self.data[0].clone(); n]
147 } else {
148 (0..n).map(|i| self.data[i.min(cur - 1)].clone()).collect()
149 };
150 AudioBuffer { sample_rate: self.sample_rate, data }
151 }
152
153 pub fn resize(&mut self, frames: usize) {
155 for c in &mut self.data {
156 c.resize(frames, 0.0);
157 }
158 }
159
160 pub fn info(&self) -> BufferInfo {
161 BufferInfo {
162 sample_rate: self.sample_rate,
163 channels: self.channels(),
164 frames: self.frames(),
165 duration_s: self.duration_s(),
166 }
167 }
168}
169
170#[derive(Clone, Debug, Serialize)]
171pub struct BufferInfo {
172 pub sample_rate: u32,
173 pub channels: usize,
174 pub frames: usize,
175 pub duration_s: f64,
176}
177
178#[derive(Clone, Debug)]
181#[non_exhaustive]
182pub enum MediaBuffer {
183 Audio(AudioBuffer),
184}
185
186impl MediaBuffer {
187 pub fn as_audio(&self) -> Option<&AudioBuffer> {
188 match self {
189 MediaBuffer::Audio(a) => Some(a),
190 }
191 }
192
193 pub fn into_audio(self) -> Option<AudioBuffer> {
194 match self {
195 MediaBuffer::Audio(a) => Some(a),
196 }
197 }
198}
199
200#[inline]
202pub fn db_to_lin(db: f64) -> f64 {
203 10f64.powf(db / 20.0)
204}
205
206#[inline]
208pub fn lin_to_db(lin: f64) -> f64 {
209 if lin <= 1e-12 {
210 -240.0
211 } else {
212 20.0 * lin.log10()
213 }
214}
215
216#[cfg(test)]
217mod tests {
218 use super::*;
219
220 #[test]
221 fn interleave_roundtrip() {
222 let b = AudioBuffer::from_planar(48000, vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]]);
223 let i = b.to_interleaved();
224 assert_eq!(i, vec![1.0, 4.0, 2.0, 5.0, 3.0, 6.0]);
225 assert_eq!(AudioBuffer::from_interleaved(48000, 2, &i), b);
226 }
227
228 #[test]
229 fn channels_conversion() {
230 let b = AudioBuffer::from_planar(48000, vec![vec![1.0, 0.0], vec![0.0, 1.0]]);
231 assert_eq!(b.with_channels(1).data[0], vec![0.5, 0.5]);
232 assert_eq!(b.with_channels(1).with_channels(2).channels(), 2);
233 }
234
235 #[test]
236 fn db_conversions() {
237 assert!((db_to_lin(-6.0206) - 0.5).abs() < 1e-4);
238 assert!((lin_to_db(0.5) + 6.0206).abs() < 1e-3);
239 }
240}