#[cfg(any(feature = "standalone", feature = "clap-plugin", test))]
use std::sync::atomic::Ordering;
#[cfg(any(feature = "standalone", feature = "clap-plugin", test))]
pub const MAX_BRIDGE_BUF: usize = 8192;
#[cfg(any(feature = "standalone", feature = "clap-plugin", test))]
pub const MAX_RESAMP_BUF: usize = 8192;
#[cfg(any(feature = "standalone", feature = "clap-plugin", test))]
#[repr(align(128))]
pub struct BridgeBuffer {
pub buf_l: [f32; MAX_BRIDGE_BUF],
pub buf_r: [f32; MAX_BRIDGE_BUF],
pub n_samples: u32,
}
#[cfg(any(feature = "standalone", feature = "clap-plugin", test))]
#[repr(align(128))]
pub struct DspBridge {
pub buffers: [BridgeBuffer; 2],
pub active_read_idx: std::sync::atomic::AtomicUsize,
pub generation: std::sync::atomic::AtomicU64,
pub consumed_gen: std::sync::atomic::AtomicU64,
pub dropped_frames: std::sync::atomic::AtomicU32,
}
#[cfg(any(feature = "standalone", feature = "clap-plugin", test))]
impl DspBridge {
pub fn drain_dropped_frames(&self) -> u32 {
self.dropped_frames.swap(0, Ordering::Relaxed)
}
}
#[cfg(any(feature = "standalone", feature = "clap-plugin", test))]
#[derive(Clone, Copy)]
pub struct BridgeRef(*mut DspBridge);
#[cfg(any(feature = "standalone", feature = "clap-plugin", test))]
impl BridgeRef {
#[inline(always)]
pub unsafe fn new(ptr: *mut DspBridge) -> Self {
assert!(!ptr.is_null());
Self(ptr)
}
#[inline(always)]
pub fn null() -> Self {
Self(std::ptr::null_mut())
}
#[inline(always)]
pub fn is_null(self) -> bool {
self.0.is_null()
}
#[inline(always)]
pub unsafe fn as_ptr(self) -> *mut DspBridge {
self.0
}
}
#[cfg(any(feature = "standalone", feature = "clap-plugin", test))]
#[derive(Clone, Copy)]
pub struct DspBridgeWriter(std::ptr::NonNull<DspBridge>);
#[cfg(any(feature = "standalone", feature = "clap-plugin", test))]
unsafe impl Send for DspBridgeWriter {}
#[cfg(any(feature = "standalone", feature = "clap-plugin", test))]
unsafe impl Sync for DspBridgeWriter {}
#[cfg(any(feature = "standalone", feature = "clap-plugin", test))]
impl DspBridgeWriter {
#[inline(always)]
pub unsafe fn new(ptr: *mut DspBridge) -> Self {
assert!(!ptr.is_null());
Self(unsafe { std::ptr::NonNull::new_unchecked(ptr) })
}
#[inline(always)]
pub fn from_ref(r: BridgeRef) -> Option<Self> {
std::ptr::NonNull::new(r.0).map(Self)
}
pub fn write_block(
&self,
resamp_out_l: &[f32],
resamp_out_r: &[f32],
n_pw: usize,
process_mono: bool,
) {
unsafe {
let bridge = self.0.as_ref();
let current_gen = bridge.generation.load(Ordering::Relaxed);
let consumed_gen = bridge.consumed_gen.load(Ordering::Acquire);
if current_gen > consumed_gen {
let _ =
bridge
.dropped_frames
.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |v| {
Some(v.saturating_add(1))
});
return;
}
let back_idx = 1 - bridge.active_read_idx.load(Ordering::Relaxed);
let back_buf = &mut (*self.0.as_ptr()).buffers[back_idx];
let n_bridge = n_pw.min(MAX_BRIDGE_BUF);
core::ptr::copy_nonoverlapping(
resamp_out_l.as_ptr(),
back_buf.buf_l.as_mut_ptr(),
n_bridge,
);
if process_mono {
core::ptr::copy_nonoverlapping(
resamp_out_l.as_ptr(),
back_buf.buf_r.as_mut_ptr(),
n_bridge,
);
} else {
core::ptr::copy_nonoverlapping(
resamp_out_r.as_ptr(),
back_buf.buf_r.as_mut_ptr(),
n_bridge,
);
}
back_buf.n_samples = n_bridge as u32;
bridge.active_read_idx.store(back_idx, Ordering::Release);
bridge.generation.store(current_gen + 1, Ordering::Release);
}
}
pub fn write_silence(&self) {
unsafe {
let bridge = self.0.as_ref();
let current_gen = bridge.generation.load(Ordering::Relaxed);
let consumed_gen = bridge.consumed_gen.load(Ordering::Acquire);
if current_gen > consumed_gen {
let _ =
bridge
.dropped_frames
.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |v| {
Some(v.saturating_add(1))
});
return;
}
let back_idx = 1 - bridge.active_read_idx.load(Ordering::Relaxed);
let back_buf = &mut (*self.0.as_ptr()).buffers[back_idx];
back_buf.n_samples = 0;
bridge.active_read_idx.store(back_idx, Ordering::Release);
bridge.generation.store(current_gen + 1, Ordering::Release);
}
}
}
#[cfg(any(feature = "standalone", feature = "clap-plugin", test))]
#[derive(Clone, Copy)]
pub struct DspBridgeReader(std::ptr::NonNull<DspBridge>);
#[cfg(any(feature = "standalone", feature = "clap-plugin", test))]
unsafe impl Send for DspBridgeReader {}
#[cfg(any(feature = "standalone", feature = "clap-plugin", test))]
unsafe impl Sync for DspBridgeReader {}
#[cfg(any(feature = "standalone", feature = "clap-plugin", test))]
impl DspBridgeReader {
#[inline(always)]
pub unsafe fn new(ptr: *mut DspBridge) -> Self {
assert!(!ptr.is_null());
Self(unsafe { std::ptr::NonNull::new_unchecked(ptr) })
}
#[inline(always)]
pub fn from_ref(r: BridgeRef) -> Option<Self> {
std::ptr::NonNull::new(r.0).map(Self)
}
pub fn read_block<F, R>(&self, last_bridge_gen: &mut u64, f: F) -> Option<R>
where
F: FnOnce(&[f32], &[f32]) -> R,
{
unsafe {
let bridge = self.0.as_ref();
let current_gen = bridge.generation.load(Ordering::Acquire);
if current_gen == *last_bridge_gen {
return None;
}
*last_bridge_gen = current_gen;
bridge.consumed_gen.store(current_gen, Ordering::Release);
let read_idx = bridge.active_read_idx.load(Ordering::Acquire);
let front_buf = &bridge.buffers[read_idx];
let n_samples = front_buf.n_samples as usize;
if n_samples == 0 || n_samples > MAX_BRIDGE_BUF {
return None;
}
Some(f(
&front_buf.buf_l[..n_samples],
&front_buf.buf_r[..n_samples],
))
}
}
}