use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use std::time::Duration;
use std::f32::consts::PI;
use std::sync::{Arc, Mutex};
use std::thread;
pub fn play_tone(frequency: u32, duration_ms: u64, volume: f32, latency: Option<Duration>) {
let host = cpal::default_host();
let device = host.default_output_device().expect("No output device available");
let config = device.default_output_config().unwrap();
let config: cpal::StreamConfig = config.into();
let sample_rate = config.sample_rate.0 as f32;
let sample_count = (sample_rate * duration_ms as f32 / 1000.0) as usize;
let mut sample_clock = 0f32;
let samples: Vec<f32> = (0..sample_count)
.map(|_| {
let value = (sample_clock * frequency as f32 * 2.0 * PI / sample_rate).sin();
sample_clock = (sample_clock + 1.0) % sample_rate;
value * volume })
.collect();
let samples = Arc::new(Mutex::new(samples));
let samples_for_thread = samples.clone();
let stream = device.build_output_stream(
&config,
move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
let mut samples = samples_for_thread.lock().unwrap();
for sample in data.iter_mut() {
if let Some(value) = samples.pop() {
*sample = value;
} else {
*sample = 0.0;
}
}
},
err_fn,
latency ).unwrap();
stream.play().unwrap();
thread::sleep(Duration::from_millis(duration_ms));
}
fn err_fn(err: cpal::StreamError) {
eprintln!("An error occurred on the audio stream: {}", err);
}