use std::sync::Arc;
use std::sync::atomic::{AtomicU32, AtomicUsize, Ordering};
use super::engine::Engine;
use super::source::AudioSource;
pub(super) struct SampleRing {
buf: Vec<AtomicU32>,
head: AtomicUsize,
tail: AtomicUsize,
}
impl SampleRing {
pub(super) fn new(capacity: usize) -> Self {
let n = (capacity + 1).max(2);
SampleRing {
buf: (0..n).map(|_| AtomicU32::new(0)).collect(),
head: AtomicUsize::new(0),
tail: AtomicUsize::new(0),
}
}
fn cap(&self) -> usize {
self.buf.len()
}
pub(super) fn len(&self) -> usize {
let t = self.tail.load(Ordering::Acquire);
let h = self.head.load(Ordering::Acquire);
(t + self.cap() - h) % self.cap()
}
fn free(&self) -> usize {
self.cap() - 1 - self.len()
}
pub(super) fn push(&self, sample: f32) -> bool {
let tail = self.tail.load(Ordering::Relaxed);
let next = (tail + 1) % self.cap();
if next == self.head.load(Ordering::Acquire) {
return false;
}
self.buf[tail].store(sample.to_bits(), Ordering::Relaxed);
self.tail.store(next, Ordering::Release);
true
}
pub(super) fn pop(&self) -> Option<f32> {
let head = self.head.load(Ordering::Relaxed);
if head == self.tail.load(Ordering::Acquire) {
return None;
}
let bits = self.buf[head].load(Ordering::Relaxed);
self.head.store((head + 1) % self.cap(), Ordering::Release);
Some(f32::from_bits(bits))
}
}
pub struct Pump<S: AudioSource> {
source: S,
ring: Arc<SampleRing>,
pump_buf: Vec<f32>,
}
impl<S: AudioSource> Pump<S> {
pub fn pump(&mut self, frames: usize) -> usize {
let frames = frames.min(self.ring.free() / 2);
if frames == 0 {
return 0;
}
if self.pump_buf.len() < frames * 2 {
self.pump_buf.resize(frames * 2, 0.0);
}
let block = &mut self.pump_buf[..frames * 2];
self.source.fill(block);
for s in block.iter() {
self.ring.push(*s);
}
frames
}
}
impl<S: AudioSource> std::ops::Deref for Pump<S> {
type Target = S;
fn deref(&self) -> &S {
&self.source
}
}
impl<S: AudioSource> std::ops::DerefMut for Pump<S> {
fn deref_mut(&mut self) -> &mut S {
&mut self.source
}
}
pub type Controller = Pump<Engine>;
pub fn spsc<S: AudioSource>(source: S, ring_frames: usize) -> (Pump<S>, Renderer) {
let ring = Arc::new(SampleRing::new(ring_frames.max(1) * 2));
(
Pump {
source,
ring: ring.clone(),
pump_buf: Vec::new(),
},
Renderer { ring },
)
}
pub struct Renderer {
pub(super) ring: Arc<SampleRing>,
}
impl AudioSource for Renderer {
fn fill(&mut self, out: &mut [f32]) -> usize {
for frame in out.chunks_mut(2) {
if frame.len() == 2 && self.ring.len() >= 2 {
frame[0] = self.ring.pop().unwrap_or(0.0);
frame[1] = self.ring.pop().unwrap_or(0.0);
} else {
frame.fill(0.0);
}
}
out.len() / 2
}
}