surgefx-conditioner 0.2.12-alpha.0

surge synthesizer -- conditioner effect
crate::ix!();

macro_rules! write_vu_from_falloff {
    ($self:ident,$cfg:ident) => ({
        $self.vu[0] = minf(8.0, $cfg.a * $self.vu[0]);
        $self.vu[1] = minf(8.0, $cfg.a * $self.vu[1]);
        $self.vu[4] = minf(8.0, $cfg.a * $self.vu[4]);
        $self.vu[5] = minf(8.0, $cfg.a * $self.vu[5]);
    });
}

impl Process for Conditioner {

    fn process<const N: usize>(
        &mut self, 
        data_l: &mut [f32; N], 
        data_r: &mut [f32; N]) 
    {
        let cfg = ConditionerProcessCfg::new(self);

        write_vu_from_falloff![self,cfg];

        self.update();

        self.process_bands(data_l,data_r);

        self.update_amp(&cfg);

        self.width.set_target_smoothed(clamp1_bipolar(cfg.width));

        self.postamp.set_target_smoothed(self.tables.db_to_linear(cfg.gain));

        self.process_mid_side(data_l,data_r);

        self.set_vu01(data_l, data_r);

        for k in 0..N {
            self.do_conditioner_block(
                k, 
                &cfg,
                data_l,
                data_r);
        }

        self.process_postamp(data_l, data_r);

        self.vu[2] = self.gain;

        self.set_vu45(data_l, data_r);
    }
}

impl Conditioner {

    #[inline] fn process_bands<const N: usize>(
        &mut self, 
        data_l: &mut [f32; N], 
        data_r: &mut [f32; N]) 
    {
        unsafe {
            self.band1.process_block_stereo(
                data_l.as_mut_ptr(), 
                data_r.as_mut_ptr(), 
                None);

            self.band2.process_block_stereo(
                data_l.as_mut_ptr(), 
                data_r.as_mut_ptr(), 
                None);
        }
    }

    #[inline] fn update_amp(&mut self, cfg: &ConditionerProcessCfg) {

        self.amp_l.set_target_smoothed(
            cfg.pregain * 0.5 * clamp1_bipolar(1.0 - cfg.balance));

        self.amp_r.set_target_smoothed(
            cfg.pregain * 0.5 * clamp1_bipolar(1.0 + cfg.balance));
    }

    #[inline] fn process_postamp<const N: usize>(
        &mut self, 
        data_l: &mut [f32; N], 
        data_r: &mut [f32; N]) {

        unsafe {
            self.postamp.multiply_2_blocks(
                data_l.as_mut_ptr(), 
                data_r.as_mut_ptr(), 
                block_size_quad![N]);
        }
    }

    #[inline] fn set_vu01<const N: usize>(
        &mut self, 
        data_l: &mut [f32; N], 
        data_r: &mut [f32; N]) {

        self.vu[0] = maxf(
            self.vu[0], 
            get_absmax(
                data_l.as_mut_ptr(), 
                block_size_quad![N])
        );

        self.vu[1] = maxf(
            self.vu[1], 
            get_absmax(
                data_r.as_mut_ptr(), 
                block_size_quad![N])
        );
    }

    #[inline] fn set_vu45<const N: usize>(
        &mut self, 
        data_l: &mut [f32; N], 
        data_r: &mut [f32; N]) {

        self.vu[4] = maxf(
            self.vu[4], 
            get_absmax(
                data_l.as_mut_ptr(), 
                block_size_quad![N])
        );

        self.vu[5] = maxf(
            self.vu[5], 
            get_absmax(
                data_r.as_mut_ptr(), 
                block_size_quad![N])
        );
    }

    #[inline] fn process_mid_side<const N: usize>(
        &mut self, 
        data_l: &mut [f32; N], 
        data_r: &mut [f32; N]) {

        let mut mid_side = MSBlock::new(N);

        unsafe {

            encode_mid_side(
                data_l.as_mut_ptr(), 
                data_r.as_mut_ptr(), 
                mid_side.m(), 
                mid_side.s(), 
                block_size_quad![N]);

            self.width.multiply_block(mid_side.s(), block_size_quad![N]);

            decode_mid_side(
                mid_side.m(), 
                mid_side.s(), 
                data_l.as_mut_ptr(), 
                data_r.as_mut_ptr(), 
                block_size_quad![N]);

            self.amp_l.multiply_block(
                data_l.as_mut_ptr(), 
                block_size_quad![N]);

            self.amp_r.multiply_block(
                data_r.as_mut_ptr(), 
                block_size_quad![N]);
        }
    }
}

impl ProcessOnlyControl for Conditioner {

    fn process_only_control<const N: usize>(&mut self) { 

        let cfg = ConditionerProcessCfg::new(self);

        write_vu_from_falloff![self,cfg];

        for _k in 0..N 
        {
            self.filtered_lamax  = (1.0 - cfg.attack)  * self.filtered_lamax  + cfg.attack;
            self.filtered_lamax2 = (1.0 - cfg.release) * self.filtered_lamax2 + ( cfg.release * self.filtered_lamax );

            if self.filtered_lamax > self.filtered_lamax2 {
                self.filtered_lamax2 = self.filtered_lamax;
            }

            self.gain = 1.0 / self.filtered_lamax2;
        }

        self.vu[2] = self.gain;
    }
}