simple_decoder 0.1.2

The ULTIMATE lightest audio decoding in Rust: Symphonia + Rubato under the hood.
Documentation
use crate::SimpleDecoderError;
use audioadapter_buffers::direct::InterleavedSlice;
use rubato::{Fft, FixedSync, Indexing, Resampler};

#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum AudioFormat {
    #[cfg(feature = "mp3")]
    MP3,
    #[cfg(feature = "oggopus")]
    OGGOpus,
    #[cfg(feature = "oggvorbis")]
    OGGVorbis,
    #[cfg(feature = "aac")]
    AAC,
    #[cfg(feature = "wav")]
    WAV,
    #[cfg(feature = "flac")]
    FLAC,

    Unknown,
}

#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct AudioTrack {
    pub format: AudioFormat,
    pub channels: u16,
    pub sample_rate: u64,
    pub pcm: Vec<f32>,
}

impl AudioTrack {
    #[cfg(feature = "resample")]
    pub fn resample(&self, target_rate: u64) -> Result<Self, SimpleDecoderError> {
        if self.sample_rate == target_rate {
            return Ok(self.clone());
        }

        let channels = self.channels as usize;

        let mut resampler = Fft::<f32>::new(
            self.sample_rate as usize,
            target_rate as usize,
            1024,
            2,
            channels,
            FixedSync::Both,
        )
        .map_err(|e| SimpleDecoderError::ResampleError(e.to_string()))?;

        let nbr = self.pcm.len() / channels;

        let input_adapter = InterleavedSlice::new(&self.pcm, channels, nbr)
            .map_err(|e| SimpleDecoderError::ResampleError(e.to_string()))?;

        let out_len_needed = resampler.process_all_needed_output_len(nbr);
        let mut out_pcm = vec![0.0f32; out_len_needed * channels];

        let mut output_adatper = InterleavedSlice::new_mut(&mut out_pcm, channels, out_len_needed)
            .map_err(|e| SimpleDecoderError::ResampleError(e.to_string()))?;

        let mut indexing = Indexing {
            input_offset: 0,
            output_offset: 0,
            active_channels_mask: None,
            partial_len: None,
        };

        let mut input_frames_left = nbr;
        let mut input_frames_next = resampler.input_frames_next();

        while input_frames_left >= input_frames_next {
            let (frames_read, frames_writen) = resampler
                .process_into_buffer(&input_adapter, &mut output_adatper, Some(&indexing))
                .map_err(|e| SimpleDecoderError::ResampleError(e.to_string()))?;

            indexing.input_offset += frames_read;
            indexing.output_offset += frames_writen;
            input_frames_left -= frames_read;
            input_frames_next = resampler.input_frames_next();
        }

        if input_frames_left > 0 {
            indexing.partial_len = Some(input_frames_left);

            let (_, frames_written) = resampler
                .process_into_buffer(&input_adapter, &mut output_adatper, Some(&indexing))
                .map_err(|e| SimpleDecoderError::ResampleError(e.to_string()))?;

            indexing.output_offset += frames_written;
        }

        let actual = indexing.output_offset * channels;
        out_pcm.truncate(actual);

        Ok(Self {
            format: self.format,
            channels: self.channels,
            sample_rate: target_rate,
            pcm: out_pcm,
        })
    }

    pub fn rechannel(&self, target_channels: u16) -> Self {
        if self.channels == target_channels {
            return self.clone();
        }

        let mut new_pcm = Vec::new();

        match (self.channels, target_channels) {
            (2, 1) => {
                new_pcm.reserve(self.pcm.len() / 2);
                for frame in self.pcm.chunks_exact(2) {
                    let mono_sample = (frame[0] + frame[1]) * 0.5;
                    new_pcm.push(mono_sample);
                }
            }
            (1, 2) => {
                new_pcm.reserve(self.pcm.len() * 2);
                for &sample in &self.pcm {
                    new_pcm.push(sample);
                    new_pcm.push(sample);
                }
            }
            _ => {
                let src_ch = self.channels as usize;
                let dst_ch = target_channels as usize;
                let frames = self.pcm.len() / src_ch;
                new_pcm.resize(frames * dst_ch, 0.0);

                for f in 0..frames {
                    for c in 0..dst_ch {
                        let val = if c < src_ch {
                            self.pcm[f * src_ch + c]
                        } else {
                            self.pcm[f * src_ch]
                        };
                        new_pcm[f * dst_ch + c] = val;
                    }
                }
            }
        }

        Self {
            format: self.format,
            channels: target_channels,
            sample_rate: self.sample_rate,
            pcm: new_pcm,
        }
    }
}