/* Copyright (c) 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 #include "m_pd.h" #include "shared.h" #include "sickle/sic.h" #include "shadow.h" #if defined(_WIN32) || defined(__APPLE__) /* cf pd/src/x_arithmetic.c */ #define fmodf fmod #endif /* Two remaining control binops have their inputs reversed. LATER think about float-to-int conversion -- there is no point in making the two below compatible, while all the others are not compatible... */ /* CHECKED left inlet causes output (refman's error -- a total rubbish) */ typedef struct _rbinop { t_object x_ob; t_float x_f1; /* left inlet value */ t_float x_f2; } t_rbinop; static t_class *rminus_class; static void rminus_bang(t_rbinop *x) { outlet_float(((t_object *)x)->ob_outlet, x->x_f2 - x->x_f1); } static void rminus_float(t_rbinop *x, t_float f) { outlet_float(((t_object *)x)->ob_outlet, x->x_f2 - (x->x_f1 = f)); } static void *rminus_new(t_floatarg f) { t_rbinop *x = (t_rbinop *)pd_new(rminus_class); floatinlet_new((t_object *)x, &x->x_f2); /* CHECKED */ outlet_new((t_object *)x, &s_float); x->x_f1 = 0; x->x_f2 = f; /* CHECKED */ return (x); } static t_class *rdiv_class; static void rdiv_bang(t_rbinop *x) { if (x->x_f1 != 0.) outlet_float(((t_object *)x)->ob_outlet, x->x_f2 / x->x_f1); else /* CHECKED int mode: nonnegative/0 == 0, negative/0 == -1, float mode: positive/0 == INT_MAX, nonpositive/0 == INT_MIN LATER rethink -- why is it INT_MAX, not FLT_MAX? */ outlet_float(((t_object *)x)->ob_outlet, (x->x_f2 > 0 ? SHARED_INT_MAX : SHARED_INT_MIN)); } static void rdiv_float(t_rbinop *x, t_float f) { x->x_f1 = f; rdiv_bang(x); } static void *rdiv_new(t_floatarg f) { t_rbinop *x = (t_rbinop *)pd_new(rdiv_class); floatinlet_new((t_object *)x, &x->x_f2); outlet_new((t_object *)x, &s_float); x->x_f1 = 0; x->x_f2 = f; /* CHECKED (refman's error) */ return (x); } /* The implementation of signal relational operators below has been tuned somewhat, mostly in order to get rid of costly int->float conversions. Loops are not hand-unrolled, because these have proven to be slower in all the tests performed so far. LATER find a good soul willing to make a serious profiling research... */ typedef struct _sigeq { t_sic x_sic; int x_algo; } t_sigeq; static t_class *sigeq_class; static t_int *sigeq_perform0(t_int *w) { int nblock = (int)(w[1]); t_float *in1 = (t_float *)(w[2]); t_float *in2 = (t_float *)(w[3]); t_float *out = (t_float *)(w[4]); t_shared_floatint fi; #ifdef NETTLES_SAFE int32 truebits; fi.fi_f = 1.; truebits = fi.fi_i; #endif while (nblock--) { #ifdef NETTLES_SAFE fi.fi_i = ~((*in1++ == *in2++) - 1) & truebits; #else fi.fi_i = ~((*in1++ == *in2++) - 1) & SHARED_TRUEBITS; #endif *out++ = fi.fi_f; } return (w + 5); } static t_int *sigeq_perform1(t_int *w) { int nblock = (int)(w[1]); t_float *in1 = (t_float *)(w[2]); t_float *in2 = (t_float *)(w[3]); t_float *out = (t_float *)(w[4]); while (nblock--) *out++ = (*in1++ == *in2++); return (w + 5); } static t_int *sigeq_perform2(t_int *w) { int nblock = (int)(w[1]); t_float *in1 = (t_float *)(w[2]); t_float *in2 = (t_float *)(w[3]); t_float *out = (t_float *)(w[4]); for (; nblock; nblock -= 8, in1 += 8, in2 += 8, out += 8) { float f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3]; float f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7]; float g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3]; float g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7]; out[0] = f0 == g0; out[1] = f1 == g1; out[2] = f2 == g2; out[3] = f3 == g3; out[4] = f4 == g4; out[5] = f5 == g5; out[6] = f6 == g6; out[7] = f7 == g7; } return (w + 5); } static void sigeq_dsp(t_sigeq *x, t_signal **sp) { switch (x->x_algo) { case 1: dsp_add(sigeq_perform1, 4, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); break; case 2: dsp_add(sigeq_perform2, 4, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); break; default: dsp_add(sigeq_perform0, 4, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); } } static void sigeq__algo(t_sigeq *x, t_floatarg f) { x->x_algo = f; } static void *sigeq_new(t_symbol *s, int ac, t_atom *av) { t_sigeq *x = (t_sigeq *)pd_new(sigeq_class); if (s == gensym("_==1~")) x->x_algo = 1; else if (s == gensym("_==2~")) x->x_algo = 2; else x->x_algo = 0; sic_inlet((t_sic *)x, 1, 0, 0, ac, av); outlet_new((t_object *)x, &s_signal); return (x); } typedef t_sic t_signeq; static t_class *signeq_class; static t_int *signeq_perform(t_int *w) { int nblock = (int)(w[1]); t_float *in1 = (t_float *)(w[2]); t_float *in2 = (t_float *)(w[3]); t_float *out = (t_float *)(w[4]); t_shared_floatint fi; while (nblock--) { fi.fi_i = ~((*in1++ != *in2++) - 1) & SHARED_TRUEBITS; *out++ = fi.fi_f; } return (w + 5); } static void signeq_dsp(t_signeq *x, t_signal **sp) { dsp_add(signeq_perform, 4, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); } static void *signeq_new(t_symbol *s, int ac, t_atom *av) { t_signeq *x = (t_signeq *)pd_new(signeq_class); sic_inlet((t_sic *)x, 1, 0, 0, ac, av); outlet_new((t_object *)x, &s_signal); return (x); } typedef t_sic t_siglt; static t_class *siglt_class; static t_int *siglt_perform(t_int *w) { int nblock = (int)(w[1]); t_float *in1 = (t_float *)(w[2]); t_float *in2 = (t_float *)(w[3]); t_float *out = (t_float *)(w[4]); t_shared_floatint fi; while (nblock--) { fi.fi_i = ~((*in1++ < *in2++) - 1) & SHARED_TRUEBITS; *out++ = fi.fi_f; } return (w + 5); } static void siglt_dsp(t_siglt *x, t_signal **sp) { dsp_add(siglt_perform, 4, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); } static void *siglt_new(t_symbol *s, int ac, t_atom *av) { t_siglt *x = (t_siglt *)pd_new(siglt_class); sic_inlet((t_sic *)x, 1, 0, 0, ac, av); outlet_new((t_object *)x, &s_signal); return (x); } typedef t_sic t_siggt; static t_class *siggt_class; static t_int *siggt_perform(t_int *w) { int nblock = (int)(w[1]); t_float *in1 = (t_float *)(w[2]); t_float *in2 = (t_float *)(w[3]); t_float *out = (t_float *)(w[4]); t_shared_floatint fi; while (nblock--) { fi.fi_i = ~((*in1++ > *in2++) - 1) & SHARED_TRUEBITS; *out++ = fi.fi_f; } return (w + 5); } static void siggt_dsp(t_siggt *x, t_signal **sp) { dsp_add(siggt_perform, 4, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); } static void *siggt_new(t_symbol *s, int ac, t_atom *av) { t_siggt *x = (t_siggt *)pd_new(siggt_class); sic_inlet((t_sic *)x, 1, 0, 0, ac, av); outlet_new((t_object *)x, &s_signal); return (x); } typedef t_sic t_sigleq; static t_class *sigleq_class; static t_int *sigleq_perform(t_int *w) { int nblock = (int)(w[1]); t_float *in1 = (t_float *)(w[2]); t_float *in2 = (t_float *)(w[3]); t_float *out = (t_float *)(w[4]); t_shared_floatint fi; while (nblock--) { fi.fi_i = ~((*in1++ <= *in2++) - 1) & SHARED_TRUEBITS; *out++ = fi.fi_f; } return (w + 5); } static void sigleq_dsp(t_sigleq *x, t_signal **sp) { dsp_add(sigleq_perform, 4, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); } static void *sigleq_new(t_symbol *s, int ac, t_atom *av) { t_sigleq *x = (t_sigleq *)pd_new(sigleq_class); sic_inlet((t_sic *)x, 1, 0, 0, ac, av); outlet_new((t_object *)x, &s_signal); return (x); } typedef t_sic t_siggeq; static t_class *siggeq_class; static t_int *siggeq_perform(t_int *w) { int nblock = (int)(w[1]); t_float *in1 = (t_float *)(w[2]); t_float *in2 = (t_float *)(w[3]); t_float *out = (t_float *)(w[4]); t_shared_floatint fi; while (nblock--) { fi.fi_i = ~((*in1++ >= *in2++) - 1) & SHARED_TRUEBITS; *out++ = fi.fi_f; } return (w + 5); } static void siggeq_dsp(t_siggeq *x, t_signal **sp) { dsp_add(siggeq_perform, 4, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); } static void *siggeq_new(t_symbol *s, int ac, t_atom *av) { t_siggeq *x = (t_siggeq *)pd_new(siggeq_class); sic_inlet((t_sic *)x, 1, 0, 0, ac, av); outlet_new((t_object *)x, &s_signal); return (x); } typedef t_sic t_sigrminus; static t_class *sigrminus_class; static t_int *sigrminus_perform(t_int *w) { int nblock = (int)(w[1]); t_float *in1 = (t_float *)(w[2]); t_float *in2 = (t_float *)(w[3]); t_float *out = (t_float *)(w[4]); while (nblock--) *out++ = *in2++ - *in1++; return (w + 5); } static void sigrminus_dsp(t_sigrminus *x, t_signal **sp) { dsp_add(sigrminus_perform, 4, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); } static void *sigrminus_new(t_symbol *s, int ac, t_atom *av) { t_sigrminus *x = (t_sigrminus *)pd_new(sigrminus_class); sic_inlet((t_sic *)x, 1, 0, 0, ac, av); outlet_new((t_object *)x, &s_signal); return (x); } typedef t_sic t_sigrover; static t_class *sigrover_class; static t_int *sigrover_perform(t_int *w) { int nblock = (int)(w[1]); t_float *in1 = (t_float *)(w[2]); t_float *in2 = (t_float *)(w[3]); t_float *out = (t_float *)(w[4]); while (nblock--) { t_float f1 = *in1++; /* CHECKED incompatible: c74 outputs NaNs. The line below is consistent with Pd's /~, LATER rethink. */ /* LATER multiply by reciprocal if in1 has no signal feeders */ *out++ = (f1 == 0. ? 0. : *in2++ / f1); } return (w + 5); } static void sigrover_dsp(t_sigrover *x, t_signal **sp) { dsp_add(sigrover_perform, 4, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); } static void *sigrover_new(t_symbol *s, int ac, t_atom *av) { t_sigrover *x = (t_sigrover *)pd_new(sigrover_class); /* CHECKED default 0 (refman's error), LATER rethink */ sic_inlet((t_sic *)x, 1, 0, 0, ac, av); outlet_new((t_object *)x, &s_signal); return (x); } typedef t_sic t_sigmod; static t_class *sigmod_class; static t_int *sigmod_perform(t_int *w) { int nblock = (int)(w[1]); t_float *in1 = (t_float *)(w[2]); t_float *in2 = (t_float *)(w[3]); t_float *out = (t_float *)(w[4]); while (nblock--) { t_float f1 = *in1++; t_float f2 = *in2++; /* LATER think about using ieee-754 normalization tricks */ *out++ = (f2 == 0. ? 0. /* CHECKED */ : fmod(f1, f2)); } return (w + 5); } static void sigmod_dsp(t_sigmod *x, t_signal **sp) { dsp_add(sigmod_perform, 4, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec); } static void *sigmod_new(t_symbol *s, int ac, t_atom *av) { t_sigmod *x = (t_sigmod *)pd_new(sigmod_class); /* CHECKED default 0 (refman's error), LATER rethink */ sic_inlet((t_sic *)x, 1, 0, 0, ac, av); outlet_new((t_object *)x, &s_signal); return (x); } typedef struct _sigaccum { t_sic x_sic; t_float x_sum; } t_sigaccum; static t_class *sigaccum_class; static t_int *sigaccum_perform(t_int *w) { t_sigaccum *x = (t_sigaccum *)(w[1]); int nblock = (int)(w[2]); t_float *in = (t_float *)(w[3]); t_float *out = (t_float *)(w[4]); t_float sum = x->x_sum; while (nblock--) *out++ = (sum += *in++); x->x_sum = sum; return (w + 5); } static void sigaccum_dsp(t_sigaccum *x, t_signal **sp) { dsp_add(sigaccum_perform, 4, x, sp[0]->s_n, sp[0]->s_vec, sp[1]->s_vec); } static void sigaccum_bang(t_sigaccum *x) { x->x_sum = 0; } static void sigaccum_set(t_sigaccum *x, t_floatarg f) { x->x_sum = f; } static void *sigaccum_new(t_floatarg f) { t_sigaccum *x = (t_sigaccum *)pd_new(sigaccum_class); x->x_sum = f; outlet_new((t_object *)x, &s_signal); return (x); } void nettles_setup(void) { rminus_class = class_new(gensym("!-"), (t_newmethod)rminus_new, 0, sizeof(t_rbinop), 0, A_DEFFLOAT, 0); class_addbang(rminus_class, rminus_bang); class_addfloat(rminus_class, rminus_float); class_sethelpsymbol(rminus_class, gensym("nettles")); rdiv_class = class_new(gensym("!/"), (t_newmethod)rdiv_new, 0, sizeof(t_rbinop), 0, A_DEFFLOAT, 0); class_addbang(rdiv_class, rdiv_bang); class_addfloat(rdiv_class, rdiv_float); class_sethelpsymbol(rdiv_class, gensym("nettles")); sigeq_class = class_new(gensym("==~"), (t_newmethod)sigeq_new, 0, sizeof(t_sigeq), 0, A_GIMME, 0); class_addcreator((t_newmethod)sigeq_new, gensym("_==1~"), A_GIMME, 0); class_addcreator((t_newmethod)sigeq_new, gensym("_==2~"), A_GIMME, 0); sic_setup(sigeq_class, sigeq_dsp, SIC_FLOATTOSIGNAL); class_addmethod(sigeq_class, (t_method)sigeq__algo, gensym("_algo"), A_FLOAT, 0); class_sethelpsymbol(sigeq_class, gensym("nettles")); signeq_class = class_new(gensym("!=~"), (t_newmethod)signeq_new, 0, sizeof(t_signeq), 0, A_GIMME, 0); sic_setup(signeq_class, signeq_dsp, SIC_FLOATTOSIGNAL); class_sethelpsymbol(signeq_class, gensym("nettles")); siglt_class = class_new(gensym("<~"), (t_newmethod)siglt_new, 0, sizeof(t_siglt), 0, A_GIMME, 0); sic_setup(siglt_class, siglt_dsp, SIC_FLOATTOSIGNAL); class_sethelpsymbol(siglt_class, gensym("nettles")); siggt_class = class_new(gensym(">~"), (t_newmethod)siggt_new, 0, sizeof(t_siggt), 0, A_GIMME, 0); sic_setup(siggt_class, siggt_dsp, SIC_FLOATTOSIGNAL); class_sethelpsymbol(siggt_class, gensym("nettles")); sigleq_class = class_new(gensym("<=~"), (t_newmethod)sigleq_new, 0, sizeof(t_sigleq), 0, A_GIMME, 0); sic_setup(sigleq_class, sigleq_dsp, SIC_FLOATTOSIGNAL); class_sethelpsymbol(sigleq_class, gensym("nettles")); siggeq_class = class_new(gensym(">=~"), (t_newmethod)siggeq_new, 0, sizeof(t_siggeq), 0, A_GIMME, 0); sic_setup(siggeq_class, siggeq_dsp, SIC_FLOATTOSIGNAL); class_sethelpsymbol(siggeq_class, gensym("nettles")); sigrminus_class = class_new(gensym("!-~"), (t_newmethod)sigrminus_new, 0, sizeof(t_sigrminus), 0, A_GIMME, 0); sic_setup(sigrminus_class, sigrminus_dsp, SIC_FLOATTOSIGNAL); class_sethelpsymbol(sigrminus_class, gensym("nettles")); sigrover_class = class_new(gensym("!/~"), (t_newmethod)sigrover_new, 0, sizeof(t_sigrover), 0, A_GIMME, 0); sic_setup(sigrover_class, sigrover_dsp, SIC_FLOATTOSIGNAL); class_sethelpsymbol(sigrover_class, gensym("nettles")); sigmod_class = class_new(gensym("%~"), (t_newmethod)sigmod_new, 0, sizeof(t_sigmod), 0, A_GIMME, 0); sic_setup(sigmod_class, sigmod_dsp, SIC_FLOATTOSIGNAL); class_sethelpsymbol(sigmod_class, gensym("nettles")); sigaccum_class = class_new(gensym("+=~"), (t_newmethod)sigaccum_new, 0, sizeof(t_sigaccum), 0, A_DEFFLOAT, 0); sic_setup(sigaccum_class, sigaccum_dsp, SIC_FLOATTOSIGNAL); class_addbang(sigaccum_class, sigaccum_bang); class_addmethod(sigaccum_class, (t_method)sigaccum_set, gensym("set"), A_FLOAT, 0); class_sethelpsymbol(sigaccum_class, gensym("nettles")); // logpost(NULL, 4, "this is cyclone/nettles %s, %dth %s build", // CYCLONE_VERSION, CYCLONE_BUILD, CYCLONE_RELEASE); } void allnettles_setup(void) { nettles_setup(); }