Some checks failed
Cargo Build & Test / Rust project - latest (stable) (push) Failing after 10s
95 lines
2.8 KiB
Rust
95 lines
2.8 KiB
Rust
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<Arc<HeapRb<u8>>, 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<AtomicBool>,
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|