use std::sync::{
Arc,
atomic::{AtomicU32, Ordering},
};
use crate::Frame;
use super::resources::Resources;
#[derive(Debug)]
pub(crate) struct RendererShared {
pub(crate) sample_rate: AtomicU32,
}
impl RendererShared {
#[must_use]
pub fn new(sample_rate: u32) -> Self {
Self {
sample_rate: AtomicU32::new(sample_rate),
}
}
}
pub struct Renderer {
dt: f64,
shared: Arc<RendererShared>,
resources: Resources,
internal_buffer_size: usize,
temp_buffer: Vec<Frame>,
}
impl Renderer {
#[must_use]
pub(crate) fn new(
shared: Arc<RendererShared>,
internal_buffer_size: usize,
resources: Resources,
) -> Self {
Self {
dt: 1.0 / shared.sample_rate.load(Ordering::SeqCst) as f64,
shared,
resources,
internal_buffer_size,
temp_buffer: vec![Frame::ZERO; internal_buffer_size],
}
}
pub fn on_change_sample_rate(&mut self, sample_rate: u32) {
self.dt = 1.0 / sample_rate as f64;
self.shared.sample_rate.store(sample_rate, Ordering::SeqCst);
self.resources.mixer.on_change_sample_rate(sample_rate);
}
pub fn on_start_processing(&mut self) {
self.resources.mixer.on_start_processing();
self.resources.clocks.on_start_processing();
self.resources.listeners.on_start_processing();
self.resources.modulators.on_start_processing();
}
pub fn process(&mut self, out: &mut [f32], num_channels: u16) {
for chunk in out.chunks_mut(self.internal_buffer_size * num_channels as usize) {
self.process_chunk(chunk, num_channels);
}
}
fn process_chunk(&mut self, chunk: &mut [f32], num_channels: u16) {
let num_frames = chunk.len() / num_channels as usize;
self.resources.modulators.process(
self.dt * num_frames as f64,
&self.resources.clocks,
&self.resources.listeners,
);
self.resources.clocks.update(
self.dt * num_frames as f64,
&self.resources.modulators,
&self.resources.listeners,
);
self.resources.listeners.update(
self.dt * num_frames as f64,
&self.resources.clocks,
&self.resources.modulators,
);
self.resources.mixer.process(
&mut self.temp_buffer[..num_frames],
self.dt,
&self.resources.clocks,
&self.resources.modulators,
&self.resources.listeners,
);
for (i, channels) in chunk.chunks_mut(num_channels.into()).enumerate() {
let mut frame = self.temp_buffer[i];
frame.left = frame.left.clamp(-1.0, 1.0);
frame.right = frame.right.clamp(-1.0, 1.0);
if num_channels == 1 {
channels[0] = (frame.left + frame.right) / 2.0;
} else {
channels[0] = frame.left;
channels[1] = frame.right;
for channel in channels.iter_mut().skip(2) {
*channel = 0.0;
}
}
}
self.temp_buffer.fill(Frame::ZERO);
}
}