use std::sync::Arc; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use std::ops::{Add, AddAssign, Sub}; use parking_lot::RwLock; use std::time::Duration; use std::thread; use cpal::SampleFormat; use crate::beep::osc::{Instrument, Oscillator}; pub mod osc; struct AudioContext { device: cpal::Device, sample_format: SampleFormat, config: cpal::StreamConfig } fn al_init() -> Result { let host = cpal::default_host(); let device = host.default_output_device() .ok_or_else(|| anyhow::anyhow!("No audio output device!"))?; let config = device.default_output_config()?; Ok(AudioContext { device, sample_format: config.sample_format(), config: config.into() }) } pub fn beep() -> Result<(), anyhow::Error> { let ac = al_init()?; match ac.sample_format { cpal::SampleFormat::F32 => run::(&ac.device, &ac.config.into())?, cpal::SampleFormat::I16 => run::(&ac.device, &ac.config.into())?, cpal::SampleFormat::U16 => run::(&ac.device, &ac.config.into())?, } Ok(()) } fn run(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<(), anyhow::Error> where T: cpal::Sample, { let sample_rate = config.sample_rate.0 as f32; let channels = config.channels as usize; println!("SR={}",sample_rate); // Produce a sinusoid of maximum amplitude. let mut ins = Instrument::new(vec![ Oscillator::new(440.0, 1.0, sample_rate), //Oscillator::new(441.0, 1.0, sample_rate), ], sample_rate); let instrument = Arc::new(parking_lot::RwLock::new(ins)); let err_fn = |err| eprintln!("an error occurred on stream: {}", err); let m_instrument = instrument.clone(); let stream = device.build_output_stream( config, move |data: &mut [T], _: &cpal::OutputCallbackInfo| { write_data(data, channels, &m_instrument) }, err_fn, )?; stream.play()?; // instrument.write().normalize(false); // instrument.write().set_amp(1.0); // thread::sleep(Duration::from_millis(500)); // // instrument.write().set_amp(0.0); // thread::sleep(Duration::from_millis(250)); instrument.write().set_amp(1.0); instrument.write().normalize(true); thread::sleep(Duration::from_millis(500)); instrument.write().set_amp(0.0); thread::sleep(Duration::from_millis(250)); instrument.write().set_amp(0.5); thread::sleep(Duration::from_millis(500)); instrument.write().set_amp(0.0); thread::sleep(Duration::from_millis(250)); instrument.write().fade_amp(1.0, Duration::from_millis(10)); instrument.write().waveforms[0].fade_balance(-1.0, Duration::from_millis(10)); thread::sleep(Duration::from_millis(500)); instrument.write().fade_amp(0.0, Duration::from_millis(10)); thread::sleep(Duration::from_millis(500)); /* //instrument.write().set_amp_fade(0.0, 4.0); thread::sleep(Duration::from_millis(1000)); instrument.write().waveforms[1].fade_amp(0.0, Duration::from_millis(500)); thread::sleep(Duration::from_millis(500)); instrument.write().waveforms[0].fade_balance(-1.0, Duration::from_millis(1000)); thread::sleep(Duration::from_millis(1000)); instrument.write().waveforms[0].fade_balance(1.0, Duration::from_millis(2000)); instrument.write().waveforms[0].fade_freq(880.0, Duration::from_millis(1000)); thread::sleep(Duration::from_millis(2000)); instrument.write().waveforms[0].fade_balance(-1.0, Duration::from_millis(1000)); instrument.write().waveforms[0].fade_amp(0.0, Duration::from_millis(1000)); thread::sleep(Duration::from_millis(1000)); */ // for _ in 0..10 // { // instrument.write().harmonics[0].set_balance_fade(-1.0, 0.1); // thread::sleep(Duration::from_millis(100)); // instrument.write().harmonics[0].set_balance_fade(1.0, 0.1); // thread::sleep(Duration::from_millis(100)); // } // // instrument.write().harmonics[0].set_balance_fade(0.0, 0.5); // instrument.write().harmonics[0].set_amp_fade(0.0, 0.05); // thread::sleep(Duration::from_millis(200)); Ok(()) } fn write_data(output: &mut [T], channels: usize, instrument: &Arc>) where T: cpal::Sample, { let mut instrument = instrument.write(); for frame in output.chunks_mut(channels) { let sample = instrument.sample(); if channels == 1 { frame[0] = cpal::Sample::from::(&((sample.left + sample.right) / 2.0)); } else { frame[0] = cpal::Sample::from::(&sample.left); frame[1] = cpal::Sample::from::(&sample.right); } } }