// porres 2021 + Booberg 2021


#include "m_pd.h"


typedef struct _softslew{

    t_object  x_obj;

    t_float   x_last;
    t_float   x_dlast;
    t_float   x_in;
    t_float   x_sr_rec;
    t_inlet  *x_limit;

}t_softslew;

static t_class *softslew_class;

static t_int *softslew_perform(t_int *w){

    t_softslew *x = (t_softslew *)(w[1]);
    int n = (int)(w[2]);
    t_float *in1 = (t_float *)(w[3]);
    t_float *in2 = (t_float *)(w[4]);
    t_float *out = (t_float *)(w[5]);
    t_float last = x->x_last;
    t_float dlast = x->x_dlast;

    while(n--){
     	float gain = *in2++ * x->x_sr_rec;
        if(gain <= 0.)
            *out++ = 0.;
        else{
    	    float f = (gain * ( *in1++ )) + dlast;
            float delta = f - last;
            float deltaclip = atanf(delta);
            float dlast = delta - deltaclip;
            last = (last + deltaclip) * 0.9999;
	    f = last/gain;
            *out++ = f;
        }
    }
    x->x_dlast = dlast;
    x->x_last = last;

    return(w+6);

}

static void softslew_dsp(t_softslew *x, t_signal **sp){

    x->x_sr_rec = 96000. / sp[0]->s_sr;

    dsp_add(softslew_perform, 5, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec);

}


static void softslew_set(t_softslew *x, t_floatarg f){
    x->x_last = f;
}



static void *softslew_free(t_softslew *x){

    inlet_free(x->x_limit);

    return(void *)x;

}




static void *softslew_new(t_symbol *s, t_floatarg f){

    s = NULL;

    t_softslew *x = (t_softslew *)pd_new(softslew_class);

	x->x_limit = inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal);

	pd_float((t_pd *)x->x_limit, f);

    outlet_new((t_object *)x, &s_signal);
    x->x_dlast = 0;
    x->x_last = 0;

    return(x);

}


void softslew_tilde_setup(void){

    softslew_class = class_new(gensym("softslew~"), (t_newmethod)softslew_new,

        (t_method)softslew_free, sizeof(t_softslew), 0, A_DEFFLOAT, 0);

    CLASS_MAINSIGNALIN(softslew_class, t_softslew, x_in);

    class_addmethod(softslew_class, (t_method)softslew_dsp, gensym("dsp"), A_CANT, 0);

    class_addmethod(softslew_class, (t_method)softslew_set, gensym("set"), A_DEFFLOAT, 0);

}