// Lock-Free real-time audio pipeline on Cubeb SPSC ring buffers
pub fn process_audio_callback(
output_buffer: &mut [f32],
cons_main: &mut Consumer<f32>,
cons_amb: &mut Consumer<f32>,
dsp: &mut DspProcessor,
quick_dsp: &mut QuickDspState,
settings: &SharedAudioSettings
) -> isize {
let frames_requested = output_buffer.len() / 2;
let mut amb_buffer = vec![0.0f32; output_buffer.len()];
let amb_popped = cons_amb.pop_slice(&mut amb_buffer);
let popped = cons_main.pop_slice(output_buffer);
let vol = settings.get_float(&settings.volume);
let bal = settings.get_float(&settings.balance_lr);
let pitch = settings.get_float(&settings.pitch);
let reverb_wet = settings.get_float(&settings.reverb_wet);
let reverb_room = settings.get_float(&settings.reverb_room);
let crossfeed = settings.get_float(&settings.crossfeed);
let l_gain = if bal > 0.0 { 1.0 - bal } else { 1.0 };
let r_gain = if bal < 0.0 { 1.0 + bal } else { 1.0 };
for i in (0..popped).step_by(2) {
let mut l = output_buffer[i];
let mut r = output_buffer[i+1];
let (l_pt, r_pt) = quick_dsp.pitch_shifter.process(l, r, pitch);
let (l_rev, r_rev) = quick_dsp.reverb.process(l_pt, r_pt, reverb_wet, reverb_room);
let (l_cf, r_cf) = quick_dsp.crossfeed.process(l_rev, r_rev, crossfeed);
let (proc_l, proc_r) = dsp.process_stereo(l_cf, r_cf);
l = proc_l * l_gain;
r = proc_r * r_gain;
if i < amb_popped {
l += amb_buffer[i];
r += amb_buffer[i+1];
}
output_buffer[i] = l * vol;
output_buffer[i+1] = r * vol;
}
frames_requested as isize
} // 3-Band Linkwitz-Riley Crossover with Envelope Tracked Compression
impl Goodizer {
pub fn process_frame(&mut self, mut l: f32, mut r: f32) -> (f32, f32) {
if self.amount <= 0.0 { return (l, r); }
let (dry_l, dry_r) = (l, r);
// 1. Поканальный кроссовер (LPF на 250 Гц, HPF на 4000 Гц)
let low_l = self.lpf_l.process(l);
let low_r = self.lpf_r.process(r);
let high_l = self.hpf_l.process(l);
let high_r = self.hpf_r.process(r);
let mid_l = l - low_l - high_l;
let mid_r = r - low_r - high_r;
// 2. Поканальная компрессия выделенных частотных диапазонов
let comp_low_l = self.c_low_l.process(low_l);
let comp_low_r = self.c_low_r.process(low_r);
let comp_mid_l = self.c_mid_l.process(mid_l);
let comp_mid_r = self.c_mid_r.process(mid_r);
let comp_high_l = self.c_high_l.process(high_l);
let comp_high_r = self.c_high_r.process(high_r);
// 3. Рекомпозиция и смешивание обработанного сигнала с сухим
let mix_l = comp_low_l + comp_mid_l + comp_high_l;
let mix_r = comp_low_r + comp_mid_r + comp_high_r;
(
dry_l * (1.0 - self.amount) + mix_l * self.amount,
dry_r * (1.0 - self.amount) + mix_r * self.amount
)
}
} // ADAA Non-Linear Waveshaping (Anti-Aliasing Double Approximation)
fn ln_cosh(x: f32) -> f32 {
let ax = x.abs();
if ax > 4.0 {
ax - 0.69314718
} else {
let x2 = x * x;
x2 * (6.0 + x2) / (3.0 * x2)
}
}
fn adaa_tanh(x: f32, x_prev: f32) -> f32 {
let diff = x - x_prev;
if diff.abs() < 1e-5 {
x.tanh()
} else {
// Вычисление первой производной первообразной ln(cosh(x))
(ln_cosh(x) - ln_cosh(x_prev)) / diff
}
}