ljud 0.0.5

Graph-based music DSP library with a focus on flexibility.
Documentation
use crate::node::Node;
use crate::{svec, Buffer, Context};
use hound::WavReader;
use smallvec::SmallVec;
use std::path::Path;

pub struct AudioPlayer {
    data: SmallVec<[Vec<f32>; 2]>,
    position: usize,
    looping: bool,
}

impl AudioPlayer {
    pub fn new<P: AsRef<Path>>(path: P) -> Self {
        let mut reader = WavReader::open(path).expect("Failed to open WAV file");
        let spec = reader.spec();
        let num_channels = spec.channels as usize;
        let mut data: SmallVec<[Vec<f32>; 2]> = svec![];

        for _ in 0..num_channels {
            data.push(Vec::new());
        }

        let mut sample_count = 0;
        for result in reader.samples::<i16>() {
            let sample = result.unwrap() as f32 / i16::MAX as f32;
            let channel = sample_count % num_channels;
            data[channel].push(sample);
            sample_count += 1;
        }
        Self {
            data,
            position: 0,
            looping: false,
        }
    }
    pub fn looping(mut self, looping: bool) -> Self {
        self.looping = looping;
        self
    }
    pub fn boxed(self) -> Box<dyn Node + Send> {
        Box::new(self)
    }
}

impl Node for AudioPlayer {
    fn process(&mut self, buffer: &mut Buffer, _context: &mut Context) {
        for (channel, buffer_channel) in self.data.iter().zip(buffer.iter_mut()) {
            for (sample_idx, buffer_sample) in buffer_channel.iter_mut().enumerate() {
                let position = self.position + sample_idx;
                if self.looping {
                    *buffer_sample = channel[position % channel.len()];
                } else {
                    if position < channel.len() {
                        *buffer_sample = channel[position];
                    } else {
                        *buffer_sample = 0.0;
                    }
                }
            }
        }
        self.position += buffer[0].len();
        if self.looping && self.position >= self.data[0].len() {
            self.position %= self.data[0].len();
        }
    }
}

pub fn audio_player<P: AsRef<Path>>(path: P) -> AudioPlayer {
    AudioPlayer::new(path)
}