use core::time::Duration;
use std::sync::Arc;
use crate::assets::Unresolved;
#[derive(Clone, Debug)]
pub struct SoundData {
source: Source,
unresolved: Unresolved,
}
impl SoundData {
pub fn mono(rate: u32, samples: Vec<f32>) -> Self {
Self::from_samples(SampleRate::new(rate), Channels::Mono, samples)
}
pub fn stereo(rate: u32, samples: Vec<f32>) -> Self {
debug_assert_eq!(
samples.len() % 2,
0,
"a stereo sound needs a left and a right sample per frame"
);
Self::from_samples(SampleRate::new(rate), Channels::Stereo, samples)
}
pub fn duration(&self) -> Duration {
self.rate().duration_of(self.frames())
}
#[must_use]
pub fn streamed(mut self) -> Self {
let source = match self.source {
Source::Resident(clip) | Source::Streamed(clip) => Source::Streamed(clip),
Source::Samples(samples) => {
log::debug!("a sound built out of samples is already in memory, not streamed");
Source::Samples(samples)
}
};
Self {
source,
unresolved: self.unresolved.taken(),
}
}
pub(crate) fn empty() -> Self {
Self::from_samples(SampleRate::new(1), Channels::Mono, Vec::new())
}
pub(crate) fn missing(unresolved: Unresolved) -> Self {
Self {
unresolved,
..Self::empty()
}
}
pub(crate) fn take_unresolved(&mut self) -> Unresolved {
self.unresolved.taken()
}
pub(crate) fn loaded(clip: Arc<Encoded>) -> Self {
Self {
source: Source::Resident(clip),
unresolved: Unresolved::default(),
}
}
pub(crate) fn source(&self) -> &Source {
&self.source
}
pub(crate) fn rate(&self) -> SampleRate {
match &self.source {
Source::Samples(samples) => samples.rate,
Source::Resident(clip) | Source::Streamed(clip) => clip.rate(),
}
}
pub(crate) fn channels(&self) -> Channels {
match &self.source {
Source::Samples(samples) => samples.channels,
Source::Resident(clip) | Source::Streamed(clip) => clip.channels(),
}
}
fn frames(&self) -> u64 {
match &self.source {
Source::Samples(samples) => {
samples.values.len() as u64 / samples.channels.count() as u64
}
Source::Resident(clip) | Source::Streamed(clip) => clip.frames(),
}
}
fn from_samples(rate: SampleRate, channels: Channels, samples: Vec<f32>) -> Self {
Self {
source: Source::Samples(Samples {
rate,
channels,
values: samples.into(),
}),
unresolved: Unresolved::default(),
}
}
}
#[derive(Clone, Debug)]
pub(crate) enum Source {
Samples(Samples),
Resident(Arc<Encoded>),
Streamed(Arc<Encoded>),
}
#[derive(Clone, Debug)]
pub(crate) struct Samples {
pub(crate) rate: SampleRate,
pub(crate) channels: Channels,
pub(crate) values: Arc<[f32]>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum Channels {
Mono,
Stereo,
}
impl Channels {
pub(crate) fn count(self) -> usize {
match self {
Self::Mono => 1,
Self::Stereo => 2,
}
}
pub(crate) fn of(count: u8) -> Self {
match count {
1 => Self::Mono,
_ => Self::Stereo,
}
}
}
#[derive(Debug)]
pub(crate) struct Clip {
pub(crate) rate: SampleRate,
pub(crate) channels: Channels,
pub(crate) frames: u64,
pub(crate) body: Body,
}
#[derive(Debug)]
pub(crate) enum Body {
Samples(Arc<[f32]>),
Encoded(Arc<Encoded>),
}
#[derive(Debug)]
pub(crate) struct Encoded {
bytes: Arc<[u8]>,
rate: SampleRate,
channels: Channels,
frames: u64,
seeks: Vec<ClipFrame>,
}
impl Encoded {
pub(crate) fn new(
bytes: Arc<[u8]>,
rate: SampleRate,
channels: Channels,
frames: u64,
seeks: Vec<ClipFrame>,
) -> Self {
Self {
bytes,
rate,
channels,
frames,
seeks,
}
}
pub(crate) fn bytes(&self) -> &Arc<[u8]> {
&self.bytes
}
pub(crate) fn rate(&self) -> SampleRate {
self.rate
}
pub(crate) fn channels(&self) -> Channels {
self.channels
}
pub(crate) fn frames(&self) -> u64 {
self.frames
}
pub(crate) fn seek_before(&self, frame: ClipFrame) -> ClipFrame {
self.seeks
.partition_point(|&indexed| indexed <= frame)
.checked_sub(1)
.map_or(ClipFrame::ZERO, |at| self.seeks[at])
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct SampleRate(u32);
impl SampleRate {
pub(crate) const fn new(rate: u32) -> Self {
debug_assert!(
rate > 0,
"a sound needs a rate of more than zero frames a second"
);
Self(if rate > 0 { rate } else { 1 })
}
pub(crate) fn duration_of(self, frames: u64) -> Duration {
Duration::from_secs_f64(frames as f64 / f64::from(self.0))
}
pub(crate) fn frames_at(self, frames: u64, rate: SampleRate) -> u64 {
(frames * u64::from(rate)).div_ceil(u64::from(self))
}
pub(crate) fn frame_at(self, span: Duration) -> ClipFrame {
ClipFrame::new((span.as_secs_f64() * f64::from(self.0)).round() as u64)
}
}
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
pub(crate) struct ClipFrame(u64);
impl ClipFrame {
pub(crate) const ZERO: Self = Self(0);
pub(crate) const fn new(frame: u64) -> Self {
Self(frame)
}
pub(crate) const fn get(self) -> u64 {
self.0
}
pub(crate) fn saturating_sub(self, other: Self) -> u64 {
self.0.saturating_sub(other.0)
}
pub(crate) fn back(self, count: u64) -> Self {
Self(self.0.saturating_sub(count))
}
}
impl core::ops::Add for ClipFrame {
type Output = Self;
fn add(self, other: Self) -> Self {
Self(self.0 + other.0)
}
}
impl core::ops::Sub for ClipFrame {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self(self.0 - other.0)
}
}
impl core::ops::Rem for ClipFrame {
type Output = Self;
fn rem(self, other: Self) -> Self {
Self(self.0 % other.0)
}
}
impl core::ops::Add<u64> for ClipFrame {
type Output = Self;
fn add(self, count: u64) -> Self {
Self(self.0 + count)
}
}
impl core::ops::AddAssign<u64> for ClipFrame {
fn add_assign(&mut self, count: u64) {
self.0 += count;
}
}
impl From<SampleRate> for u64 {
fn from(rate: SampleRate) -> Self {
Self::from(rate.0)
}
}
impl From<SampleRate> for f64 {
fn from(rate: SampleRate) -> Self {
f64::from(rate.0)
}
}
impl From<SampleRate> for f32 {
fn from(rate: SampleRate) -> Self {
rate.0 as f32
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_sound_lasts_as_long_as_its_frames_take_at_its_rate() {
let mono = SoundData::mono(8_000, vec![0.0; 4_000]);
let stereo = SoundData::stereo(8_000, vec![0.0; 4_000]);
assert_eq!(mono.duration(), Duration::from_millis(500));
assert_eq!(stereo.duration(), Duration::from_millis(250));
assert_eq!(SoundData::empty().duration(), Duration::ZERO);
}
#[test]
fn a_seek_starts_from_the_last_indexed_position_before_it() {
let clip = Encoded::new(
Arc::from(&b""[..]),
SampleRate::new(44_100),
Channels::Mono,
132_300,
vec![
ClipFrame::new(0),
ClipFrame::new(44_100),
ClipFrame::new(88_200),
],
);
assert_eq!(clip.seek_before(ClipFrame::new(0)).get(), 0);
assert_eq!(clip.seek_before(ClipFrame::new(44_099)).get(), 0);
assert_eq!(clip.seek_before(ClipFrame::new(44_100)).get(), 44_100);
assert_eq!(clip.seek_before(ClipFrame::new(120_000)).get(), 88_200);
}
}