1use crate::math::sin_turns;
2use crate::{DecodeInfo, Error, Limits, Result, TimePosition};
3use std::fmt;
4
5#[derive(Clone, Debug)]
8pub struct Audio {
9 pub(crate) data: Vec<Vec<f32>>,
10 pub(crate) rate: u32,
11 pub(crate) info: DecodeInfo,
12 #[cfg(feature = "mixer")]
15 id: u64,
16}
17#[cfg(feature = "mixer")]
19use crate::identity::next as next_id;
20impl Audio {
21 #[cfg(feature = "mixer")]
24 pub(crate) fn id(&self) -> u64 {
25 self.id
26 }
27 pub fn new(data: Vec<Vec<f32>>, sample_rate: u32) -> Result<Self> {
28 let frames = data.first().map_or(0, Vec::len);
29 Limits::default().check(frames, data.len(), sample_rate)?;
30 if data
31 .iter()
32 .any(|c| c.len() != frames || c.iter().any(|s| !s.is_finite()))
33 {
34 return Err(Error::invalid(
35 "Channels must have equal lengths and finite samples",
36 ));
37 }
38 Ok(Self {
39 data,
40 rate: sample_rate,
41 info: DecodeInfo::default(),
42 #[cfg(feature = "mixer")]
43 id: next_id(),
44 })
45 }
46 pub(crate) fn decoded(data: Vec<Vec<f32>>, rate: u32, info: DecodeInfo) -> Result<Self> {
47 if data.is_empty()
48 || rate == 0
49 || data
50 .iter()
51 .any(|c| c.len() != data[0].len() || c.iter().any(|s| !s.is_finite()))
52 {
53 return Err(Error::decode("Invalid decoded PCM"));
54 }
55 Ok(Self {
56 data,
57 rate,
58 info,
59 #[cfg(feature = "mixer")]
60 id: next_id(),
61 })
62 }
63 pub(crate) fn with_data(&self, data: Vec<Vec<f32>>) -> Self {
64 Self {
65 data,
66 rate: self.rate,
67 info: self.info.clone(),
68 #[cfg(feature = "mixer")]
69 id: next_id(),
70 }
71 }
72 pub fn sample_rate(&self) -> u32 {
73 self.rate
74 }
75 pub fn channels(&self) -> usize {
76 self.data.len()
77 }
78 pub fn frames(&self) -> usize {
79 self.data[0].len()
80 }
81 pub fn duration(&self) -> f64 {
82 self.frames() as f64 / self.rate as f64
83 }
84 pub fn info(&self) -> &DecodeInfo {
85 &self.info
86 }
87 pub fn channel_data(&self, channel: usize) -> Result<&[f32]> {
88 self.data
89 .get(channel)
90 .map(Vec::as_slice)
91 .ok_or_else(|| Error::invalid("Channel index out of range"))
92 }
93 pub fn all_channels(&self) -> &[Vec<f32>] {
94 &self.data
95 }
96 pub fn to_interleaved(&self) -> Vec<f32> {
97 let mut out = Vec::with_capacity(self.frames() * self.channels());
98 for frame in 0..self.frames() {
99 for channel in &self.data {
100 out.push(channel[frame]);
101 }
102 }
103 out
104 }
105 pub fn from_interleaved(samples: &[f32], channels: usize, rate: u32) -> Result<Self> {
106 if channels == 0 || samples.len() % channels != 0 {
107 return Err(Error::invalid("Incomplete interleaved frames"));
108 }
109 Limits::default().check(samples.len() / channels, channels, rate)?;
110 let mut data = vec![vec![0.0; samples.len() / channels]; channels];
111 for (i, frame) in samples.chunks_exact(channels).enumerate() {
112 for (c, &v) in frame.iter().enumerate() {
113 data[c][i] = v;
114 }
115 }
116 Self::new(data, rate)
117 }
118 pub fn silence(duration: impl Into<TimePosition>, channels: usize, rate: u32) -> Result<Self> {
119 let frames = duration.into().duration(rate)?;
120 Limits::default().check(frames, channels, rate)?;
121 Self::new(vec![vec![0.0; frames]; channels], rate)
122 }
123 pub fn cut(&self, from: impl Into<TimePosition>, to: impl Into<TimePosition>) -> Result<Self> {
124 let start = from.into().index(self.rate, self.frames())?;
125 let end = to.into().index(self.rate, self.frames())?.max(start);
126 Ok(self.with_data(self.data.iter().map(|c| c[start..end].to_vec()).collect()))
127 }
128 pub fn remove(
129 &self,
130 from: impl Into<TimePosition>,
131 to: impl Into<TimePosition>,
132 ) -> Result<Self> {
133 let start = from.into().index(self.rate, self.frames())?;
134 let end = to.into().index(self.rate, self.frames())?.max(start);
135 Ok(self.with_data(
136 self.data
137 .iter()
138 .map(|c| c[..start].iter().chain(&c[end..]).copied().collect())
139 .collect(),
140 ))
141 }
142 pub(crate) fn same_shape(&self, other: &Self) -> Result<()> {
143 if self.rate != other.rate || self.channels() != other.channels() {
144 return Err(Error::invalid("Sample rates and channel counts must match"));
145 }
146 Ok(())
147 }
148 pub fn concat(&self, other: &Self) -> Result<Self> {
149 self.same_shape(other)?;
150 let frames = self
151 .frames()
152 .checked_add(other.frames())
153 .ok_or_else(|| Error::limit("Frame count overflow"))?;
154 Limits::default().check(frames, self.channels(), self.rate)?;
155 Ok(self.with_data(
156 self.data
157 .iter()
158 .zip(&other.data)
159 .map(|(a, b)| a.iter().chain(b).copied().collect())
160 .collect(),
161 ))
162 }
163 pub fn pad(
164 &self,
165 before: impl Into<TimePosition>,
166 after: impl Into<TimePosition>,
167 ) -> Result<Self> {
168 let before = before.into().duration(self.rate)?;
169 let after = after.into().duration(self.rate)?;
170 let frames = before
171 .checked_add(self.frames())
172 .and_then(|n| n.checked_add(after))
173 .ok_or_else(|| Error::limit("Frame count overflow"))?;
174 Limits::default().check(frames, self.channels(), self.rate)?;
175 Ok(self.with_data(
176 self.data
177 .iter()
178 .map(|c| {
179 let mut out = vec![0.0; frames];
180 out[before..before + c.len()].copy_from_slice(c);
181 out
182 })
183 .collect(),
184 ))
185 }
186 pub fn reverse(&self) -> Self {
187 self.with_data(
188 self.data
189 .iter()
190 .map(|c| c.iter().rev().copied().collect())
191 .collect(),
192 )
193 }
194 pub fn mix(&self, overlay: &Self, offset: i64, gain: f32, extend: bool) -> Result<Self> {
195 self.same_shape(overlay)?;
196 if !gain.is_finite() {
197 return Err(Error::invalid("Gain must be finite"));
198 }
199 let needed = (self.frames() as i128).max(offset as i128 + overlay.frames() as i128);
200 let frames = if extend {
201 usize::try_from(needed).map_err(|_| Error::limit("Frame count overflow"))?
202 } else {
203 self.frames()
204 };
205 Limits::default().check(frames, self.channels(), self.rate)?;
206 let mut out = self.data.clone();
207 for (c, dst) in out.iter_mut().enumerate() {
208 dst.resize(frames, 0.0);
209 for (i, &s) in overlay.data[c].iter().enumerate() {
210 let at = offset as i128 + i as i128;
211 if at >= 0 && at < frames as i128 {
212 dst[at as usize] += s * gain;
213 }
214 }
215 }
216 if out.iter().flatten().any(|s| !s.is_finite()) {
217 return Err(Error::invalid("Mix overflow"));
218 }
219 Ok(self.with_data(out))
220 }
221 pub fn crossfade_to(&self, other: &Self, duration: impl Into<TimePosition>) -> Result<Self> {
222 self.same_shape(other)?;
223 let n = duration
224 .into()
225 .duration(self.rate)?
226 .min(self.frames())
227 .min(other.frames());
228 let frames = self
229 .frames()
230 .checked_add(other.frames())
231 .and_then(|v| v.checked_sub(n))
232 .ok_or_else(|| Error::limit("Frame count overflow"))?;
233 Limits::default().check(frames, self.channels(), self.rate)?;
234 let mut data = Vec::new();
235 for (a, b) in self.data.iter().zip(&other.data) {
236 let mut out = a[..a.len() - n].to_vec();
237 for i in 0..n {
238 let turns = i as f64 / n.saturating_sub(1).max(1) as f64 / 4.0;
240 let (fade_out, fade_in) = (sin_turns(0.25 - turns), sin_turns(turns));
241 out.push(a[a.len() - n + i] * fade_out as f32 + b[i] * fade_in as f32);
242 }
243 out.extend_from_slice(&b[n..]);
244 data.push(out);
245 }
246 Ok(self.with_data(data))
247 }
248 pub fn to_mono(&self) -> Self {
249 let mut mono = vec![0.0; self.frames()];
250 for c in &self.data {
251 for (v, s) in mono.iter_mut().zip(c) {
252 *v += *s / self.channels() as f32;
253 }
254 }
255 self.with_data(vec![mono])
256 }
257 pub fn to_stereo(&self) -> Self {
258 if self.channels() == 2 {
259 return self.clone();
260 }
261 let mono = self.to_mono();
262 self.with_data(vec![mono.data[0].clone(), mono.data[0].clone()])
263 }
264 pub fn to_channels(&self, count: usize) -> Result<Self> {
265 Limits::default().check(self.frames(), count, self.rate)?;
266 match count {
267 1 => Ok(self.to_mono()),
268 2 => Ok(self.to_stereo()),
269 _ => Ok(self.with_data(
270 (0..count)
271 .map(|c| self.data[c % self.channels()].clone())
272 .collect(),
273 )),
274 }
275 }
276 pub fn map_channels(&self, mapping: &[usize]) -> Result<Self> {
277 Limits::default().check(self.frames(), mapping.len(), self.rate)?;
278 let data = mapping
279 .iter()
280 .map(|&i| self.channel_data(i).map(<[f32]>::to_vec))
281 .collect::<Result<_>>()?;
282 Ok(self.with_data(data))
283 }
284 pub fn pan(&self, position: f64) -> Result<Self> {
285 if !position.is_finite() {
286 return Err(Error::invalid("Pan must be finite"));
287 }
288 let turns = (position.clamp(-1.0, 1.0) + 1.0) / 8.0;
290 let (left, right) = (sin_turns(0.25 - turns) as f32, sin_turns(turns) as f32);
291 let mut out = self.to_stereo();
292 #[cfg(feature = "mixer")]
294 {
295 out.id = next_id();
296 }
297 for s in &mut out.data[0] {
298 *s *= left;
299 }
300 for s in &mut out.data[1] {
301 *s *= right;
302 }
303 Ok(out)
304 }
305 pub fn split(&self) -> Vec<Self> {
306 self.data
307 .iter()
308 .map(|c| self.with_data(vec![c.clone()]))
309 .collect()
310 }
311 pub fn merge(parts: &[Self]) -> Result<Self> {
312 let first = parts
313 .first()
314 .ok_or_else(|| Error::invalid("No audio to merge"))?;
315 if parts.iter().any(|p| p.rate != first.rate) {
316 return Err(Error::invalid("Sample rates must match"));
317 }
318 let frames = parts.iter().map(Self::frames).max().unwrap_or(0);
319 let channels = parts
320 .iter()
321 .try_fold(0usize, |n, p| n.checked_add(p.channels()))
322 .ok_or_else(|| Error::limit("Channel count overflow"))?;
323 Limits::default().check(frames, channels, first.rate)?;
324 let data = parts
325 .iter()
326 .flat_map(|p| {
327 p.data.iter().map(|c| {
328 let mut out = c.clone();
329 out.resize(frames, 0.0);
330 out
331 })
332 })
333 .collect();
334 Ok(first.with_data(data))
335 }
336 pub fn duration_formatted(&self) -> String {
337 let ms = (self.duration() * 1000.0).round() as u64;
338 let h = ms / 3600000;
339 let m = ms / 60000 % 60;
340 let s = ms / 1000 % 60;
341 if h > 0 {
342 format!("{h}:{m:02}:{s:02}.{:03}", ms % 1000)
343 } else {
344 format!("{m}:{s:02}.{:03}", ms % 1000)
345 }
346 }
347}
348impl fmt::Display for Audio {
349 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
350 write!(
351 f,
352 "Audio({}, {} Hz, {}ch)",
353 self.duration_formatted(),
354 self.rate,
355 self.channels()
356 )
357 }
358}