babycat 0.0.14

An audio decoding and manipulation library, with bindings for C, Python, and WebAssembly.
use crate::backend::display::est_num_frames_to_str;
use crate::backend::Error;
use crate::backend::Signal;
use crate::backend::Source;

/// [`Source::append()`]
pub struct Append<S1: Source, S2: Source> {
    first: S1,
    second: S2,
}

impl<S1: Source, S2: Source> std::fmt::Debug for Append<S1, S2> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(
            f,
            "Append {{ {} + {} = {} frames,  {} channels,  {} hz,  {} }}",
            est_num_frames_to_str(self.first.num_frames_estimate()),
            est_num_frames_to_str(self.second.num_frames_estimate()),
            est_num_frames_to_str(self.num_frames_estimate()),
            self.num_channels(),
            self.frame_rate_hz(),
            self.duration_estimate_to_str(),
        )
    }
}

impl<S1: Source, S2: Source> Append<S1, S2> {
    #[inline]
    pub fn new(first: S1, second: S2) -> Result<Self, Error> {
        let f_nc = first.num_channels();
        let s_nc = second.num_channels();
        if f_nc != s_nc {
            return Err(Error::CannotAppendSourcesWithDifferentNumChannels(
                f_nc, s_nc,
            ));
        }
        let f_fr = first.frame_rate_hz();
        let s_fr = second.frame_rate_hz();
        if f_fr != s_fr {
            return Err(Error::CannotAppendSourcesWithDifferentFrameRates(
                f_fr, s_fr,
            ));
        }
        Ok(Self { first, second })
    }
}

impl<S1: Source, S2: Source> Source for Append<S1, S2> {}

impl<S1: Source, S2: Source> Signal for Append<S1, S2> {
    #[inline]
    fn frame_rate_hz(&self) -> u32 {
        self.first.frame_rate_hz()
    }

    #[inline]
    fn num_channels(&self) -> u16 {
        self.first.num_channels()
    }

    #[inline]
    fn num_frames_estimate(&self) -> Option<usize> {
        match (
            self.first.num_frames_estimate(),
            self.second.num_frames_estimate(),
        ) {
            (Some(first), Some(second)) => Some(first + second),
            _ => None,
        }
    }
}

impl<S1: Source, S2: Source> Iterator for Append<S1, S2> {
    type Item = f32;

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let (first_lower, first_upper) = self.first.size_hint();
        let (second_lower, second_upper) = self.second.size_hint();
        let lower = first_lower + second_lower;
        let upper = match (first_upper, second_upper) {
            (Some(first), Some(second)) => Some(first + second),
            _ => None,
        };
        (lower, upper)
    }

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        match self.first.next() {
            Some(first) => Some(first),
            None => self.second.next(),
        }
    }
}