voxio 0.1.2

A lightweight audio playback engine
Documentation
use rubato::audioadapter_buffers::direct::InterleavedSlice;
use rubato::{Fft, FixedSync, Resampler};

use crate::{RESAMPLER_CHUNK_SIZE, RESAMPLER_SUBCHUNK_SIZE, error::VoxError};

pub struct VoxResampler {
    resampler: Fft<f32>,
    output_buf: Vec<f32>,
    pub input_rate: u32,
    channels: usize,
}

impl VoxResampler {
    pub fn new(
        input_rate: u32,
        output_rate: u32,
        channels: usize,
    ) -> Result<Option<Self>, VoxError> {
        if input_rate == output_rate {
            return Ok(None);
        }

        let resampler = Fft::<f32>::new(
            input_rate as usize,
            output_rate as usize,
            RESAMPLER_CHUNK_SIZE,
            RESAMPLER_SUBCHUNK_SIZE,
            channels,
            FixedSync::Input,
        )
        .map_err(|e| VoxError::Resampler(e.to_string()))?;

        let output_buf = vec![0.0f32; resampler.output_frames_max() * channels];

        Ok(Some(Self {
            resampler,
            output_buf,
            input_rate,
            channels,
        }))
    }

    pub fn process<F>(&mut self, pending: &mut Vec<f32>, mut output: F) -> Result<(), VoxError>
    where
        F: FnMut(&[f32]),
    {
        let frames_needed = self.resampler.input_frames_next();
        let samples_needed = frames_needed * self.channels;

        while pending.len() >= samples_needed {
            let input = InterleavedSlice::new(&pending[..samples_needed], self.channels, frames_needed)
                .map_err(|e| VoxError::Resampler(e.to_string()))?;

            let out_frames_max = self.resampler.output_frames_max();
            let mut out = InterleavedSlice::new_mut(&mut self.output_buf, self.channels, out_frames_max)
                .map_err(|e| VoxError::Resampler(e.to_string()))?;

            let (_, out_frames) = self
                .resampler
                .process_into_buffer(&input, &mut out, None)
                .map_err(|e| VoxError::Resampler(e.to_string()))?;

            pending.drain(..samples_needed);
            output(&self.output_buf[..out_frames * self.channels]);
        }

        Ok(())
    }

    pub fn flush<F>(&mut self, pending: &mut Vec<f32>, output: F) -> Result<(), VoxError>
    where
        F: FnMut(&[f32]),
    {
        if pending.is_empty() {
            return Ok(());
        }

        let frames_needed = self.resampler.input_frames_next();
        let samples_needed = frames_needed * self.channels;
        pending.resize(samples_needed, 0.0);
        self.process(pending, output)
    }

    pub fn reset(&mut self) {
        self.resampler.reset();
    }
}