Untitled

mail@pastecode.io avatar
unknown
rust
2 years ago
3.3 kB
4
Indexable
Never
extern crate anyhow;
extern crate cpal;
extern crate ringbuf;

use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
// use ringbuf::RingBuffer;
use std::f32::consts::PI;

#[derive(Debug)]
struct Opt {
    latency: f32,
    input_device: String,
    output_device: String,
}

impl Opt {
    fn default() -> Self {
        let latency: f32 = 50.0;
        let input_device = "default".to_string();
        let output_device = "default".to_string();

        Opt {
            latency,
            input_device,
            output_device,
        }
    }
}

fn main() -> anyhow::Result<()> {
    let opt = Opt::default();

 
    let host = cpal::default_host();

    // Find devices.

    let output_device = if opt.output_device == "default" {
        host.default_output_device()
    } else {
        host.output_devices()?
            .find(|x| x.name().map(|y| y == opt.output_device).unwrap_or(false))
    }
    .expect("failed to find output device");

    println!("Using output device: \"{}\"", output_device.name()?);

    // We'll try and use the same configuration between streams to keep it simple.
    let config = output_device.default_output_config()?;

    // let output_data_fn = move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
    //     for sample in data.chunks_exact_mut(2) {
    //         sample[0] = 0.0;
    //         sample[1] = 0.0;
    //     }
    // };

    // Build streams.
    println!(
        "Attempting to build stream with f32 samples and `{:?}`.",
        config
    );

    assert!(config.sample_format() == cpal::SampleFormat::F32);
    assert!(config.channels() == 2);


    let output_stream = run(&output_device, &config.into()).unwrap();

    // let output_stream = output_device.build_output_stream(&config, output_data_fn, err_fn)?;
    // println!("Successfully built streams.");

    // Play the streams.
    println!(
        "Starting the input and output streams with `{}` milliseconds of latency.",
        opt.latency
    );
    // input_stream.play()?;
    output_stream.play()?;

    // Run for 3 seconds before closing.
    println!("Playing for 3 seconds... ");
    std::thread::sleep(std::time::Duration::from_secs(3));
    // drop(input_stream);
    drop(output_stream);
    println!("Done!");
    Ok(())
}

pub fn run(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<cpal::Stream, anyhow::Error>
{
    let mut audio_closure = build_closure(config);

    let stream = device.build_output_stream(
        config,
        move |buffer: &mut [f32], _: &cpal::OutputCallbackInfo| {
            audio_closure(buffer);
        },
        err_fn,
    )?;

    Ok(stream)
}

fn build_closure(config: &cpal::StreamConfig) -> impl FnMut(&mut [f32]) {
    let sample_rate = config.sample_rate.0 as f32;
    // Callback data
    let mut accum = 0.0;
    let freq = 440.0  / sample_rate;
    move |buffer: &mut [f32]| {
        for sample in buffer.chunks_mut(2) {
            accum += freq;
            accum = accum.fract();
            let out = (accum* 2.0 * PI).sin();
            sample[0] = out;
            sample[1] = out;
        }
    }
}

fn err_fn(err: cpal::StreamError) {
    eprintln!("an error occurred on stream: {}", err);
}