use std::{ sync::{ atomic::AtomicBool, mpsc::{channel, Sender, TryRecvError}, Arc }, time::Instant, }; use cpal::{ Device, FrameCount, Host, SampleFormat, Stream, traits::{DeviceTrait, HostTrait, StreamTrait}, }; use ringbuf::{ HeapRb, SharedRb, traits::{Consumer, Observer, Producer, Split}, wrap::caching::Caching, }; type SampleTx = Caching>, true, false>; // TODO: Audio should be run through a low-pass filter, // a high-pass filter, as well as some kind of envelope // around pause events pub struct Audio { _host: Host, _device: Device, _stream: Stream, rb: SampleTx, last: usize, max: usize, paused: Arc, } impl Audio { pub fn init() -> Self { const BUFFER_SIZE: usize = 1 << 10; let host = cpal::default_host(); let device = host.default_output_device().unwrap(); // let mut configs = device.supported_output_configs().unwrap(); // dbg!(configs.find(|c| c.sample_format() == SampleFormat::U8)); // let v = dbg!(configs.next().unwrap().buffer_size()); // let mut t = 0; let (prod, mut cons) = SharedRb::new(BUFFER_SIZE * 1024 * 1024).split(); let paused = Arc::new(AtomicBool::new(true)); let paused_inner = Arc::clone(&paused); let stream = device .build_output_stream( &cpal::StreamConfig { channels: 1, sample_rate: 60 * 3723, buffer_size: cpal::BufferSize::Fixed(BUFFER_SIZE as FrameCount), }, move |a: &mut [u8], _b| { if !paused_inner.load(std::sync::atomic::Ordering::Acquire) { let taken = cons.pop_slice(a); a[taken..].fill(128); } }, |e| eprintln!("Audio: {e}"), None, ) .unwrap(); stream.play().unwrap(); Self { _host: host, _device: device, _stream: stream, rb: prod, paused, last: 0, max: 0, } } pub fn pause(&mut self) { self.paused.store(true, std::sync::atomic::Ordering::Release); } pub fn submit(&mut self, samples: &[u8]) { let start = self.rb.occupied_len(); self.max = self.max.max(self.last - start); println!("Buffer size: {:07}, Max: {:07}", start, self.max); println!( "Adding: {:07}, Played: {:07}", samples.len(), self.last - start ); self.rb.push_slice(samples); self.last = self.rb.occupied_len(); if self.last > 9000 { self.paused.store(false, std::sync::atomic::Ordering::Release); } } }