audio-lab 0.1.0

Toolkit for audio research and testing
Documentation
use std::time::Duration;

use audio_host::{AudioBackend, AudioBlock, AudioBlockMut, AudioHost, Config};

use crate::signal::TimeSignal;

pub fn play(signal: &TimeSignal) -> Result<(), audio_host::Error> {
    let num_output_channels = signal.num_channels() as u16;
    let sample_rate = signal.sample_rate().round() as u32;
    let num_frames = 512;
    let interleaved: Vec<f32> = signal.time_data().t().iter().map(|&s| s as f32).collect();
    let total_frames = signal.num_time_steps();
    let mut next_frame = 0usize;

    let mut host = AudioHost::new()?;
    host.start(
        Config::default()
            .with_input_channels(0)
            .with_output_channels(num_output_channels)
            .with_sample_rate(sample_rate)
            .with_num_frames(num_frames),
        move |_input, mut output| {
            for frame in 0..output.num_frames() {
                let src_frame = next_frame;
                next_frame += 1;

                for ch in 0..output.num_channels() as usize {
                    let sample = if src_frame < total_frames {
                        interleaved[src_frame * num_output_channels as usize + ch]
                    } else {
                        0.0
                    };
                    *output.sample_mut(ch as u16, frame) = sample;
                }
            }
        },
    )?;

    std::thread::sleep(Duration::from_secs_f64(
        signal.length_in_seconds() + num_frames as f64 / sample_rate as f64,
    ));
    host.stop()?;
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    #[ignore]
    fn play_audio() {
        use std::f64::consts::TAU;

        let sample_rate = 48_000.0;
        let seconds = 2.0;
        let num_time_steps = (sample_rate * seconds) as usize;
        let frequency = 440.0;

        let data = ndarray::Array2::from_shape_fn((2, num_time_steps), |(_, frame)| {
            let t = frame as f64 / sample_rate;
            0.2 * (TAU * frequency * t).sin()
        });

        let signal = TimeSignal::new(data, sample_rate).unwrap();
        play(&signal).unwrap();
    }
}