/* Copyright (c) 2002-2003 krzYszcz and others. * For information on usage and redistribution, and for a DISCLAIMER OF ALL * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ #include "m_pd.h" #include "sickle/sic.h" #define VECTRAL_DEFSIZE 512 struct _vectral; typedef void (*t_vectral_perform)(struct _vectral *, int, t_float *, t_float *, t_float *, t_float *); typedef struct _vectral { t_sic x_sic; t_vectral_perform x_perform; int x_bufsize; t_float *x_buffer; t_float *x_lastframe; /* rampsmooth and slide state */ double x_upcoef; double x_downcoef; /* deltaclip state */ float x_lo; float x_hi; } t_vectral; static t_class *vectral_class; /* LATER after any modification make sure about syncing other variants of perform routine to the bypassing version */ /* this is: for i in [0..nblock) buf[in2[i]] = in3[i], out[i] = buf[in1[i]] */ static void vectral_perform_bypass(t_vectral *x, int nblock, t_float *in1, t_float *in2, t_float *in3, t_float *out) { t_float *buf = x->x_buffer; int bufsize = x->x_bufsize; t_float *last = x->x_lastframe; int blocksize = nblock; while (nblock--) { int indx = (int)*in2++; /* CHECKED buffer not zeroed out (the buffer's garbage remains) */ if (indx >= 0 && indx < bufsize) buf[indx] = *in3; in3++; } while (blocksize--) { int ondx = (int)*in1++; if (ondx >= 0 && ondx < bufsize) *out++ = *last++ = buf[ondx]; else /* CHECKED garbage in the output vector is cleared */ *out++ = *last++ = 0.; } } /* this one is used for rampsmooth mode as well (see rampsmooth.c) LATER recheck */ static void vectral_perform_slide(t_vectral *x, int nblock, t_float *in1, t_float *in2, t_float *in3, t_float *out) { t_float *buf = x->x_buffer; int bufsize = x->x_bufsize; double upcoef = x->x_upcoef; double downcoef = x->x_downcoef; t_float *last = x->x_lastframe; int blocksize = nblock; while (nblock--) { int indx = (int)*in2++; if (indx >= 0 && indx < bufsize) buf[indx] = *in3; in3++; } while (blocksize--) { int ondx = (int)*in1++; if (ondx >= 0 && ondx < bufsize) { /* CHECKME what is smoothed, and FIXME */ float delta = buf[ondx] - *last; *out++ = (*last++ += (delta > 0 ? delta * upcoef : delta * downcoef)); } else *out++ = *last++ = 0.; } } static void vectral_perform_clip(t_vectral *x, int nblock, t_float *in1, t_float *in2, t_float *in3, t_float *out) { t_float *buf = x->x_buffer; int bufsize = x->x_bufsize; float lo = x->x_lo; float hi = x->x_hi; t_float *last = x->x_lastframe; int blocksize = nblock; while (nblock--) { int indx = (int)*in2++; if (indx >= 0 && indx < bufsize) buf[indx] = *in3; in3++; } while (blocksize--) { int ondx = (int)*in1++; if (ondx >= 0 && ondx < bufsize) { /* CHECKME what is smoothed, and FIXME */ float delta = buf[ondx] - *last; if (delta < lo) *out++ = (*last++ += lo); else if (delta > hi) *out++ = (*last++ += hi); else *out++ = *last++ = buf[ondx]; } else *out++ = *last++ = 0.; } } static t_int *vectral_perform(t_int *w) { t_vectral *x = (t_vectral *)(w[1]); (*x->x_perform)(x, (int)(w[2]), (t_float *)(w[3]), (t_float *)(w[4]), (t_float *)(w[5]), (t_float *)(w[6])); return (w + 7); } static void vectral_dsp(t_vectral *x, t_signal **sp) { int nblock = sp[0]->s_n; if (nblock > x->x_bufsize) nblock = x->x_bufsize; /* CHECKME */ dsp_add(vectral_perform, 6, x, nblock, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec); } static void vectral_rampsmooth(t_vectral *x, t_symbol *s, int ac, t_atom *av) { if (ac && av->a_type == A_FLOAT) { int i; x->x_upcoef = ((i = (int)av->a_w.w_float) > 1 ? 1. / (double)i : 1.); ac--; av++; if (ac && av->a_type == A_FLOAT) x->x_downcoef = ((i = (int)av->a_w.w_float) > 1 ? 1. / (double)i : 1.); else x->x_downcoef = 1.; /* CHECKED */ x->x_perform = vectral_perform_slide; /* see above */ } else x->x_perform = vectral_perform_bypass; /* CHECKED */ } static void vectral_slide(t_vectral *x, t_symbol *s, int ac, t_atom *av) { if (ac && av->a_type == A_FLOAT) { double d; x->x_upcoef = ((d = av->a_w.w_float) > 1. ? 1. / d : 1.); ac--; av++; if (ac && av->a_type == A_FLOAT) x->x_downcoef = ((d = av->a_w.w_float) > 1. ? 1. / d : 1.); else x->x_downcoef = 1.; /* CHECKED */ x->x_perform = vectral_perform_slide; } else x->x_perform = vectral_perform_bypass; /* CHECKED */ } /* CHECKED 'deltaclip ' (deltaclip~'s args are swapped) */ static void vectral_deltaclip(t_vectral *x, t_symbol *s, int ac, t_atom *av) { if (ac && av->a_type == A_FLOAT) { x->x_hi = av->a_w.w_float; ac--; av++; if (ac && av->a_type == A_FLOAT) x->x_lo = av->a_w.w_float; else x->x_lo = 0.; /* CHECKED */ } else x->x_lo = x->x_hi = 0.; /* CHECKED */ x->x_perform = vectral_perform_clip; } static void vectral_free(t_vectral *x) { if (x->x_buffer) freebytes(x->x_buffer, x->x_bufsize * sizeof(*x->x_buffer)); if (x->x_lastframe) freebytes(x->x_lastframe, x->x_bufsize * sizeof(*x->x_lastframe)); } static void *vectral_new(t_floatarg f) { t_vectral *x = (t_vectral *)pd_new(vectral_class); int i = (int)f; x->x_bufsize = (i > 0 ? i : VECTRAL_DEFSIZE); if (!(x->x_buffer = getbytes(x->x_bufsize * sizeof(*x->x_buffer)))) goto failure; if (!(x->x_lastframe = getbytes(x->x_bufsize * sizeof(*x->x_lastframe)))) goto failure; x->x_perform = vectral_perform_bypass; inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal); inlet_new((t_object *)x, (t_pd *)x, &s_signal, &s_signal); outlet_new((t_object *)x, &s_signal); return (x); failure: pd_free((t_pd *)x); return (0); } void vectral_tilde_setup(void) { vectral_class = class_new(gensym("vectral~"), (t_newmethod)vectral_new, (t_method)vectral_free, sizeof(t_vectral), 0, A_DEFFLOAT, 0); sic_setup(vectral_class, vectral_dsp, SIC_FLOATTOSIGNAL); class_addmethod(vectral_class, (t_method)vectral_rampsmooth, gensym("rampsmooth"), A_GIMME, 0); class_addmethod(vectral_class, (t_method)vectral_slide, gensym("slide"), A_GIMME, 0); class_addmethod(vectral_class, (t_method)vectral_deltaclip, gensym("deltaclip"), A_GIMME, 0); }