1use core::time::Duration;
2use std::sync::Arc;
3
4use crate::assets::Unresolved;
5
6#[derive(Clone, Debug)]
11pub struct SoundData {
12 source: Source,
13 unresolved: Unresolved,
15}
16
17impl SoundData {
18 pub fn mono(rate: u32, samples: Vec<f32>) -> Self {
22 Self::from_samples(SampleRate::new(rate), Channels::Mono, samples)
23 }
24
25 pub fn stereo(rate: u32, samples: Vec<f32>) -> Self {
31 debug_assert_eq!(
32 samples.len() % 2,
33 0,
34 "a stereo sound needs a left and a right sample per frame"
35 );
36
37 Self::from_samples(SampleRate::new(rate), Channels::Stereo, samples)
38 }
39
40 pub fn duration(&self) -> Duration {
42 self.rate().duration_of(self.frames())
43 }
44
45 #[must_use]
51 pub fn streamed(mut self) -> Self {
52 let source = match self.source {
53 Source::Resident(clip) | Source::Streamed(clip) => Source::Streamed(clip),
54 Source::Samples(samples) => {
55 log::debug!("a sound built out of samples is already in memory, not streamed");
56 Source::Samples(samples)
57 }
58 };
59
60 Self {
61 source,
62 unresolved: self.unresolved.taken(),
63 }
64 }
65
66 pub(crate) fn empty() -> Self {
69 Self::from_samples(SampleRate::new(1), Channels::Mono, Vec::new())
70 }
71
72 pub(crate) fn missing(unresolved: Unresolved) -> Self {
75 Self {
76 unresolved,
77 ..Self::empty()
78 }
79 }
80
81 pub(crate) fn take_unresolved(&mut self) -> Unresolved {
83 self.unresolved.taken()
84 }
85
86 pub(crate) fn loaded(clip: Arc<Encoded>) -> Self {
89 Self {
90 source: Source::Resident(clip),
91 unresolved: Unresolved::default(),
92 }
93 }
94
95 pub(crate) fn source(&self) -> &Source {
96 &self.source
97 }
98
99 pub(crate) fn rate(&self) -> SampleRate {
100 match &self.source {
101 Source::Samples(samples) => samples.rate,
102 Source::Resident(clip) | Source::Streamed(clip) => clip.rate(),
103 }
104 }
105
106 pub(crate) fn channels(&self) -> Channels {
107 match &self.source {
108 Source::Samples(samples) => samples.channels,
109 Source::Resident(clip) | Source::Streamed(clip) => clip.channels(),
110 }
111 }
112
113 fn frames(&self) -> u64 {
114 match &self.source {
115 Source::Samples(samples) => {
116 samples.values.len() as u64 / samples.channels.count() as u64
117 }
118 Source::Resident(clip) | Source::Streamed(clip) => clip.frames(),
119 }
120 }
121
122 fn from_samples(rate: SampleRate, channels: Channels, samples: Vec<f32>) -> Self {
123 Self {
124 source: Source::Samples(Samples {
125 rate,
126 channels,
127 values: samples.into(),
128 }),
129 unresolved: Unresolved::default(),
130 }
131 }
132}
133
134#[derive(Clone, Debug)]
137pub(crate) enum Source {
138 Samples(Samples),
139 Resident(Arc<Encoded>),
140 Streamed(Arc<Encoded>),
141}
142
143#[derive(Clone, Debug)]
145pub(crate) struct Samples {
146 pub(crate) rate: SampleRate,
147 pub(crate) channels: Channels,
148 pub(crate) values: Arc<[f32]>,
149}
150
151#[derive(Clone, Copy, Debug, Eq, PartialEq)]
154pub(crate) enum Channels {
155 Mono,
156 Stereo,
157}
158
159impl Channels {
160 pub(crate) fn count(self) -> usize {
161 match self {
162 Self::Mono => 1,
163 Self::Stereo => 2,
164 }
165 }
166
167 pub(crate) fn of(count: u8) -> Self {
171 match count {
172 1 => Self::Mono,
173 _ => Self::Stereo,
174 }
175 }
176}
177
178#[derive(Debug)]
181pub(crate) struct Clip {
182 pub(crate) rate: SampleRate,
183 pub(crate) channels: Channels,
184 pub(crate) frames: u64,
185 pub(crate) body: Body,
186}
187
188#[derive(Debug)]
190pub(crate) enum Body {
191 Samples(Arc<[f32]>),
192 Encoded(Arc<Encoded>),
193}
194
195#[derive(Debug)]
198pub(crate) struct Encoded {
199 bytes: Arc<[u8]>,
200 rate: SampleRate,
201 channels: Channels,
202 frames: u64,
203 seeks: Vec<ClipFrame>,
206}
207
208impl Encoded {
209 pub(crate) fn new(
210 bytes: Arc<[u8]>,
211 rate: SampleRate,
212 channels: Channels,
213 frames: u64,
214 seeks: Vec<ClipFrame>,
215 ) -> Self {
216 Self {
217 bytes,
218 rate,
219 channels,
220 frames,
221 seeks,
222 }
223 }
224
225 pub(crate) fn bytes(&self) -> &Arc<[u8]> {
226 &self.bytes
227 }
228
229 pub(crate) fn rate(&self) -> SampleRate {
230 self.rate
231 }
232
233 pub(crate) fn channels(&self) -> Channels {
234 self.channels
235 }
236
237 pub(crate) fn frames(&self) -> u64 {
238 self.frames
239 }
240
241 pub(crate) fn seek_before(&self, frame: ClipFrame) -> ClipFrame {
244 self.seeks
245 .partition_point(|&indexed| indexed <= frame)
246 .checked_sub(1)
247 .map_or(ClipFrame::ZERO, |at| self.seeks[at])
248 }
249}
250
251#[derive(Clone, Copy, Debug, Eq, PartialEq)]
253pub(crate) struct SampleRate(u32);
254
255impl SampleRate {
256 pub(crate) const fn new(rate: u32) -> Self {
259 debug_assert!(
260 rate > 0,
261 "a sound needs a rate of more than zero frames a second"
262 );
263
264 Self(if rate > 0 { rate } else { 1 })
265 }
266
267 pub(crate) fn duration_of(self, frames: u64) -> Duration {
269 Duration::from_secs_f64(frames as f64 / f64::from(self.0))
270 }
271
272 pub(crate) fn frames_at(self, frames: u64, rate: SampleRate) -> u64 {
275 (frames * u64::from(rate)).div_ceil(u64::from(self))
276 }
277
278 pub(crate) fn frame_at(self, span: Duration) -> ClipFrame {
282 ClipFrame::new((span.as_secs_f64() * f64::from(self.0)).round() as u64)
283 }
284}
285
286#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
288pub(crate) struct ClipFrame(u64);
289
290impl ClipFrame {
291 pub(crate) const ZERO: Self = Self(0);
292
293 pub(crate) const fn new(frame: u64) -> Self {
294 Self(frame)
295 }
296
297 pub(crate) const fn get(self) -> u64 {
298 self.0
299 }
300
301 pub(crate) fn saturating_sub(self, other: Self) -> u64 {
303 self.0.saturating_sub(other.0)
304 }
305
306 pub(crate) fn back(self, count: u64) -> Self {
309 Self(self.0.saturating_sub(count))
310 }
311}
312
313impl core::ops::Add for ClipFrame {
314 type Output = Self;
315
316 fn add(self, other: Self) -> Self {
317 Self(self.0 + other.0)
318 }
319}
320
321impl core::ops::Sub for ClipFrame {
322 type Output = Self;
323
324 fn sub(self, other: Self) -> Self {
325 Self(self.0 - other.0)
326 }
327}
328
329impl core::ops::Rem for ClipFrame {
330 type Output = Self;
331
332 fn rem(self, other: Self) -> Self {
333 Self(self.0 % other.0)
334 }
335}
336
337impl core::ops::Add<u64> for ClipFrame {
338 type Output = Self;
339
340 fn add(self, count: u64) -> Self {
341 Self(self.0 + count)
342 }
343}
344
345impl core::ops::AddAssign<u64> for ClipFrame {
346 fn add_assign(&mut self, count: u64) {
347 self.0 += count;
348 }
349}
350
351impl From<SampleRate> for u64 {
352 fn from(rate: SampleRate) -> Self {
353 Self::from(rate.0)
354 }
355}
356
357impl From<SampleRate> for f64 {
358 fn from(rate: SampleRate) -> Self {
359 f64::from(rate.0)
360 }
361}
362
363impl From<SampleRate> for f32 {
364 fn from(rate: SampleRate) -> Self {
365 rate.0 as f32
366 }
367}
368
369#[cfg(test)]
370mod tests {
371 use super::*;
372
373 #[test]
374 fn a_sound_lasts_as_long_as_its_frames_take_at_its_rate() {
375 let mono = SoundData::mono(8_000, vec![0.0; 4_000]);
376 let stereo = SoundData::stereo(8_000, vec![0.0; 4_000]);
377
378 assert_eq!(mono.duration(), Duration::from_millis(500));
379 assert_eq!(stereo.duration(), Duration::from_millis(250));
380 assert_eq!(SoundData::empty().duration(), Duration::ZERO);
381 }
382
383 #[test]
384 fn a_seek_starts_from_the_last_indexed_position_before_it() {
385 let clip = Encoded::new(
386 Arc::from(&b""[..]),
387 SampleRate::new(44_100),
388 Channels::Mono,
389 132_300,
390 vec![
391 ClipFrame::new(0),
392 ClipFrame::new(44_100),
393 ClipFrame::new(88_200),
394 ],
395 );
396
397 assert_eq!(clip.seek_before(ClipFrame::new(0)).get(), 0);
398 assert_eq!(clip.seek_before(ClipFrame::new(44_099)).get(), 0);
399 assert_eq!(clip.seek_before(ClipFrame::new(44_100)).get(), 44_100);
400 assert_eq!(clip.seek_before(ClipFrame::new(120_000)).get(), 88_200);
401 }
402}