Skip to content

Loading and playing a wav file

Dionysis Athinaios edited this page Jun 1, 2022 · 1 revision

This example assumes that you have an assets folder at the root of your project. Just change the file name from "a11wlk01.wav" to the one you are using. Dependencies for this example are:

fundsp = "0.6.4"
cpal = "0.13.5"
anyhow = "1.0.56"
find_folder = "0.3.0"
hound = "3.4.0"
dasp = "0.11.0"
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use fundsp::hacker::*;
use std::sync::Arc;

fn main() {
    let host = cpal::default_host();

    let device = host
        .default_output_device()
        .expect("failed to find a default output device");
    let config = device.default_output_config().unwrap();

    match config.sample_format() {
        cpal::SampleFormat::F32 => run::<f32>(&device, &config.into()).unwrap(),
        cpal::SampleFormat::I16 => run::<i16>(&device, &config.into()).unwrap(),
        cpal::SampleFormat::U16 => run::<u16>(&device, &config.into()).unwrap(),
    }
}

fn run<T>(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<(), anyhow::Error>
where
    T: cpal::Sample,
{
    let sample_rate = config.sample_rate.0 as f64;
    let channels = config.channels as usize;

    let assets = find_folder::Search::ParentsThenKids(5, 5)
        .for_folder("assets")
        .unwrap();

    let reader = hound::WavReader::open(assets.join("a11wlk01.wav")).unwrap();

    let spec = reader.spec();
    // println!("{:?}", spec.channels);
    // println!("{:?}", spec.sample_rate);
    // println!("{:?}", samples.len());

    let samples = reader.into_samples::<i16>()
        .filter_map( |s|
            match s {
                Ok(sample) => Some(dasp::sample::conv::i16::to_f64(sample)),
                Err(_) => None
            }
        ).collect::<Vec<f64>>();

    let mut wavefile = Wave64::with_capacity(
        spec.channels.into(),
        spec.sample_rate.into(),
        samples.len()
    );

    wavefile.resize(samples.len());

    for (pos, s) in samples.iter().enumerate() {
        wavefile.set(0, pos, *s);
    };

    let wav_arc: Arc<Wave64> = Arc::new(wavefile);

    let c = wave64(wav_arc, 0, Some(0));

    let c = (c | lfo(|t| (xerp11(110.0, 11000.0, sin_hz(0.15, t)), 0.4))) >> moog();

    let c = c >> split::<U2>();

    let mut c = c
    >> (declick() | declick()) >> (dcblock() | dcblock())
    >> limiter_stereo((1.0, 5.0));

    c.reset(Some(sample_rate));
    let mut next_value = move || c.get_stereo();

    let err_fn = |err| eprintln!("an error occurred on stream: {}", err);

    let stream = device.build_output_stream(
        config,
        move |data: &mut [T], _: &cpal::OutputCallbackInfo| {
            write_data(data, channels, &mut next_value)
        },
        err_fn,
    )?;

    stream.play()?;

    std::thread::sleep(std::time::Duration::from_millis(5000));

    Ok(())
}

fn write_data<T>(output: &mut [T], channels: usize, next_sample: &mut dyn FnMut() -> (f64, f64))
where
    T: cpal::Sample,
{
    for frame in output.chunks_mut(channels) {
        let sample = next_sample();
        let left: T = cpal::Sample::from::<f32>(&(sample.0 as f32));
        let right: T = cpal::Sample::from::<f32>(&(sample.1 as f32));

        for (channel, sample) in frame.iter_mut().enumerate() {
            if channel & 1 == 0 {
                *sample = left;
            } else {
                *sample = right;
            }
        }
    }
}
Clone this wiki locally