use no_denormals::*;
pub struct Saturation {
drive_alpha_plus: f32,
drive_alpha_minus: f32,
compression_beta_plus: f32,
compression_beta_minus: f32,
bias_delta: f32,
flip_polarity: bool,
norm_factor_plus: f32,
norm_factor_minus: f32,
}
impl Saturation {
pub fn new(
alpha_plus: f32,
alpha_minus: f32,
beta_plus: f32,
beta_minus: f32,
delta_bias: f32,
flip: bool,
) -> Self {
let drive_alpha_plus = alpha_plus.max(1e-4);
let drive_alpha_minus = alpha_minus.max(1e-4);
let norm_factor_plus = 1.0 / (1.0 + drive_alpha_plus).log2();
let norm_factor_minus = 1.0 / (1.0 + drive_alpha_minus).log2();
Self {
drive_alpha_plus,
drive_alpha_minus,
compression_beta_plus: beta_plus,
compression_beta_minus: beta_minus,
bias_delta: delta_bias,
flip_polarity: flip,
norm_factor_plus,
norm_factor_minus,
}
}
#[inline]
pub fn process(&self, input_sample: f32) -> f32 {
let output_value = if input_sample >= self.bias_delta {
let relative_input = input_sample - self.bias_delta;
let log_out = (1.0 + self.drive_alpha_plus * relative_input).log2();
self.compression_beta_plus * (log_out * self.norm_factor_plus)
} else {
let relative_input = self.bias_delta - input_sample;
let log_out = (1.0 + self.drive_alpha_minus * relative_input).log2();
-self.compression_beta_minus * (log_out * self.norm_factor_minus)
};
if self.flip_polarity {
-output_value
} else {
output_value
}
}
pub fn run(&self, input: &[f32], output: &mut [f32]) {
unsafe {
no_denormals(|| {
for index in 0..input.len().min(output.len()) {
output[index] = self.process(input[index]);
}
});
}
}
}
#[cfg(feature = "sim")]
pub struct TubeSaturation {
stage: crate::sim::components::tubes::TriodeStage,
}
#[cfg(feature = "sim")]
impl TubeSaturation {
pub fn new(sample_rate: f32) -> Self {
Self::with_params(
sample_rate,
crate::sim::components::tubes::PARAMS_12AX7.clone(),
)
}
pub fn with_params(
sample_rate: f32,
params: crate::sim::components::tubes::TriodeParams,
) -> Self {
use crate::sim::components::CircuitComponent;
let mut stage = crate::sim::components::tubes::TriodeStage::new(params);
stage.prepare(sample_rate);
Self { stage }
}
pub fn set_sample_rate(&mut self, sample_rate: f32) {
use crate::sim::components::CircuitComponent;
self.stage.prepare(sample_rate);
}
#[inline]
pub fn process(&mut self, input_sample: f32) -> f32 {
use crate::sim::components::CircuitComponent;
let input = [input_sample];
let mut output = [0.0f32];
self.stage.process_block(&input, &mut output);
output[0]
}
pub fn run(&mut self, input: &[f32], output: &mut [f32]) {
use crate::sim::components::CircuitComponent;
let len = input.len().min(output.len());
unsafe {
no_denormals(|| {
self.stage.process_block(&input[..len], &mut output[..len]);
});
}
}
}