1use core::time::Duration;
2use std::sync::Arc;
3
4#[derive(Clone, Debug)]
9pub struct SoundData {
10 source: Source,
11}
12
13impl SoundData {
14 pub fn mono(rate: u32, samples: Vec<f32>) -> Self {
18 Self::from_samples(SampleRate::new(rate), Channels::Mono, samples)
19 }
20
21 pub fn stereo(rate: u32, samples: Vec<f32>) -> Self {
27 debug_assert_eq!(
28 samples.len() % 2,
29 0,
30 "a stereo sound needs a left and a right sample per frame"
31 );
32
33 Self::from_samples(SampleRate::new(rate), Channels::Stereo, samples)
34 }
35
36 pub fn duration(&self) -> Duration {
38 self.rate().duration_of(self.frames())
39 }
40
41 #[must_use]
47 pub fn streamed(self) -> Self {
48 let source = match self.source {
49 Source::Resident(clip) | Source::Streamed(clip) => Source::Streamed(clip),
50 Source::Samples(samples) => {
51 log::debug!("a sound built out of samples is already in memory, not streamed");
52 Source::Samples(samples)
53 }
54 };
55
56 Self { source }
57 }
58
59 pub(crate) fn empty() -> Self {
62 Self::from_samples(SampleRate::new(1), Channels::Mono, Vec::new())
63 }
64
65 pub(crate) fn loaded(clip: Arc<Encoded>) -> Self {
68 Self {
69 source: Source::Resident(clip),
70 }
71 }
72
73 pub(crate) fn source(&self) -> &Source {
74 &self.source
75 }
76
77 pub(crate) fn rate(&self) -> SampleRate {
78 match &self.source {
79 Source::Samples(samples) => samples.rate,
80 Source::Resident(clip) | Source::Streamed(clip) => clip.rate(),
81 }
82 }
83
84 pub(crate) fn channels(&self) -> Channels {
85 match &self.source {
86 Source::Samples(samples) => samples.channels,
87 Source::Resident(clip) | Source::Streamed(clip) => clip.channels(),
88 }
89 }
90
91 fn frames(&self) -> u64 {
92 match &self.source {
93 Source::Samples(samples) => {
94 samples.values.len() as u64 / samples.channels.count() as u64
95 }
96 Source::Resident(clip) | Source::Streamed(clip) => clip.frames(),
97 }
98 }
99
100 fn from_samples(rate: SampleRate, channels: Channels, samples: Vec<f32>) -> Self {
101 Self {
102 source: Source::Samples(Samples {
103 rate,
104 channels,
105 values: samples.into(),
106 }),
107 }
108 }
109}
110
111#[derive(Clone, Debug)]
114pub(crate) enum Source {
115 Samples(Samples),
116 Resident(Arc<Encoded>),
117 Streamed(Arc<Encoded>),
118}
119
120#[derive(Clone, Debug)]
122pub(crate) struct Samples {
123 pub(crate) rate: SampleRate,
124 pub(crate) channels: Channels,
125 pub(crate) values: Arc<[f32]>,
126}
127
128#[derive(Clone, Copy, Debug, Eq, PartialEq)]
131pub(crate) enum Channels {
132 Mono,
133 Stereo,
134}
135
136impl Channels {
137 pub(crate) fn count(self) -> usize {
138 match self {
139 Self::Mono => 1,
140 Self::Stereo => 2,
141 }
142 }
143
144 pub(crate) fn of(count: u8) -> Self {
148 match count {
149 1 => Self::Mono,
150 _ => Self::Stereo,
151 }
152 }
153}
154
155#[derive(Debug)]
158pub(crate) struct Clip {
159 pub(crate) rate: SampleRate,
160 pub(crate) channels: Channels,
161 pub(crate) frames: u64,
162 pub(crate) body: Body,
163}
164
165#[derive(Debug)]
167pub(crate) enum Body {
168 Samples(Arc<[f32]>),
169 Encoded(Arc<Encoded>),
170}
171
172#[derive(Debug)]
175pub(crate) struct Encoded {
176 bytes: Arc<[u8]>,
177 rate: SampleRate,
178 channels: Channels,
179 frames: u64,
180 seeks: Vec<ClipFrame>,
183}
184
185impl Encoded {
186 pub(crate) fn new(
187 bytes: Arc<[u8]>,
188 rate: SampleRate,
189 channels: Channels,
190 frames: u64,
191 seeks: Vec<ClipFrame>,
192 ) -> Self {
193 Self {
194 bytes,
195 rate,
196 channels,
197 frames,
198 seeks,
199 }
200 }
201
202 pub(crate) fn bytes(&self) -> &Arc<[u8]> {
203 &self.bytes
204 }
205
206 pub(crate) fn rate(&self) -> SampleRate {
207 self.rate
208 }
209
210 pub(crate) fn channels(&self) -> Channels {
211 self.channels
212 }
213
214 pub(crate) fn frames(&self) -> u64 {
215 self.frames
216 }
217
218 pub(crate) fn seek_before(&self, frame: ClipFrame) -> ClipFrame {
221 self.seeks
222 .partition_point(|&indexed| indexed <= frame)
223 .checked_sub(1)
224 .map_or(ClipFrame::ZERO, |at| self.seeks[at])
225 }
226}
227
228#[derive(Clone, Copy, Debug, Eq, PartialEq)]
230pub(crate) struct SampleRate(u32);
231
232impl SampleRate {
233 pub(crate) const fn new(rate: u32) -> Self {
236 debug_assert!(
237 rate > 0,
238 "a sound needs a rate of more than zero frames a second"
239 );
240
241 Self(if rate > 0 { rate } else { 1 })
242 }
243
244 pub(crate) fn duration_of(self, frames: u64) -> Duration {
246 Duration::from_secs_f64(frames as f64 / f64::from(self.0))
247 }
248
249 pub(crate) fn frames_at(self, frames: u64, rate: SampleRate) -> u64 {
252 (frames * u64::from(rate)).div_ceil(u64::from(self))
253 }
254
255 pub(crate) fn frame_at(self, span: Duration) -> ClipFrame {
259 ClipFrame::new((span.as_secs_f64() * f64::from(self.0)).round() as u64)
260 }
261}
262
263#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
265pub(crate) struct ClipFrame(u64);
266
267impl ClipFrame {
268 pub(crate) const ZERO: Self = Self(0);
269
270 pub(crate) const fn new(frame: u64) -> Self {
271 Self(frame)
272 }
273
274 pub(crate) const fn get(self) -> u64 {
275 self.0
276 }
277
278 pub(crate) fn saturating_sub(self, other: Self) -> u64 {
280 self.0.saturating_sub(other.0)
281 }
282
283 pub(crate) fn back(self, count: u64) -> Self {
286 Self(self.0.saturating_sub(count))
287 }
288}
289
290impl core::ops::Add for ClipFrame {
291 type Output = Self;
292
293 fn add(self, other: Self) -> Self {
294 Self(self.0 + other.0)
295 }
296}
297
298impl core::ops::Sub for ClipFrame {
299 type Output = Self;
300
301 fn sub(self, other: Self) -> Self {
302 Self(self.0 - other.0)
303 }
304}
305
306impl core::ops::Rem for ClipFrame {
307 type Output = Self;
308
309 fn rem(self, other: Self) -> Self {
310 Self(self.0 % other.0)
311 }
312}
313
314impl core::ops::Add<u64> for ClipFrame {
315 type Output = Self;
316
317 fn add(self, count: u64) -> Self {
318 Self(self.0 + count)
319 }
320}
321
322impl core::ops::AddAssign<u64> for ClipFrame {
323 fn add_assign(&mut self, count: u64) {
324 self.0 += count;
325 }
326}
327
328impl From<SampleRate> for u64 {
329 fn from(rate: SampleRate) -> Self {
330 Self::from(rate.0)
331 }
332}
333
334impl From<SampleRate> for f64 {
335 fn from(rate: SampleRate) -> Self {
336 f64::from(rate.0)
337 }
338}
339
340impl From<SampleRate> for f32 {
341 fn from(rate: SampleRate) -> Self {
342 rate.0 as f32
343 }
344}
345
346#[cfg(test)]
347mod tests {
348 use super::*;
349
350 #[test]
351 fn a_sound_lasts_as_long_as_its_frames_take_at_its_rate() {
352 let mono = SoundData::mono(8_000, vec![0.0; 4_000]);
353 let stereo = SoundData::stereo(8_000, vec![0.0; 4_000]);
354
355 assert_eq!(mono.duration(), Duration::from_millis(500));
356 assert_eq!(stereo.duration(), Duration::from_millis(250));
357 assert_eq!(SoundData::empty().duration(), Duration::ZERO);
358 }
359
360 #[test]
361 fn a_seek_starts_from_the_last_indexed_position_before_it() {
362 let clip = Encoded::new(
363 Arc::from(&b""[..]),
364 SampleRate::new(44_100),
365 Channels::Mono,
366 132_300,
367 vec![
368 ClipFrame::new(0),
369 ClipFrame::new(44_100),
370 ClipFrame::new(88_200),
371 ],
372 );
373
374 assert_eq!(clip.seek_before(ClipFrame::new(0)).get(), 0);
375 assert_eq!(clip.seek_before(ClipFrame::new(44_099)).get(), 0);
376 assert_eq!(clip.seek_before(ClipFrame::new(44_100)).get(), 44_100);
377 assert_eq!(clip.seek_before(ClipFrame::new(120_000)).get(), 88_200);
378 }
379}