Partial audio implementation
Some checks failed
Cargo Build & Test / Rust project - latest (stable) (push) Failing after 10s
Some checks failed
Cargo Build & Test / Rust project - latest (stable) (push) Failing after 10s
This commit is contained in:
94
src/audio.rs
Normal file
94
src/audio.rs
Normal file
@@ -0,0 +1,94 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user