use std::f32::consts::FRAC_PI_4;
use sim_lib_audio_graph_core::{PrepareConfig, ProcessBlock, Processor};
use crate::common::{input_sample, output_channels, prepare_channels, prepared_output_channels};
#[derive(Clone, Debug, PartialEq)]
pub struct Gain {
gain: f32,
}
impl Gain {
pub fn new(gain: f32) -> Self {
Self { gain }
}
pub fn gain(&self) -> f32 {
self.gain
}
}
impl Processor for Gain {
fn prepare(&mut self, _cfg: PrepareConfig) {}
fn reset(&mut self) {}
fn process(&mut self, block: &mut ProcessBlock<'_>) {
let frames = block.frames as usize;
for channel in 0..output_channels(block) {
for frame in 0..frames {
block.out_audio[channel][frame] = input_sample(block, channel, frame) * self.gain;
}
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Pan {
pan: f32,
}
impl Pan {
pub fn new(pan: f32) -> Self {
Self {
pan: pan.clamp(-1.0, 1.0),
}
}
pub fn gains(&self) -> (f32, f32) {
let angle = (self.pan + 1.0) * FRAC_PI_4;
(angle.cos(), angle.sin())
}
}
impl Processor for Pan {
fn prepare(&mut self, _cfg: PrepareConfig) {}
fn reset(&mut self) {}
fn process(&mut self, block: &mut ProcessBlock<'_>) {
let frames = block.frames as usize;
let (left_gain, right_gain) = self.gains();
match output_channels(block) {
0 => {}
1 => {
for frame in 0..frames {
let mono = input_sample(block, 0, frame);
block.out_audio[0][frame] = mono * (left_gain + right_gain) * 0.5;
}
}
_ => {
for frame in 0..frames {
let left = input_sample(block, 0, frame);
let right = if block.in_audio.len() > 1 {
input_sample(block, 1, frame)
} else {
left
};
block.out_audio[0][frame] = left * left_gain;
block.out_audio[1][frame] = right * right_gain;
}
}
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
struct DcState {
x1: f32,
y1: f32,
}
#[derive(Clone, Debug, PartialEq)]
pub struct DcBlocker {
coefficient: f32,
states: Vec<DcState>,
}
impl DcBlocker {
pub fn new(coefficient: f32) -> Self {
Self {
coefficient: coefficient.clamp(0.0, 0.9999),
states: Vec::new(),
}
}
#[cfg(all(test, not(debug_assertions)))]
pub(crate) fn realtime_state_snapshot(&self) -> Vec<usize> {
vec![self.states.capacity()]
}
}
impl Default for DcBlocker {
fn default() -> Self {
Self::new(0.995)
}
}
impl Processor for DcBlocker {
fn prepare(&mut self, cfg: PrepareConfig) {
prepare_channels(
&mut self.states,
cfg.out_channels as usize,
DcState::default(),
);
}
fn reset(&mut self) {
self.states.fill(DcState::default());
}
fn process(&mut self, block: &mut ProcessBlock<'_>) {
let channels = prepared_output_channels(block, self.states.len(), "DcBlocker");
let frames = block.frames as usize;
for channel in 0..channels {
let state = &mut self.states[channel];
for frame in 0..frames {
let input = input_sample(block, channel, frame);
let output = input - state.x1 + self.coefficient * state.y1;
state.x1 = input;
state.y1 = output;
block.out_audio[channel][frame] = output;
}
}
}
}