futuresdr 0.0.41

An Experimental Async SDR Runtime for Heterogeneous Architectures.
Documentation
use rodio::Decoder;
use rodio::source::Buffered;
use rodio::source::Source;
use std::fs::File;
use std::io::BufReader;

use crate::runtime::dev::prelude::*;

/// Read an audio file and output its samples.
///
/// # Stream Inputs
///
/// No stream inputs.
///
/// # Stream Outputs
///
/// `output`: Decoded `f32` audio samples.
///
/// # Usage
/// ```no_run
/// use futuresdr::blocks::audio::FileSource;
///
/// let source = FileSource::new("input.wav");
/// ```
#[derive(Block)]
pub struct FileSource<O = DefaultCpuWriter<f32>>
where
    O: CpuBufferWriter<Item = f32>,
{
    #[output]
    output: O,
    src: Buffered<Decoder<BufReader<File>>>,
}

impl FileSource<DefaultCpuWriter<f32>> {
    /// Create FileSource block with the default stream buffer.
    pub fn new(file: &str) -> Self {
        Self::with_buffer(file)
    }
}

impl<O> FileSource<O>
where
    O: CpuBufferWriter<Item = f32>,
{
    /// Create FileSource block with a custom stream buffer.
    pub fn with_buffer(file: &str) -> Self {
        let file = BufReader::new(File::open(file).unwrap());
        let source = Decoder::new(file).unwrap();

        FileSource {
            output: O::default(),
            src: source.buffered(),
        }
    }
    /// Get sample rate
    pub fn sample_rate(&self) -> u32 {
        self.src.sample_rate().into()
    }
    /// Get number of samples
    pub fn channels(&self) -> u16 {
        self.src.channels().into()
    }
}

#[doc(hidden)]
impl<O> Kernel for FileSource<O>
where
    O: CpuBufferWriter<Item = f32>,
{
    async fn work(
        &mut self,
        io: &mut WorkIo,
        _mo: &mut MessageOutputs,
        _meta: &mut BlockMeta,
    ) -> Result<()> {
        let out = self.output.slice();
        let o_len = out.len();

        let mut n = 0;
        for (i, v) in self.src.by_ref().take(out.len()).enumerate() {
            out[i] = v;
            n += 1;
        }

        self.output.produce(n);
        if n < o_len {
            io.finished = true;
        }

        Ok(())
    }
}