From 4d84d14ac1aa13958eaa2971b03f7f929a519105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?IOhannes=20m=20zm=C3=B6lnig?= Date: Fri, 8 Feb 2008 13:00:32 +0000 Subject: reorganized svn path=/trunk/; revision=9400 --- desiredata/src/builtins_dsp.c | 3844 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3844 insertions(+) create mode 100644 desiredata/src/builtins_dsp.c (limited to 'desiredata/src/builtins_dsp.c') diff --git a/desiredata/src/builtins_dsp.c b/desiredata/src/builtins_dsp.c new file mode 100644 index 00000000..cf2d460e --- /dev/null +++ b/desiredata/src/builtins_dsp.c @@ -0,0 +1,3844 @@ +/* Copyright (c) 2007 Mathieu Bouchard + Copyright (c) 1997-1999 Miller Puckette. + For information on usage and redistribution, + and for a DISCLAIMER OF ALL WARRANTIES, + see the file "LICENSE.txt" in this distribution. */ + +/* arithmetic binops (+, -, *, /). +If no creation argument is given, there are two signal inlets for vector/vector +operation; otherwise it's vector/scalar and the second inlet takes a float +to reset the value. +*/ + +//#define HAVE_LIBFFTW3F + +#define PD_PLUSPLUS_FACE +#include "desire.h" +#include "m_simd.h" +#include "s_stuff.h" +#include +#include +#include +#include +extern int ugen_getsortno (); +#define DEFDELVS 64 /* LATER get this from canvas at DSP time */ +#ifdef HAVE_LIBFFTW3F +#include +#endif +#define DEFSENDVS 64 /* LATER get send to get this from canvas */ +#define LOGTEN 2.302585092994 +#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */ +#define int32 int +#ifdef BIGENDIAN +#define HIOFFSET 0 /* word offset to find MSB */ +#define LOWOFFSET 1 /* word offset to find LSB */ +#else +#define HIOFFSET 1 +#define LOWOFFSET 0 +#endif + +#undef CLASS_MAINSIGNALIN +/* because C++ bitches about null pointers, we'll use 8 instead (really): */ +#define CLASS_MAINSIGNALIN(c, type, field) class_domainsignalin(c, (char *)(&((type *)8)->field) - (char *)8) + +#define clock_new(a,b) clock_new(a,(t_method)b) + +#undef min +#undef max + +/* ----------------------------- plus ----------------------------- */ + +struct t_dop : t_object { + float a; + t_float b; /* inlet value, if necessary */ +}; + +#define DSPDECL(NAME) static t_class *NAME##_class, *scalar##NAME##_class; typedef t_dop t_##NAME, t_scalar##NAME; +DSPDECL(plus) +DSPDECL(minus) +DSPDECL(times) +DSPDECL(over) +DSPDECL(max) +DSPDECL(min) +DSPDECL(lt) +DSPDECL(gt) +DSPDECL(le) +DSPDECL(ge) +DSPDECL(eq) +DSPDECL(ne) + +#define DSPNEW(NAME,SYM) \ +static void *NAME##_new(t_symbol *s, int argc, t_atom *argv) { \ + if (argc > 1) error("extra arguments ignored"); \ + t_dop *x = (t_dop *)pd_new(argc ? scalar##NAME##_class : NAME##_class); \ + if (argc) { \ + floatinlet_new(x, &x->b); \ + x->b = atom_getfloatarg(0, argc, argv); \ + } else inlet_new(x, x, &s_signal, &s_signal); \ + outlet_new(x, &s_signal); \ + x->a = 0; \ + return x;} \ +static void NAME##_setup() { \ + t_class *c = NAME##_class = class_new2(SYM,NAME##_new,0,sizeof(t_dop),0,"*"); \ + class_addmethod2(c, NAME##_dsp, "dsp",""); \ + CLASS_MAINSIGNALIN(c, t_dop, a); \ + class_sethelpsymbol(NAME##_class, gensym("sigbinops")); \ + c = scalar##NAME##_class = class_new2(SYM,0,0,sizeof(t_dop),0,""); \ + CLASS_MAINSIGNALIN(c, t_dop, a); \ + class_addmethod2(c, scalar##NAME##_dsp, "dsp",""); \ + class_sethelpsymbol(scalar##NAME##_class, gensym("sigbinops"));} + +/* use when simd functions are present */ +#define DSPDSP(NAME) \ +static void NAME##_dsp(t_minus *x, t_signal **sp) { \ + const int n = sp[0]->n; \ + if(n&7) dsp_add(NAME##_perform, 4, sp[0]->v, sp[1]->v, sp[2]->v, n); \ + else if(SIMD_CHECK3(n,sp[0]->v,sp[1]->v,sp[2]->v)) \ + dsp_add(NAME##_perf_simd, 4, sp[0]->v, sp[1]->v, sp[2]->v, n); \ + else dsp_add(NAME##_perf8, 4, sp[0]->v, sp[1]->v, sp[2]->v, n);} \ +static void scalar##NAME##_dsp(t_scalarminus *x, t_signal **sp) { \ + const int n = sp[0]->n;\ + if(n&7) dsp_add(scalar##NAME##_perform, 4, sp[0]->v, &x->b,sp[1]->v, n);\ + else if(SIMD_CHECK2(n,sp[0]->v,sp[1]->v)) \ + dsp_add(scalar##NAME##_perf_simd, 4, sp[0]->v, &x->b, sp[1]->v, n);\ + else dsp_add(scalar##NAME##_perf8, 4, sp[0]->v, &x->b, sp[1]->v, n);} + +/* use when simd functions are missing */ +#define DSPDSP2(NAME) \ +static void NAME##_dsp(t_minus *x, t_signal **sp) { \ + const int n = sp[0]->n; \ + if(n&7) dsp_add(NAME##_perform, 4, sp[0]->v, sp[1]->v, sp[2]->v, n); \ + else dsp_add(NAME##_perf8, 4, sp[0]->v, sp[1]->v, sp[2]->v, n);} \ +static void scalar##NAME##_dsp(t_scalarminus *x, t_signal **sp) { \ + const int n = sp[0]->n;\ + if(n&7) dsp_add(scalar##NAME##_perform, 4, sp[0]->v, &x->b,sp[1]->v, n);\ + else dsp_add(scalar##NAME##_perf8, 4, sp[0]->v, &x->b, sp[1]->v, n);} + +#define PERFORM(NAME,EXPR) \ +t_int *NAME##_perform(t_int *w) { \ + t_float *in1 = (t_float *)w[1], *in2 = (t_float *)w[2], *out = (t_float *)w[3]; \ + int n = (int)w[4]; \ + while (n--) {t_float a=*in1++, b=*in2++; *out++ = (EXPR);} \ + return w+5;} \ +t_int *NAME##_perf8(t_int *w) { \ + t_float *in1 = (t_float *)w[1], *in2 = (t_float *)w[2], *out = (t_float *)w[3]; \ + int n = (int)w[4]; \ + for (; n; n -= 8, in1 += 8, in2 += 8, out += 8) { \ + {t_float a=in1[0], b=in2[0]; out[0] = (EXPR);} \ + {t_float a=in1[1], b=in2[1]; out[1] = (EXPR);} \ + {t_float a=in1[2], b=in2[2]; out[2] = (EXPR);} \ + {t_float a=in1[3], b=in2[3]; out[3] = (EXPR);} \ + {t_float a=in1[4], b=in2[4]; out[4] = (EXPR);} \ + {t_float a=in1[5], b=in2[5]; out[5] = (EXPR);} \ + {t_float a=in1[6], b=in2[6]; out[6] = (EXPR);} \ + {t_float a=in1[7], b=in2[7]; out[7] = (EXPR);}} \ + return w+5;} \ +t_int *scalar##NAME##_perform(t_int *w) { \ + t_float *in = (t_float *)w[1]; t_float b = *(t_float *)w[2]; t_float *out = (t_float *)w[3]; \ + int n = (int)w[4]; \ + while (n--) {t_float a=*in++; *out++ = (EXPR);} \ + return w+5;} \ +t_int *scalar##NAME##_perf8(t_int *w) { \ + t_float *in = (t_float *)w[1]; t_float b = *(t_float *)w[2]; t_float *out = (t_float *)w[3]; \ + int n = (int)w[4]; \ + for (; n; n -= 8, in += 8, out += 8) { \ + {t_float a=in[0]; out[0] = (EXPR);} \ + {t_float a=in[1]; out[1] = (EXPR);} \ + {t_float a=in[2]; out[2] = (EXPR);} \ + {t_float a=in[3]; out[3] = (EXPR);} \ + {t_float a=in[4]; out[4] = (EXPR);} \ + {t_float a=in[5]; out[5] = (EXPR);} \ + {t_float a=in[6]; out[6] = (EXPR);} \ + {t_float a=in[7]; out[7] = (EXPR);}} \ + return w+5;} + +void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n) { + if (n&7) dsp_add(plus_perform, 4, in1, in2, out, n); + else if(SIMD_CHECK3(n,in1,in2,out)) dsp_add(plus_perf_simd, 4, in1, in2, out, n); + else dsp_add(plus_perf8, 4, in1, in2, out, n); +} + +/* T.Grill - squaring: optimized * for equal input signals */ +t_int *sqr_perf8(t_int *w) { + t_float *in = (t_float *)w[1]; + t_float *out = (t_float *)w[2]; + int n = (int)w[3]; + for (; n; n -= 8, in += 8, out += 8) { + float f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3]; + float f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7]; + out[0] = f0 * f0; out[1] = f1 * f1; out[2] = f2 * f2; out[3] = f3 * f3; + out[4] = f4 * f4; out[5] = f5 * f5; out[6] = f6 * f6; out[7] = f7 * f7; + } + return w+4; +} + +/* T.Grill - added optimization for equal input signals */ +static void times_dsp(t_times *x, t_signal **sp) { + const int n = sp[0]->n; + if (n&7) dsp_add(times_perform, 4, sp[0]->v, sp[1]->v, sp[2]->v, n); + else if(sp[0]->v == sp[1]->v) { + if(SIMD_CHECK2(n,sp[0]->v,sp[2]->v)) + dsp_add(sqr_perf_simd, 3, sp[0]->v, sp[2]->v, n); + else dsp_add(sqr_perf8, 3, sp[0]->v, sp[2]->v, n); + } else { + if(SIMD_CHECK3(n,sp[0]->v,sp[1]->v,sp[2]->v)) + dsp_add(times_perf_simd, 4, sp[0]->v, sp[1]->v, sp[2]->v, n); + else dsp_add(times_perf8, 4, sp[0]->v, sp[1]->v, sp[2]->v, n); + } +} +static void scalartimes_dsp(t_scalartimes *x, t_signal **sp) { + const int n = sp[0]->n; + if (n&7) dsp_add(scalartimes_perform, 4, sp[0]->v, &x->b,sp[1]->v, n); + else if(SIMD_CHECK2(n,sp[0]->v,sp[1]->v)) + dsp_add(scalartimes_perf_simd, 4, sp[0]->v, &x->b, sp[1]->v, n); + else dsp_add(scalartimes_perf8, 4, sp[0]->v, &x->b, sp[1]->v, n); +} + +PERFORM(plus ,a+b) DSPDSP(plus) DSPNEW(plus ,"+~") +PERFORM(minus,a-b) DSPDSP(minus) DSPNEW(minus,"-~") +PERFORM(times,a*b) /*DSPDSP(times)*/ DSPNEW(times,"*~") +/*PERFORM(over,a/b)*/ DSPDSP(over) DSPNEW(over ,"/~") +PERFORM(min ,ab?a:b) DSPDSP(max) DSPNEW(max ,"max~") +PERFORM(lt ,ab) DSPDSP2(gt) DSPNEW(gt ,">~") +PERFORM(le ,a<=b) DSPDSP2(le) DSPNEW(le ,"<=~") +PERFORM(ge ,a>=b) DSPDSP2(ge) DSPNEW(ge ,">=~") +PERFORM(eq ,a==b) DSPDSP2(eq) DSPNEW(eq ,"==~") +PERFORM(ne ,a!=b) DSPDSP2(ne) DSPNEW(ne ,"!=~") + +t_int *over_perform(t_int *w) { + t_float *in1 = (t_float *)w[1], *in2 = (t_float *)w[2], *out = (t_float *)w[3]; + int n = (int)w[4]; + while (n--) { + float g = *in2++; + *out++ = (g ? *in1++ / g : 0); + } + return w+5; +} +t_int *over_perf8(t_int *w) { + t_float *in1 = (t_float *)w[1]; + t_float *in2 = (t_float *)w[2]; + t_float *out = (t_float *)w[3]; + int n = (int)w[4]; + for (; n; n -= 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] = (g0? f0 / g0 : 0); + out[1] = (g1? f1 / g1 : 0); + out[2] = (g2? f2 / g2 : 0); + out[3] = (g3? f3 / g3 : 0); + out[4] = (g4? f4 / g4 : 0); + out[5] = (g5? f5 / g5 : 0); + out[6] = (g6? f6 / g6 : 0); + out[7] = (g7? f7 / g7 : 0); + } + return w+5; +} +/* T.Grill - added check for zero */ +t_int *scalarover_perform(t_int *w) { + t_float *in = (t_float *)w[1]; + t_float f = *(t_float *)w[2]; + t_float *out = (t_float *)w[3]; + int n = (int)w[4]; + if(f) f = 1./f; + while (n--) *out++ = *in++ * f; + return w+5; +} +t_int *scalarover_perf8(t_int *w) { + t_float *in = (t_float *)w[1]; + t_float g = *(t_float *)w[2]; + t_float *out = (t_float *)w[3]; + int n = (int)w[4]; + if (g) g = 1.f / g; + for (; n; n -= 8, in += 8, out += 8) { + out[0] = in[0] * g; out[1] = in[1] * g; out[2] = in[2] * g; out[3] = in[3] * g; + out[4] = in[4] * g; out[5] = in[5] * g; out[6] = in[6] * g; out[7] = in[7] * g; + } + return w+5; +} + +/* ------------------------- tabwrite~ -------------------------- */ +static t_class *tabwrite_tilde_class; +struct t_tabwrite_tilde : t_object { + int phase; + int nsampsintab; + float *vec; + t_symbol *arrayname; + float a; +}; +static void *tabwrite_tilde_new(t_symbol *s) { + t_tabwrite_tilde *x = (t_tabwrite_tilde *)pd_new(tabwrite_tilde_class); + x->phase = 0x7fffffff; + x->arrayname = s; + x->a = 0; + return x; +} +static void tabwrite_tilde_redraw(t_tabwrite_tilde *x) { + t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class); + if (!a) bug("tabwrite_tilde_redraw"); + else garray_redraw(a); +} +static t_int *tabwrite_tilde_perform(t_int *w) { + t_tabwrite_tilde *x = (t_tabwrite_tilde *)w[1]; + t_float *in = (t_float *)w[2]; + int n = (int)w[3], phase = x->phase, endphase = x->nsampsintab; + if (!x->vec) goto bad; + if (endphase > phase) { + int nxfer = endphase - phase; + float *fp = x->vec + phase; + if (nxfer > n) nxfer = n; + phase += nxfer; + testcopyvec(fp, in, nxfer); + if (phase >= endphase) { + tabwrite_tilde_redraw(x); + phase = 0x7fffffff; + } + x->phase = phase; + } else x->phase = 0x7fffffff; +bad: + return w+4; +} +static t_int *tabwrite_tilde_perf_simd(t_int *w) { + t_tabwrite_tilde *x = (t_tabwrite_tilde *)w[1]; + t_float *in = (t_float *)w[2]; + int n = (int)w[3], phase = x->phase, endphase = x->nsampsintab; + if (!x->vec) goto bad; + if (endphase > phase) { + int nxfer = endphase - phase; + float *fp = x->vec + phase; + if (nxfer > n) nxfer = n; + phase += nxfer; + if (SIMD_CHKCNT(nxfer)) testcopyvec_simd(fp, in, nxfer); + else testcopyvec(fp, in, nxfer); + if (phase >= endphase) { + tabwrite_tilde_redraw(x); + phase = 0x7fffffff; + } + x->phase = phase; + } else x->phase = 0x7fffffff; +bad: + return w+4; +} +void tabwrite_tilde_set(t_tabwrite_tilde *x, t_symbol *s) { + x->arrayname = s; + t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class); + if (!a) { + if (*s->name) error("tabwrite~: %s: no such array", x->arrayname->name); + x->vec = 0; + } else if (!garray_getfloatarray(a, &x->nsampsintab, &x->vec)) { + error("%s: bad template for tabwrite~", x->arrayname->name); + x->vec = 0; + } else garray_usedindsp(a); +} +static void tabwrite_tilde_dsp(t_tabwrite_tilde *x, t_signal **sp) { + tabwrite_tilde_set(x, x->arrayname); + if (SIMD_CHECK1(sp[0]->n, sp[0]->v)) + dsp_add(tabwrite_tilde_perf_simd, 3, x, sp[0]->v, sp[0]->n); + else dsp_add(tabwrite_tilde_perform, 3, x, sp[0]->v, sp[0]->n); +} +static void tabwrite_tilde_bang(t_tabwrite_tilde *x) {x->phase = 0;} +static void tabwrite_tilde_start(t_tabwrite_tilde *x, t_floatarg f) {x->phase = (int)max((int)f,0);} +static void tabwrite_tilde_stop(t_tabwrite_tilde *x) { + if (x->phase != 0x7fffffff) { + tabwrite_tilde_redraw(x); + x->phase = 0x7fffffff; + } +} + +/* ------------ tabplay~ - non-transposing sample playback --------------- */ +static t_class *tabplay_tilde_class; +struct t_tabplay_tilde : t_object { + int phase; + int nsampsintab; + int limit; + float *vec; + t_symbol *arrayname; + t_clock *clock; +}; +static void tabplay_tilde_tick(t_tabplay_tilde *x); +static void *tabplay_tilde_new(t_symbol *s) { + t_tabplay_tilde *x = (t_tabplay_tilde *)pd_new(tabplay_tilde_class); + x->clock = clock_new(x, tabplay_tilde_tick); + x->phase = 0x7fffffff; + x->limit = 0; + x->arrayname = s; + outlet_new(x, &s_signal); + outlet_new(x, &s_bang); + return x; +} +static t_int *tabplay_tilde_perform(t_int *w) { + t_tabplay_tilde *x = (t_tabplay_tilde *)w[1]; + t_float *out = (t_float *)w[2], *fp; + int n = (int)w[3], phase = x->phase, endphase = (x->nsampsintab < x->limit ? x->nsampsintab : x->limit), nxfer, n3; + if (!x->vec || phase >= endphase) {while (n--) *out++ = 0; goto bye;} + nxfer = min(endphase-phase,n); + fp = x->vec + phase; + n3 = n - nxfer; + phase += nxfer; + while (nxfer--) *out++ = *fp++; + if (phase >= endphase) { + clock_delay(x->clock, 0); + x->phase = 0x7fffffff; + while (n3--) *out++ = 0; + } else x->phase = phase; + return w+4; +bye: + return w+4; +} +void tabplay_tilde_set(t_tabplay_tilde *x, t_symbol *s) { + t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class); + x->arrayname = s; + if (!a) { + if (*s->name) error("tabplay~: %s: no such array", x->arrayname->name); + x->vec = 0; + } else if (!garray_getfloatarray(a, &x->nsampsintab, &x->vec)) { + error("%s: bad template for tabplay~", x->arrayname->name); + x->vec = 0; + } else garray_usedindsp(a); +} +static void tabplay_tilde_dsp(t_tabplay_tilde *x, t_signal **sp) { + tabplay_tilde_set(x, x->arrayname); + dsp_add(tabplay_tilde_perform, 3, x, sp[0]->v, sp[0]->n); +} +static void tabplay_tilde_list(t_tabplay_tilde *x, t_symbol *s, int argc, t_atom *argv) { + long start = atom_getintarg(0, argc, argv); + long length = atom_getintarg(1, argc, argv); + if (start < 0) start = 0; + if (length <= 0) x->limit = 0x7fffffff; else x->limit = start + length; + x->phase = start; +} +static void tabplay_tilde_stop(t_tabplay_tilde *x) {x->phase = 0x7fffffff;} +static void tabplay_tilde_tick(t_tabplay_tilde *x) {outlet_bang(x->out(1));} +static void tabplay_tilde_free(t_tabplay_tilde *x) {clock_free(x->clock);} + +/******************** tabread~ ***********************/ +static t_class *tabread_tilde_class; +struct t_tabread_tilde : t_object { + int npoints; + float *vec; + t_symbol *arrayname; + float a; +}; +static void *tabread_tilde_new(t_symbol *s) { + t_tabread_tilde *x = (t_tabread_tilde *)pd_new(tabread_tilde_class); + x->arrayname = s; + x->vec = 0; + outlet_new(x, &s_signal); + x->a = 0; + return x; +} +static t_int *tabread_tilde_perform(t_int *w) { + t_tabread_tilde *x = (t_tabread_tilde *)w[1]; + t_float *in = (t_float *)w[2]; + t_float *out = (t_float *)w[3]; + int n = (int)w[4]; + float *buf = x->vec; + int maxindex = x->npoints - 1; + if (!buf) {while (n--) *out++ = 0; goto bad;} + for (int i = 0; i < n; i++) { + int index = (int)*in++; + if (index < 0) index = 0; else if (index > maxindex) index = maxindex; + *out++ = buf[index]; + } +bad:return w+5; +} +void tabread_tilde_set(t_tabread_tilde *x, t_symbol *s) { + x->arrayname = s; + t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class); + if (!a) { + if (*s->name) error("tabread~: %s: no such array", x->arrayname->name); + x->vec = 0; + } else if (!garray_getfloatarray(a, &x->npoints, &x->vec)) { + error("%s: bad template for tabread~", x->arrayname->name); + x->vec = 0; + } else garray_usedindsp(a); +} +static void tabread_tilde_dsp(t_tabread_tilde *x, t_signal **sp) { + tabread_tilde_set(x, x->arrayname); + dsp_add(tabread_tilde_perform, 4, x, sp[0]->v, sp[1]->v, sp[0]->n); +} +static void tabread_tilde_free(t_tabread_tilde *x) {} + +/******************** tabread4~ ***********************/ +static t_class *tabread4_tilde_class; +struct t_tabread4_tilde : t_object { + int npoints; + float *vec; + t_symbol *arrayname; + float a; +}; +static void *tabread4_tilde_new(t_symbol *s) { + t_tabread4_tilde *x = (t_tabread4_tilde *)pd_new(tabread4_tilde_class); + x->arrayname = s; + x->vec = 0; + outlet_new(x, &s_signal); + x->a = 0; + return x; +} +static t_int *tabread4_tilde_perform(t_int *w) { + t_tabread4_tilde *x = (t_tabread4_tilde *)w[1]; + t_float *in = (t_float *)w[2]; + t_float *out = (t_float *)w[3]; + int n = (int)w[4]; + int maxindex; + float *buf = x->vec, *fp; + maxindex = x->npoints - 3; + if (!buf) goto zero; +#if 0 /* test for spam -- I'm not ready to deal with this */ + for (i = 0, xmax = 0, xmin = maxindex, fp = in1; i < n; i++, fp++) { + float f = *in1; + if (f < xmin) xmin = f; + else if (f > xmax) xmax = f; + } + if (xmax < xmin + x->c_maxextent) xmax = xmin + x->c_maxextent; + for (i = 0, splitlo = xmin+ x->c_maxextent, splithi = xmax - x->c_maxextent, + fp = in1; i < n; i++, fp++) { + float f = *in1; + if (f > splitlo && f < splithi) goto zero; + } +#endif + for (int i=0; i maxindex) index = maxindex, frac = 1; + else frac = findex - index; + fp = buf + index; + float a=fp[-1], b=fp[0], c=fp[1], d=fp[2]; + /* if (!i && !(count++ & 1023)) post("fp = %lx, shit = %lx, b = %f", fp, buf->b_shit, b); */ + float cminusb = c-b; + *out++ = b + frac * (cminusb - 0.1666667f * (1.-frac) * ((d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b))); + } + return w+5; + zero: + while (n--) *out++ = 0; + return w+5; +} +void tabread4_tilde_set(t_tabread4_tilde *x, t_symbol *s) { + x->arrayname = s; + t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class); + if (!a) { + if (*s->name) error("tabread4~: %s: no such array", x->arrayname->name); + x->vec = 0; + } else if (!garray_getfloatarray(a, &x->npoints, &x->vec)) { + error("%s: bad template for tabread4~", x->arrayname->name); + x->vec = 0; + } else garray_usedindsp(a); +} +static void tabread4_tilde_dsp(t_tabread4_tilde *x, t_signal **sp) { + tabread4_tilde_set(x, x->arrayname); + dsp_add(tabread4_tilde_perform, 4, x, sp[0]->v, sp[1]->v, sp[0]->n); +} +static void tabread4_tilde_free(t_tabread4_tilde *x) {} + +/******************** tabosc4~ ***********************/ + +#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */ + +#ifdef BIGENDIAN +#define HIOFFSET 0 /* word offset to find MSB */ +#define LOWOFFSET 1 /* word offset to find LSB */ +#else +#define HIOFFSET 1 +#define LOWOFFSET 0 +#endif +#include +//#define int32 int32_t +#define int32 int + +union tabfudge { + double d; + int32 i[2]; +}; +static t_class *tabosc4_tilde_class; +struct t_tabosc4_tilde : t_object { + float fnpoints; + float finvnpoints; + float *vec; + t_symbol *arrayname; + float a; + double phase; + float conv; +}; +static void *tabosc4_tilde_new(t_symbol *s) { + t_tabosc4_tilde *x = (t_tabosc4_tilde *)pd_new(tabosc4_tilde_class); + x->arrayname = s; + x->vec = 0; + x->fnpoints = 512.; + x->finvnpoints = (1./512.); + outlet_new(x, &s_signal); + inlet_new(x, x, &s_float, gensym("ft1")); + x->a = 0; + return x; +} +static t_int *tabosc4_tilde_perform(t_int *w) { + t_tabosc4_tilde *x = (t_tabosc4_tilde *)w[1]; + t_float *in = (t_float *)w[2]; + t_float *out = (t_float *)w[3]; + int n = (int)w[4]; + union tabfudge tf; + float fnpoints = x->fnpoints; + int mask = (int)(fnpoints-1); + float conv = fnpoints * x->conv; + float *tab = x->vec, *addr; + double dphase = fnpoints * x->phase + UNITBIT32; + if (!tab) {while (n--) *out++ = 0; return w+5;} + tf.d = UNITBIT32; + int normhipart = tf.i[HIOFFSET]; +#if 1 + while (n--) { + tf.d = dphase; + dphase += *in++ * conv; + addr = tab + (tf.i[HIOFFSET] & mask); + tf.i[HIOFFSET] = normhipart; + float frac = tf.d - UNITBIT32; + float a = addr[0]; + float b = addr[1]; + float c = addr[2]; + float d = addr[3]; + float cminusb = c-b; + *out++ = b + frac * (cminusb - 0.1666667f * (1.-frac) * ((d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b))); + } +#endif + tf.d = UNITBIT32 * fnpoints; + normhipart = tf.i[HIOFFSET]; + tf.d = dphase + (UNITBIT32 * fnpoints - UNITBIT32); + tf.i[HIOFFSET] = normhipart; + x->phase = (tf.d - UNITBIT32 * fnpoints) * x->finvnpoints; + return w+5; +} +void tabosc4_tilde_set(t_tabosc4_tilde *x, t_symbol *s) { + t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class); + int npoints, pointsinarray; + x->arrayname = s; + if (!a) { + if (*s->name) error("tabosc4~: %s: no such array", x->arrayname->name); + x->vec = 0; + } else if (!garray_getfloatarray(a, &pointsinarray, &x->vec)) { + error("%s: bad template for tabosc4~", x->arrayname->name); + x->vec = 0; + } else if ((npoints = pointsinarray - 3) != (1 << ilog2(pointsinarray - 3))) { + error("%s: number of points (%d) not a power of 2 plus three", x->arrayname->name, pointsinarray); + x->vec = 0; + garray_usedindsp(a); + } else { + x->fnpoints = npoints; + x->finvnpoints = 1./npoints; + garray_usedindsp(a); + } +} +static void tabosc4_tilde_ft1(t_tabosc4_tilde *x, t_float f) { + x->phase = f; +} +static void tabosc4_tilde_dsp(t_tabosc4_tilde *x, t_signal **sp) { + x->conv = 1. / sp[0]->sr; + tabosc4_tilde_set(x, x->arrayname); + dsp_add(tabosc4_tilde_perform, 4, x, sp[0]->v, sp[1]->v, sp[0]->n); +} +static void tabosc4_tilde_setup() { +} + +static void tab_tilde_setup() { + t_class *c; + c = tabwrite_tilde_class = class_new2("tabwrite~",tabwrite_tilde_new,0,sizeof(t_tabwrite_tilde),0,"S"); + CLASS_MAINSIGNALIN(c, t_tabwrite_tilde, a); + class_addmethod2(c, tabwrite_tilde_dsp, "dsp",""); + class_addmethod2(c, tabwrite_tilde_set, "set","s"); + class_addmethod2(c, tabwrite_tilde_stop,"stop",""); + class_addmethod2(c, tabwrite_tilde_start,"start","F"); + class_addbang(c, tabwrite_tilde_bang); + c = tabplay_tilde_class = class_new2("tabplay~",tabplay_tilde_new,tabplay_tilde_free,sizeof(t_tabplay_tilde),0,"S"); + class_addmethod2(c, tabplay_tilde_dsp, "dsp",""); + class_addmethod2(c, tabplay_tilde_stop, "stop",""); + class_addmethod2(c, tabplay_tilde_set, "set","S"); + class_addlist(c, tabplay_tilde_list); + c = tabread_tilde_class = class_new2("tabread~",tabread_tilde_new,tabread_tilde_free, sizeof(t_tabread_tilde),0,"S"); + CLASS_MAINSIGNALIN(c, t_tabread_tilde, a); + class_addmethod2(c, tabread_tilde_dsp, "dsp",""); + class_addmethod2(c, tabread_tilde_set, "set","s"); + c = tabread4_tilde_class = class_new2("tabread4~",tabread4_tilde_new,tabread4_tilde_free,sizeof(t_tabread4_tilde),0,"S"); + CLASS_MAINSIGNALIN(c, t_tabread4_tilde, a); + class_addmethod2(c, tabread4_tilde_dsp, "dsp",""); + class_addmethod2(c, tabread4_tilde_set, "set","s"); + c = tabosc4_tilde_class = class_new2("tabosc4~",tabosc4_tilde_new,0,sizeof(t_tabosc4_tilde),0,"S"); + CLASS_MAINSIGNALIN(c, t_tabosc4_tilde, a); + class_addmethod2(c, tabosc4_tilde_dsp, "dsp",""); + class_addmethod2(c, tabosc4_tilde_set, "set","s"); + class_addmethod2(c, tabosc4_tilde_ft1, "ft1","f"); +} + +/* ------------------------ tabsend~ ------------------------- */ +static t_class *tabsend_class; +struct t_tabsend : t_object { + float *vec; + int graphperiod; + int graphcount; + t_symbol *arrayname; + float a; +}; +static void *tabsend_new(t_symbol *s) { + t_tabsend *x = (t_tabsend *)pd_new(tabsend_class); + x->graphcount = 0; + x->arrayname = s; + x->a = 0; + return x; +} +static t_int *tabsend_perform(t_int *w) { + t_tabsend *x = (t_tabsend *)w[1]; + t_float *in = (t_float *)w[2]; + int n = w[3]; + t_float *dest = x->vec; + int i = x->graphcount; + if (!x->vec) goto bad; + testcopyvec(dest,in,n); + if (!i--) { + t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class); + if (!a) bug("tabsend_dsp"); + else garray_redraw(a); + i = x->graphperiod; + } + x->graphcount = i; +bad: + return w+4; +} +static t_int *tabsend_perf_simd(t_int *w) { + t_tabsend *x = (t_tabsend *)w[1]; + t_float *in = (t_float *)w[2]; + int n = w[3]; + t_float *dest = x->vec; + int i = x->graphcount; + if (!x->vec) goto bad; + testcopyvec_simd(dest,in,n); + if (!i--) { + t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class); + if (!a) bug("tabsend_dsp"); + else garray_redraw(a); + i = x->graphperiod; + } + x->graphcount = i; +bad: + return w+4; +} +static void tabsend_dsp(t_tabsend *x, t_signal **sp) { + int vecsize; + t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class); + if (!a) { + if (*x->arrayname->name) {error("tabsend~: %s: no such array", x->arrayname->name); return;} + } else if (!garray_getfloatarray(a, &vecsize, &x->vec)) { + error("%s: bad template for tabsend~", x->arrayname->name); return; + } else { + int n = sp[0]->n; + int ticksper = (int)(sp[0]->sr/n); + if (ticksper < 1) ticksper = 1; + x->graphperiod = ticksper; + if (x->graphcount > ticksper) x->graphcount = ticksper; + if (n < vecsize) vecsize = n; + garray_usedindsp(a); + if(SIMD_CHECK1(vecsize,sp[0]->v)) + dsp_add(tabsend_perf_simd, 3, x, sp[0]->v, vecsize); + else dsp_add(tabsend_perform, 3, x, sp[0]->v, vecsize); + } +} + +static void tabsend_setup() { + tabsend_class = class_new2("tabsend~",tabsend_new,0,sizeof(t_tabsend),0,"S"); + CLASS_MAINSIGNALIN(tabsend_class, t_tabsend, a); + class_addmethod2(tabsend_class, tabsend_dsp, "dsp",""); +} + +/* ------------------------ tabreceive~ ------------------------- */ +static t_class *tabreceive_class; +struct t_tabreceive : t_object { + float *vec; + int vecsize; + t_symbol *arrayname; +}; +static t_int *tabreceive_perform(t_int *w) { + t_tabreceive *x = (t_tabreceive *)w[1]; + t_float *out = (t_float *)w[2]; + int n = w[3]; + t_float *from = x->vec; + if (from) { + int vecsize = x->vecsize; while (vecsize--) *out++ = *from++; + vecsize = n - x->vecsize; while (vecsize--) *out++ = 0; + } else while (n--) *out++ = 0; + return w+4; +} +static t_int *tabreceive_perf8(t_int *w) { + t_tabreceive *x = (t_tabreceive *)w[1]; + t_float *from = x->vec; + if (from) copyvec_8((t_float *)w[2],from,w[3]); + else zerovec_8((t_float *)w[2], w[3]); + return w+4; +} +static t_int *tabreceive_perfsimd(t_int *w) { + t_tabreceive *x = (t_tabreceive *)w[1]; + t_float *from = x->vec; + if(from) copyvec_simd((t_float *)w[2],from,w[3]); + else zerovec_simd((t_float *)w[2], w[3]); + return w+4; +} +static void tabreceive_dsp(t_tabreceive *x, t_signal **sp) { + t_garray *a; + if (!(a = (t_garray *)pd_findbyclass(x->arrayname, garray_class))) { + if (*x->arrayname->name) error("tabsend~: %s: no such array", x->arrayname->name); + } else if (!garray_getfloatarray(a, &x->vecsize, &x->vec)) { + error("%s: bad template for tabreceive~", x->arrayname->name); + } else { + if (x->vecsize > sp[0]->n) x->vecsize = sp[0]->n; + garray_usedindsp(a); + /* the array is aligned in any case */ + if(sp[0]->n&7) dsp_add(tabreceive_perform, 3, x, sp[0]->v, sp[0]->n); + else if(SIMD_CHECK1(sp[0]->n,sp[0]->v)) + dsp_add(tabreceive_perfsimd, 3, x, sp[0]->v, sp[0]->n); + else dsp_add(tabreceive_perf8, 3, x, sp[0]->v, sp[0]->n); + } +} +static void *tabreceive_new(t_symbol *s) { + t_tabreceive *x = (t_tabreceive *)pd_new(tabreceive_class); + x->arrayname = s; + outlet_new(x, &s_signal); + return x; +} +static void tabreceive_setup() { + tabreceive_class = class_new2("tabreceive~",tabreceive_new,0,sizeof(t_tabreceive),0,"S"); + class_addmethod2(tabreceive_class, tabreceive_dsp, "dsp",""); +} + +/* ---------- tabread: control, non-interpolating ------------------------ */ +static t_class *tabread_class; +struct t_tabread : t_object { + t_symbol *arrayname; +}; +static void tabread_float(t_tabread *x, t_float f) { + int npoints; + t_float *vec; + t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class); + if (!a) {error("%s: no such array", x->arrayname->name); return;} + if (!garray_getfloatarray(a, &npoints, &vec)) {error("%s: bad template for tabread", x->arrayname->name); return;} + int n = clip(int(f),0,npoints-1); + outlet_float(x->outlet, (npoints ? vec[n] : 0)); +} +static void tabread_set(t_tabread *x, t_symbol *s) { + x->arrayname = s; +} +static void *tabread_new(t_symbol *s) { + t_tabread *x = (t_tabread *)pd_new(tabread_class); + x->arrayname = s; + outlet_new(x, &s_float); + return x; +} +static void tabread_setup() { + tabread_class = class_new2("tabread",tabread_new,0,sizeof(t_tabread),0,"S"); + class_addfloat(tabread_class, tabread_float); + class_addmethod2(tabread_class, tabread_set, "set","s"); +} + +/* ---------- tabread4: control, 4-point interpolation --------------- */ +static t_class *tabread4_class; +struct t_tabread4 : t_object { + t_symbol *arrayname; +}; +static void tabread4_float(t_tabread4 *x, t_float f) { + t_garray *ar = (t_garray *)pd_findbyclass(x->arrayname, garray_class); + int npoints; + t_float *vec; + if (!ar) {error("%s: no such array", x->arrayname->name); return;} + if (!garray_getfloatarray(ar, &npoints, &vec)) {error("%s: bad template for tabread4", x->arrayname->name); return;} + if (npoints < 4) {outlet_float(x->outlet, 0); return;} + if (f <= 1) {outlet_float(x->outlet, vec[1]); return;} + if (f >= npoints-2) {outlet_float(x->outlet, vec[npoints-2]); return;} + int n = min(int(f),npoints-3); + float *fp = vec + n; + float frac = f - n; + float a=fp[-1], b=fp[0], c=fp[1], d=fp[2]; + float cminusb = c-b; + outlet_float(x->outlet, b + frac * (cminusb - 0.1666667f * (1.-frac) * ((d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)))); +} +static void tabread4_set(t_tabread4 *x, t_symbol *s) {x->arrayname = s;} +static void *tabread4_new(t_symbol *s) { + t_tabread4 *x = (t_tabread4 *)pd_new(tabread4_class); + x->arrayname = s; + outlet_new(x, &s_float); + return x; +} +static void tabread4_setup() { + tabread4_class = class_new2("tabread4",tabread4_new,0,sizeof(t_tabread4),0,"S"); + class_addfloat(tabread4_class, tabread4_float); + class_addmethod2(tabread4_class, tabread4_set, "set","s"); +} + +/* ------------------ tabwrite: control ------------------------ */ +static t_class *tabwrite_class; +struct t_tabwrite : t_object { + t_symbol *arrayname; + float ft1; +}; +static void tabwrite_float(t_tabwrite *x, t_float f) { + int vecsize; + t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class); + t_float *vec; + if (!a) {error("%s: no such array", x->arrayname->name); return;} + if (!garray_getfloatarray(a, &vecsize, &vec)) {error("%s: bad template for tabwrite", x->arrayname->name); return;} + int n = (int)x->ft1; + if (n < 0) n = 0; else if (n > vecsize-1) n = vecsize-1; + vec[n] = f; + garray_redraw(a); +} +static void tabwrite_set(t_tabwrite *x, t_symbol *s) {x->arrayname = s;} +static void *tabwrite_new(t_symbol *s) { + t_tabwrite *x = (t_tabwrite *)pd_new(tabwrite_class); + x->ft1 = 0; + x->arrayname = s; + floatinlet_new(x, &x->ft1); + return x; +} +void tabwrite_setup() { + tabwrite_class = class_new2("tabwrite",tabwrite_new,0,sizeof(t_tabwrite),0,"S"); + class_addfloat(tabwrite_class, tabwrite_float); + class_addmethod2(tabwrite_class, tabwrite_set, "set","s"); +} + +/* -------------------------- sig~ ------------------------------ */ +static t_class *sig_tilde_class; +struct t_sig : t_object { + float a; +}; +t_int *sig_tilde_perform(t_int *w) { + t_float f = *(t_float *)w[1]; + t_float *out = (t_float *)w[2]; + int n = (int)w[3]; + while (n--) *out++ = f; + return w+4; +} +t_int *sig_tilde_perf8(t_int *w) { + t_float f = *(t_float *)w[1]; + t_float *out = (t_float *)w[2]; + int n = (int)w[3]; + for (; n; n -= 8, out += 8) { + out[0] = f; out[1] = f; + out[2] = f; out[3] = f; + out[4] = f; out[5] = f; + out[6] = f; out[7] = f; + } + return w+4; +} +void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n) { + if (n&7) + dsp_add(sig_tilde_perform, 3, in, out, n); + else if(SIMD_CHECK1(n,out)) + dsp_add(sig_tilde_perf_simd, 3, in, out, n); + else dsp_add(sig_tilde_perf8, 3, in, out, n); +} +static void sig_tilde_float(t_sig *x, t_float f) { + x->a = f; +} +static void sig_tilde_dsp(t_sig *x, t_signal **sp) { +/* dsp_add(sig_tilde_perform, 3, &x->a, sp[0]->v, sp[0]->n); */ + /* T.Grill - use chance of unrolling */ + dsp_add_scalarcopy(&x->a, sp[0]->v, sp[0]->n); +} +static void *sig_tilde_new(t_floatarg f) { + t_sig *x = (t_sig *)pd_new(sig_tilde_class); + x->a = f; + outlet_new(x, &s_signal); + return x; +} +static void sig_tilde_setup() { + sig_tilde_class = class_new2("sig~",sig_tilde_new,0,sizeof(t_sig),0,"F"); + class_addfloat(sig_tilde_class, sig_tilde_float); + class_addmethod2(sig_tilde_class, sig_tilde_dsp,"dsp",""); +} + +/* -------------------------- line~ ------------------------------ */ +static t_class *line_tilde_class; +struct t_line : t_object { + float target; + float value; + float biginc; + float inc; + float oneovern; + float dspticktomsec; + float inletvalue; + float inletwas; + int ticksleft; + int retarget; + float* slopes; /* tb: for simd-optimized line */ + float slopestep; /* tb: 4*x->inc */ +}; +static t_int *line_tilde_perform(t_int *w) { + t_line *x = (t_line *)w[1]; + t_float *out = (t_float *)w[2]; + int n = (int)w[3]; + float f = x->value; + if (PD_BIGORSMALL(f)) x->value = f = 0; + if (x->retarget) { + int nticks = (int)(x->inletwas * x->dspticktomsec); + if (!nticks) nticks = 1; + x->ticksleft = nticks; + x->biginc = (x->target - x->value)/(float)nticks; + x->inc = x->oneovern * x->biginc; + x->retarget = 0; + } + if (x->ticksleft) { + float f = x->value; + float slope = x->inc; /* tb: make sure, x->inc is loaded to a register */ + while (n--) *out++ = f, f += slope; + x->value += x->biginc; + x->ticksleft--; + } else { + float g = x->value = x->target; + while (n--) + *out++ = g; + } + return w+4; +} +/* tb: vectorized / simd version { */ +static void line_tilde_slope(t_float* out, t_int n, t_float* value, t_float* slopes, t_float* slopestep) { + t_float slope = slopes[1]; + t_float f = *value; + n>>=3; + while (n--) { + *out++ = f;f += slope; + *out++ = f;f += slope; + *out++ = f;f += slope; + *out++ = f;f += slope; + *out++ = f;f += slope; + *out++ = f;f += slope; + *out++ = f;f += slope; + *out++ = f;f += slope; + } +} +static t_int *line_tilde_perf8(t_int *w) { + t_line *x = (t_line *)w[1]; + t_float *out = (t_float *)w[2]; + int n = (int)w[3]; + float f = x->value; + if (PD_BIGORSMALL(f)) x->value = f = 0; + if (x->retarget) { + int nticks = (int)(x->inletwas * x->dspticktomsec); + if (!nticks) nticks = 1; + x->ticksleft = nticks; + x->biginc = (x->target - x->value)/(float)nticks; + x->inc = x->oneovern * x->biginc; + x->retarget = 0; + /* tb: rethink!!! this is ugly */ + for (int i = 0; i != 4; ++i) x->slopes[i] = i*x->inc; + x->slopestep = 4 * x->inc; + } + if (x->ticksleft) { + line_tilde_slope(out, n, &x->value, x->slopes, &x->slopestep); + x->value += x->biginc; + x->ticksleft--; + } else { + float f = x->value = x->target; + setvec_8(out,f,n); + } + return w+4; +} +static t_int *line_tilde_perfsimd(t_int *w) { + t_line *x = (t_line *)w[1]; + t_float *out = (t_float *)w[2]; + int n = (int)w[3]; + float f = x->value; + if (PD_BIGORSMALL(f)) x->value = f = 0; + if (x->retarget) { + int nticks = (int)(x->inletwas * x->dspticktomsec); + if (!nticks) nticks = 1; + x->ticksleft = nticks; + x->biginc = (x->target - x->value)/(float)nticks; + x->inc = x->oneovern * x->biginc; + x->retarget = 0; + for (int i = 0; i != 4; ++i) x->slopes[i] = i*x->inc; + x->slopestep = 4 * x->inc; + } + if (x->ticksleft) { + line_tilde_slope_simd(out, n, &x->value, x->slopes, &x->slopestep); + x->value += x->biginc; + x->ticksleft--; + } else { + float f = x->value = x->target; + setvec_simd(out,f,n); + } + return w+4; +} +/* tb } */ +static void line_tilde_float(t_line *x, t_float f) { + if (x->inletvalue <= 0) { + x->target = x->value = f; + x->ticksleft = x->retarget = 0; + } else { + x->target = f; + x->retarget = 1; + x->inletwas = x->inletvalue; + x->inletvalue = 0; + } +} +static void line_tilde_stop(t_line *x) { + x->target = x->value; + x->ticksleft = x->retarget = 0; +} +static void line_tilde_dsp(t_line *x, t_signal **sp) { + if(sp[0]->n&7) + dsp_add(line_tilde_perform, 3, x, sp[0]->v, sp[0]->n); + else if (SIMD_CHECK1(sp[0]->n,sp[0]->v)) + dsp_add(line_tilde_perfsimd, 3, x, sp[0]->v, sp[0]->n); + else dsp_add(line_tilde_perf8, 3, x, sp[0]->v, sp[0]->n); + x->oneovern = 1./sp[0]->n; + x->dspticktomsec = sp[0]->sr / (1000 * sp[0]->n); +} +/* tb: modified for simd-optimized line~ */ +static void *line_tilde_new() { + t_line *x = (t_line *)pd_new(line_tilde_class); + outlet_new(x, &s_signal); + floatinlet_new(x, &x->inletvalue); + x->ticksleft = x->retarget = 0; + x->value = x->target = x->inletvalue = x->inletwas = 0; + x->slopes = (t_float *)getalignedbytes(4*sizeof(t_float)); + return x; +} + +static void line_tilde_free(t_line * x) { + freealignedbytes(x->slopes, 4*sizeof(t_float)); +} +static void line_tilde_setup() { + line_tilde_class = class_new2("line~",line_tilde_new,line_tilde_free,sizeof(t_line),0,""); + class_addfloat(line_tilde_class, line_tilde_float); + class_addmethod2(line_tilde_class, line_tilde_dsp, "dsp",""); + class_addmethod2(line_tilde_class, line_tilde_stop,"stop",""); +} + +/* -------------------------- vline~ ------------------------------ */ +static t_class *vline_tilde_class; +struct t_vseg { + double s_targettime; + double s_starttime; + float s_target; + t_vseg *s_next; +}; +struct t_vline : t_object { + double value; + double inc; + double referencetime; + double samppermsec; + double msecpersamp; + double targettime; + float target; + float inlet1; + float inlet2; + t_vseg *list; +}; +static t_int *vline_tilde_perform(t_int *w) { + t_vline *x = (t_vline *)w[1]; + t_float *out = (t_float *)w[2]; + int n = (int)w[3], i; + double f = x->value; + double inc = x->inc; + double msecpersamp = x->msecpersamp; + double timenow = clock_gettimesince(x->referencetime) - n * msecpersamp; + t_vseg *s = x->list; + for (i = 0; i < n; i++) { + double timenext = timenow + msecpersamp; + checknext: + if (s) { + /* has starttime elapsed? If so update value and increment */ + if (s->s_starttime < timenext) { + if (x->targettime <= timenext) + f = x->target, inc = 0; + /* if zero-length segment bash output value */ + if (s->s_targettime <= s->s_starttime) { + f = s->s_target; + inc = 0; + } else { + double incpermsec = (s->s_target - f)/ + (s->s_targettime - s->s_starttime); + f = f + incpermsec * (timenext - s->s_starttime); + inc = incpermsec * msecpersamp; + } + x->inc = inc; + x->target = s->s_target; + x->targettime = s->s_targettime; + x->list = s->s_next; + free(s); + s = x->list; + goto checknext; + } + } + if (x->targettime <= timenext) + f = x->target, inc = x->inc = 0, x->targettime = 1e20; + *out++ = f; + f = f + inc; + timenow = timenext; + } + x->value = f; + return w+4; +} +static void vline_tilde_stop(t_vline *x) { + t_vseg *s1, *s2; + for (s1 = x->list; s1; s1 = s2) + s2 = s1->s_next, free(s1); + x->list = 0; + x->inc = 0; + x->inlet1 = x->inlet2 = 0; + x->target = x->value; + x->targettime = 1e20; +} +static void vline_tilde_float(t_vline *x, t_float f) { + double timenow = clock_gettimesince(x->referencetime); + float inlet1 = (x->inlet1 < 0 ? 0 : x->inlet1); + float inlet2 = x->inlet2; + double starttime = timenow + inlet2; + t_vseg *s1, *s2, *deletefrom = 0, *snew; + if (PD_BIGORSMALL(f)) f = 0; + /* negative delay input means stop and jump immediately to new value */ + if (inlet2 < 0) { + x->value = f; + vline_tilde_stop(x); + return; + } + snew = (t_vseg *)t_getbytes(sizeof(*snew)); + /* check if we supplant the first item in the list. We supplant + an item by having an earlier starttime, or an equal starttime unless + the equal one was instantaneous and the new one isn't (in which case + we'll do a jump-and-slide starting at that time.) */ + if (!x->list || x->list->s_starttime > starttime || + (x->list->s_starttime == starttime && + (x->list->s_targettime > x->list->s_starttime || inlet1 <= 0))) { + deletefrom = x->list; + x->list = snew; + } else { + for (s1 = x->list; (s2 = s1->s_next); s1 = s2) { + if (s2->s_starttime > starttime || + (s2->s_starttime == starttime && + (s2->s_targettime > s2->s_starttime || inlet1 <= 0))) { + deletefrom = s2; + s1->s_next = snew; + goto didit; + } + } + s1->s_next = snew; + deletefrom = 0; + didit: ; + } + while (deletefrom) { + s1 = deletefrom->s_next; + free(deletefrom); + deletefrom = s1; + } + snew->s_next = 0; + snew->s_target = f; + snew->s_starttime = starttime; + snew->s_targettime = starttime + inlet1; + x->inlet1 = x->inlet2 = 0; +} +static void vline_tilde_dsp(t_vline *x, t_signal **sp) { + dsp_add(vline_tilde_perform, 3, x, sp[0]->v, sp[0]->n); + x->samppermsec = ((double)(sp[0]->sr)) / 1000; + x->msecpersamp = ((double)1000) / sp[0]->sr; +} +static void *vline_tilde_new() { + t_vline *x = (t_vline *)pd_new(vline_tilde_class); + outlet_new(x, &s_signal); + floatinlet_new(x, &x->inlet1); + floatinlet_new(x, &x->inlet2); + x->inlet1 = x->inlet2 = 0; + x->value = x->inc = 0; + x->referencetime = clock_getlogicaltime(); + x->list = 0; + x->samppermsec = 0; + x->targettime = 1e20; + return x; +} +static void vline_tilde_setup() { + vline_tilde_class = class_new2("vline~",vline_tilde_new,vline_tilde_stop,sizeof(t_vline),0,""); + class_addfloat(vline_tilde_class, vline_tilde_float); + class_addmethod2(vline_tilde_class, vline_tilde_dsp, "dsp",""); + class_addmethod2(vline_tilde_class, vline_tilde_stop,"stop",""); +} + +/* -------------------------- snapshot~ ------------------------------ */ +static t_class *snapshot_tilde_class; +struct t_snapshot : t_object { + t_sample value; + float a; +}; +static void *snapshot_tilde_new() { + t_snapshot *x = (t_snapshot *)pd_new(snapshot_tilde_class); + x->value = 0; + outlet_new(x, &s_float); + x->a = 0; + return x; +} +static t_int *snapshot_tilde_perform(t_int *w) { + t_float *in = (t_float *)w[1]; + t_float *out = (t_float *)w[2]; + *out = *in; + return w+3; +} +static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp) { + dsp_add(snapshot_tilde_perform, 2, sp[0]->v + (sp[0]->n-1), &x->value); +} +static void snapshot_tilde_bang(t_snapshot *x) { + outlet_float(x->outlet, x->value); +} +static void snapshot_tilde_set(t_snapshot *x, t_floatarg f) { + x->value = f; +} +static void snapshot_tilde_setup() { + snapshot_tilde_class = class_new2("snapshot~",snapshot_tilde_new,0,sizeof(t_snapshot),0,""); + CLASS_MAINSIGNALIN(snapshot_tilde_class, t_snapshot, a); + class_addmethod2(snapshot_tilde_class, snapshot_tilde_dsp, "dsp",""); + class_addmethod2(snapshot_tilde_class, snapshot_tilde_set, "set","s"); + class_addbang(snapshot_tilde_class, snapshot_tilde_bang); +} + +/* -------------------------- vsnapshot~ ------------------------------ */ +static t_class *vsnapshot_tilde_class; +struct t_vsnapshot : t_object { + int n; + int gotone; + t_sample *vec; + float a; + float sampspermsec; + double time; +}; +static void *vsnapshot_tilde_new() { + t_vsnapshot *x = (t_vsnapshot *)pd_new(vsnapshot_tilde_class); + outlet_new(x, &s_float); + x->a = 0; + x->n = 0; + x->vec = 0; + x->gotone = 0; + return x; +} +static t_int *vsnapshot_tilde_perform(t_int *w) { + t_float *in = (t_float *)w[1]; + t_vsnapshot *x = (t_vsnapshot *)w[2]; + t_float *out = x->vec; + int n = x->n, i; + for (i = 0; i < n; i++) out[i] = in[i]; + x->time = clock_getlogicaltime(); + x->gotone = 1; + return w+3; +} +static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp) { + int n = sp[0]->n; + if (n != x->n) { + if (x->vec) free(x->vec); + x->vec = (t_sample *)getbytes(n * sizeof(t_sample)); + x->gotone = 0; + x->n = n; + } + x->sampspermsec = sp[0]->sr / 1000; + dsp_add(vsnapshot_tilde_perform, 2, sp[0]->v, x); +} +static void vsnapshot_tilde_bang(t_vsnapshot *x) { + float val; + if (x->gotone) { + int indx = clip((int)(clock_gettimesince(x->time) * x->sampspermsec),0,x->n-1); + val = x->vec[indx]; + } else val = 0; + outlet_float(x->outlet, val); +} +static void vsnapshot_tilde_ff(t_vsnapshot *x) { + if (x->vec) free(x->vec); +} +static void vsnapshot_tilde_setup() { + vsnapshot_tilde_class = + class_new2("vsnapshot~",vsnapshot_tilde_new, vsnapshot_tilde_ff,sizeof(t_vsnapshot), 0,""); + CLASS_MAINSIGNALIN(vsnapshot_tilde_class, t_vsnapshot, a); + class_addmethod2(vsnapshot_tilde_class, vsnapshot_tilde_dsp, "dsp",""); + class_addbang(vsnapshot_tilde_class, vsnapshot_tilde_bang); +} + +/* ---------------- env~ - simple envelope follower. ----------------- */ +#define MAXOVERLAP 10 +#define MAXVSTAKEN 64 +struct t_sigenv : t_object { + t_clock *clock; /* a "clock" object */ + float *buf; /* a Hanning window */ + int phase; /* number of points since last output */ + int period; /* requested period of output */ + int realperiod; /* period rounded up to vecsize multiple */ + int npoints; /* analysis window size in samples */ + float result; /* result to output */ + float sumbuf[MAXOVERLAP]; /* summing buffer */ + float a; +}; +t_class *env_tilde_class; +static void env_tilde_tick(t_sigenv *x); +static void *env_tilde_new(t_floatarg fnpoints, t_floatarg fperiod) { + int npoints = (int)fnpoints; + int period = (int)fperiod; + float *buf; + if (npoints < 1) npoints = 1024; + if (period < 1) period = npoints/2; + if (period < npoints / MAXOVERLAP + 1) + period = npoints / MAXOVERLAP + 1; + if (!(buf = (float *)getalignedbytes(sizeof(float) * (npoints + MAXVSTAKEN)))) { + error("env: couldn't allocate buffer"); + return 0; + } + t_sigenv *x = (t_sigenv *)pd_new(env_tilde_class); + x->buf = buf; + x->npoints = npoints; + x->phase = 0; + x->period = period; + int i; + for (i = 0; i < MAXOVERLAP; i++) x->sumbuf[i] = 0; + for (i = 0; i < npoints; i++) buf[i] = (1. - cos((2 * 3.14159 * i) / npoints))/npoints; + for (; i < npoints+MAXVSTAKEN; i++) buf[i] = 0; + x->clock = clock_new(x, env_tilde_tick); + x->outlet = outlet_new(x, &s_float); + x->a = 0; + return x; +} +static t_int *env_tilde_perform(t_int *w) { + t_sigenv *x = (t_sigenv *)w[1]; + t_float *in = (t_float *)w[2]; + int n = (int)w[3]; + float *sump = x->sumbuf; + in += n; + for (int count = x->phase; count < x->npoints; count += x->realperiod, sump++) { + float *hp = x->buf + count; + float *fp = in; + float sum = *sump; + for (int i = 0; i < n; i++) { + fp--; + sum += *hp++ * (*fp * *fp); + } + *sump = sum; + } + sump[0] = 0; + x->phase -= n; + if (x->phase < 0) { + x->result = x->sumbuf[0]; + sump = x->sumbuf; + for (int count = x->realperiod; count < x->npoints; count += x->realperiod, sump++) sump[0] = sump[1]; + sump[0] = 0; + x->phase = x->realperiod - n; + clock_delay(x->clock, 0L); + } + return w+4; +} +/* tb: loop unrolling and simd */ +static float env_tilde_accum_8(t_float* in, t_float* hp, t_int n) { + float ret = 0; + n>>=3; + for (int i = 0; i !=n; ++i) { + in--; ret += *hp++ * (*in * *in); + in--; ret += *hp++ * (*in * *in); + in--; ret += *hp++ * (*in * *in); + in--; ret += *hp++ * (*in * *in); + in--; ret += *hp++ * (*in * *in); + in--; ret += *hp++ * (*in * *in); + in--; ret += *hp++ * (*in * *in); + in--; ret += *hp++ * (*in * *in); + } + return ret; +} +static t_int *env_tilde_perf8(t_int *w) { + t_sigenv *x = (t_sigenv *)w[1]; + t_float *in = (t_float *)w[2]; + int n = (int)w[3]; + float *sump = x->sumbuf; + in += n; + for (int count = x->phase; count < x->npoints; count += x->realperiod, sump++) { + *sump += env_tilde_accum_8(in, x->buf + count, n); + } + sump[0] = 0; + x->phase -= n; + if (x->phase < 0) { + x->result = x->sumbuf[0]; + float *sump = x->sumbuf; + for (int count = x->realperiod; count < x->npoints; count += x->realperiod, sump++) + sump[0] = sump[1]; + sump[0] = 0; + x->phase = x->realperiod - n; + clock_delay(x->clock, 0L); + } + return w+4; +} +static t_int *env_tilde_perf_simd(t_int *w) { + t_sigenv *x = (t_sigenv *)w[1]; + t_float *in = (t_float *)w[2]; + int n = (int)w[3]; + float *sump = x->sumbuf; + in += n; + for (int count = x->phase; count < x->npoints; count += x->realperiod, sump++) { + *sump += env_tilde_accum_simd(in, x->buf + count, n); + } + sump[0] = 0; + x->phase -= n; + if (x->phase < 0) { + x->result = x->sumbuf[0]; + float *sump = x->sumbuf; + for (int count = x->realperiod; count < x->npoints; count += x->realperiod, sump++) sump[0] = sump[1]; + sump[0] = 0; + x->phase = x->realperiod - n; + clock_delay(x->clock, 0L); + } + return w+4; +} +static void env_tilde_dsp(t_sigenv *x, t_signal **sp) { + int mod = x->period % sp[0]->n; + if (mod) x->realperiod = x->period + sp[0]->n - mod; else x->realperiod = x->period; + if (sp[0]->n & 7) + dsp_add(env_tilde_perform, 3, x, sp[0]->v, sp[0]->n); + else if (SIMD_CHECK1(sp[0]->n, sp[0]->v)) + dsp_add(env_tilde_perf_simd, 3, x, sp[0]->v, sp[0]->n); + else dsp_add(env_tilde_perf8, 3, x, sp[0]->v, sp[0]->n); + if (sp[0]->n > MAXVSTAKEN) bug("env_tilde_dsp"); +} +static void env_tilde_tick(t_sigenv *x) { + outlet_float(x->outlet, powtodb(x->result)); +} +static void env_tilde_ff(t_sigenv *x) { + clock_free(x->clock); + freealignedbytes(x->buf, (x->npoints + MAXVSTAKEN) * sizeof(float)); +} +void env_tilde_setup() { + env_tilde_class = class_new2("env~",env_tilde_new,env_tilde_ff,sizeof(t_sigenv),0,"FF"); + CLASS_MAINSIGNALIN(env_tilde_class, t_sigenv, a); + class_addmethod2(env_tilde_class, env_tilde_dsp, "dsp",""); +} + +/* --------------------- threshold~ ----------------------------- */ +static t_class *threshold_tilde_class; +struct t_threshold_tilde : t_object { + t_clock *clock; /* wakeup for message output */ + float a; /* scalar inlet */ + int state; /* 1 = high, 0 = low */ + float hithresh; /* value of high threshold */ + float lothresh; /* value of low threshold */ + float deadwait; /* msec remaining in dead period */ + float msecpertick; /* msec per DSP tick */ + float hideadtime; /* hi dead time in msec */ + float lodeadtime; /* lo dead time in msec */ +}; +static void threshold_tilde_tick(t_threshold_tilde *x); +/* "set" message to specify thresholds and dead times */ +static void threshold_tilde_set(t_threshold_tilde *x, + t_floatarg hithresh, t_floatarg hideadtime, + t_floatarg lothresh, t_floatarg lodeadtime) { + if (lothresh > hithresh) lothresh = hithresh; + x->hithresh = hithresh; x->hideadtime = hideadtime; + x->lothresh = lothresh; x->lodeadtime = lodeadtime; +} +static t_threshold_tilde *threshold_tilde_new(t_floatarg hithresh, + t_floatarg hideadtime, t_floatarg lothresh, t_floatarg lodeadtime) { + t_threshold_tilde *x = (t_threshold_tilde *)pd_new(threshold_tilde_class); + x->state = 0; /* low state */ + x->deadwait = 0; /* no dead time */ + x->clock = clock_new(x, threshold_tilde_tick); + outlet_new(x, &s_bang); + outlet_new(x, &s_bang); + inlet_new(x, x, &s_float, gensym("ft1")); + x->msecpertick = 0.; + x->a = 0; + threshold_tilde_set(x, hithresh, hideadtime, lothresh, lodeadtime); + return x; +} +/* number in inlet sets state -- note incompatible with JMAX which used + "int" message for this, impossible here because of auto signal conversion */ +static void threshold_tilde_ft1(t_threshold_tilde *x, t_floatarg f) { + x->state = (f != 0); + x->deadwait = 0; +} +static void threshold_tilde_tick(t_threshold_tilde *x) { + outlet_bang(x->out(x->state?0:1)); +} +static t_int *threshold_tilde_perform(t_int *w) { + float *in1 = (float *)w[1]; + t_threshold_tilde *x = (t_threshold_tilde *)w[2]; + int n = (t_int)w[3]; + if (x->deadwait > 0) + x->deadwait -= x->msecpertick; + else if (x->state) { + /* we're high; look for low sample */ + for (; n--; in1++) { + if (*in1 < x->lothresh) { + clock_delay(x->clock, 0L); + x->state = 0; + x->deadwait = x->lodeadtime; + goto done; + } + } + } else { + /* we're low; look for high sample */ + for (; n--; in1++) { + if (*in1 >= x->hithresh) { + clock_delay(x->clock, 0L); + x->state = 1; + x->deadwait = x->hideadtime; + goto done; + } + } + } +done: + return w+4; +} +void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp) { + x->msecpertick = 1000. * sp[0]->n / sp[0]->sr; + dsp_add(threshold_tilde_perform, 3, sp[0]->v, x, sp[0]->n); +} +static void threshold_tilde_ff(t_threshold_tilde *x) {clock_free(x->clock);} +static void threshold_tilde_setup() { + t_class *c = threshold_tilde_class = + class_new2("threshold~",threshold_tilde_new,threshold_tilde_ff,sizeof(t_threshold_tilde), 0, "FFFF"); + CLASS_MAINSIGNALIN(c, t_threshold_tilde, a); + class_addmethod2(c, threshold_tilde_set, "set","ffff"); + class_addmethod2(c, threshold_tilde_ft1, "ft1","f"); + class_addmethod2(c, threshold_tilde_dsp, "dsp",""); +} + +/* ----------------------------- dac~ --------------------------- */ +static t_class *dac_class; +struct t_dac : t_object { + t_int n; + t_int *vec; + float a; +}; +static void *dac_new(t_symbol *s, int argc, t_atom *argv) { + t_dac *x = (t_dac *)pd_new(dac_class); + t_atom defarg[2]; + if (!argc) { + argv = defarg; + argc = 2; + SETFLOAT(&defarg[0], 1); + SETFLOAT(&defarg[1], 2); + } + x->n = argc; + x->vec = (t_int *)getbytes(argc * sizeof(*x->vec)); + for (int i = 0; i < argc; i++) x->vec[i] = atom_getintarg(i, argc, argv); + for (int i = 1; i < argc; i++) inlet_new(x, x, &s_signal, &s_signal); + x->a = 0; + return x; +} +static void dac_dsp(t_dac *x, t_signal **sp) { + t_int i, *ip; + t_signal **sp2; + for (i = x->n, ip = x->vec, sp2 = sp; i--; ip++, sp2++) { + int ch = *ip - 1; + if ((*sp2)->n != sys_dacblocksize) error("dac~: bad vector size"); + else if (ch >= 0 && ch < sys_get_outchannels()) + if(SIMD_CHECK3(sys_dacblocksize,sys_soundout + sys_dacblocksize*ch, (*sp2)->v,sys_soundout + sys_dacblocksize*ch)) + dsp_add(plus_perf_simd, 4, sys_soundout + sys_dacblocksize*ch, + (*sp2)->v, sys_soundout + sys_dacblocksize*ch, sys_dacblocksize); + else + dsp_add(plus_perform, 4, sys_soundout + sys_dacblocksize*ch, (*sp2)->v, sys_soundout + sys_dacblocksize*ch, + sys_dacblocksize); + } +} +static void dac_free(t_dac *x) {free(x->vec);} +static void dac_setup() { + dac_class = class_new2("dac~",dac_new,dac_free,sizeof(t_dac),0,"*"); + CLASS_MAINSIGNALIN(dac_class, t_dac, a); + class_addmethod2(dac_class, dac_dsp, "dsp","!"); + class_sethelpsymbol(dac_class, gensym("adc~_dac~")); +} + +/* ----------------------------- adc~ --------------------------- */ +static t_class *adc_class; +struct t_adc : t_object { + t_int n; + t_int *vec; +}; +static void *adc_new(t_symbol *s, int argc, t_atom *argv) { + t_adc *x = (t_adc *)pd_new(adc_class); + t_atom defarg[2]; + if (!argc) { + argv = defarg; + argc = 2; + SETFLOAT(&defarg[0], 1); + SETFLOAT(&defarg[1], 2); + } + x->n = argc; + x->vec = (t_int *)getbytes(argc * sizeof(*x->vec)); + for (int i = 0; i < argc; i++) x->vec[i] = atom_getintarg(i, argc, argv); + for (int i = 0; i < argc; i++) outlet_new(x, &s_signal); + return x; +} +t_int *copy_perform(t_int *w) { + t_float *in1 = (t_float *)w[1]; + t_float *out = (t_float *)w[2]; + int n = (int)w[3]; + while (n--) *out++ = *in1++; + return w+4; +} +t_int *copy_perf8(t_int *w) { + t_float *in1 = (t_float *)w[1]; + t_float *out = (t_float *)w[2]; + int n = (int)w[3]; + for (; n; n -= 8, in1 += 8, out += 8) { + out[0] = in1[0]; + out[1] = in1[1]; + out[2] = in1[2]; + out[3] = in1[3]; + out[4] = in1[4]; + out[5] = in1[5]; + out[6] = in1[6]; + out[7] = in1[7]; + } + return w+4; +} +void dsp_add_copy(t_sample *in, t_sample *out, int n) { + if (n&7) + dsp_add(copy_perform, 3, in, out, n); + else if (SIMD_CHECK2(n,in,out)) + dsp_add(copy_perf_simd, 3, in, out, n); + else dsp_add(copy_perf8, 3, in, out, n); +} +static void adc_dsp(t_adc *x, t_signal **sp) { + t_int i, *ip; + t_signal **sp2; + for (i = x->n, ip = x->vec, sp2 = sp; i--; ip++, sp2++) { + int ch = *ip - 1; + if ((*sp2)->n != sys_dacblocksize) + error("adc~: bad vector size"); + else if (ch >= 0 && ch < sys_get_inchannels()) + dsp_add_copy(sys_soundin + sys_dacblocksize*ch, (*sp2)->v, sys_dacblocksize); + else dsp_add_zero((*sp2)->v, sys_dacblocksize); + } +} +static void adc_free(t_adc *x) {free(x->vec);} +static void adc_setup() { + adc_class = class_new2("adc~",adc_new,adc_free,sizeof(t_adc),0,"*"); + class_addmethod2(adc_class, adc_dsp, "dsp","!"); + class_sethelpsymbol(adc_class, gensym("adc~_dac~")); +} + +/* ----------------------------- delwrite~ ----------------------------- */ +static t_class *sigdelwrite_class; +struct t_delwritectl { + int c_n; + float *c_vec; + int c_phase; +}; +struct t_sigdelwrite : t_object { + t_symbol *sym; + t_delwritectl cspace; + int sortno; /* DSP sort number at which this was last put on chain */ + int rsortno; /* DSP sort # for first delread or write in chain */ + int vecsize; /* vector size for delread~ to use */ + float a; +}; +#define XTRASAMPS 4 +#define SAMPBLK 4 +/* routine to check that all delwrites/delreads/vds have same vecsize */ +static void sigdelwrite_checkvecsize(t_sigdelwrite *x, int vecsize) { + if (x->rsortno != ugen_getsortno()) { + x->vecsize = vecsize; + x->rsortno = ugen_getsortno(); + } + /* LATER this should really check sample rate and blocking, once that is + supported. Probably we don't actually care about vecsize. + For now just suppress this check. */ +#if 0 + else if (vecsize != x->vecsize) + error("delread/delwrite/vd vector size mismatch"); +#endif +} +static void *sigdelwrite_new(t_symbol *s, t_floatarg msec) { + t_sigdelwrite *x = (t_sigdelwrite *)pd_new(sigdelwrite_class); + if (!*s->name) s = gensym("delwrite~"); + pd_bind(x, s); + x->sym = s; + int nsamps = (int)(msec * sys_getsr() * (float)(0.001f)); + if (nsamps < 1) nsamps = 1; + nsamps += ((- nsamps) & (SAMPBLK - 1)); + nsamps += DEFDELVS; +#ifdef SIMD_BYTEALIGN + nsamps += (SIMD_BYTEALIGN - nsamps) % SIMD_BYTEALIGN; /* tb: for simd */ +#endif + x->cspace.c_n = nsamps; + x->cspace.c_vec = (float *)getalignedbytes((nsamps + XTRASAMPS) * sizeof(float)); + x->cspace.c_phase = XTRASAMPS; + x->sortno = 0; + x->vecsize = 0; + x->a = 0; + return x; +} +static t_int *sigdelwrite_perform(t_int *w) { + t_float *in = (t_float *)w[1]; + t_delwritectl *c = (t_delwritectl *)w[2]; + int n = (int)w[3]; + int phase = c->c_phase, nsamps = c->c_n; + float *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS); + phase += n; + while (n--) { + float f = *in++; + if (PD_BIGORSMALL(f)) + f = 0; + *bp++ = f; + if (bp == ep) { + vp[0] = ep[-4]; + vp[1] = ep[-3]; + vp[2] = ep[-2]; + vp[3] = ep[-1]; + bp = vp + XTRASAMPS; + phase -= nsamps; + } + } + c->c_phase = phase; + return w+4; +} +static t_int *sigdelwrite_perf8(t_int *w) { + t_float *in = (t_float *)w[1]; + t_delwritectl *c = (t_delwritectl *)w[2]; + int n = (int)w[3]; + int phase = c->c_phase, nsamps = c->c_n; + float *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS); + phase += n; + if (phase > nsamps) + while (n--) { + float f = *in++; + if (PD_BIGORSMALL(f)) f = 0; + *bp++ = f; + if (bp == ep) { + vp[0] = ep[-4]; + vp[1] = ep[-3]; + vp[2] = ep[-2]; + vp[3] = ep[-1]; + bp = vp + XTRASAMPS; + phase -= nsamps; + } + } + else testcopyvec_8(bp, in, n); + c->c_phase = phase; + return w+4; +} +static t_int *sigdelwrite_perfsimd(t_int *w) { + t_float *in = (t_float *)w[1]; + t_delwritectl *c = (t_delwritectl *)w[2]; + int n = (int)w[3]; + int phase = c->c_phase, nsamps = c->c_n; + float *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS); + phase += n; + if (phase > nsamps ) + while (n--) { + float f = *in++; + if (PD_BIGORSMALL(f)) f = 0; + *bp++ = f; + if (bp == ep) { + vp[0] = ep[-4]; + vp[1] = ep[-3]; + vp[2] = ep[-2]; + vp[3] = ep[-1]; + bp = vp + XTRASAMPS; + phase -= nsamps; + } + } + else testcopyvec_simd(bp, in, n); + c->c_phase = phase; + return w+4; +} +static void sigdelwrite_dsp(t_sigdelwrite *x, t_signal **sp) { + if (sp[0]->n & 7) + dsp_add(sigdelwrite_perform, 3, sp[0]->v, &x->cspace, sp[0]->n); + else if (SIMD_CHECK1(sp[0]->n, sp[0]->v)) + dsp_add(sigdelwrite_perfsimd, 3, sp[0]->v, &x->cspace, sp[0]->n); + else dsp_add(sigdelwrite_perf8, 3, sp[0]->v, &x->cspace, sp[0]->n); + x->sortno = ugen_getsortno(); + sigdelwrite_checkvecsize(x, sp[0]->n); +} +static void sigdelwrite_free(t_sigdelwrite *x) { + pd_unbind(x, x->sym); + freealignedbytes(x->cspace.c_vec, (x->cspace.c_n + XTRASAMPS) * sizeof(float)); +} +static void sigdelwrite_setup() { + sigdelwrite_class = class_new2("delwrite~",sigdelwrite_new,sigdelwrite_free,sizeof(t_sigdelwrite),0,"SF"); + CLASS_MAINSIGNALIN(sigdelwrite_class, t_sigdelwrite, a); + class_addmethod2(sigdelwrite_class, sigdelwrite_dsp,"dsp",""); +} + +/* ----------------------------- delread~ ----------------------------- */ +static t_class *sigdelread_class; +struct t_sigdelread : t_object { + t_symbol *sym; + t_float deltime; /* delay in msec */ + int delsamps; /* delay in samples */ + t_float sr; /* samples per msec */ + t_float n; /* vector size */ + int zerodel; /* 0 or vecsize depending on read/write order */ + void (*copy_fp)(t_float*, const t_float*, int); /* tb: copy function */ +}; +static void sigdelread_float(t_sigdelread *x, t_float f); +static void *sigdelread_new(t_symbol *s, t_floatarg f) { + t_sigdelread *x = (t_sigdelread *)pd_new(sigdelread_class); + x->sym = s; + x->sr = 1; + x->n = 1; + x->zerodel = 0; + sigdelread_float(x, f); + outlet_new(x, &s_signal); + return x; +} +static void sigdelread_float(t_sigdelread *x, t_float f) { + t_sigdelwrite *delwriter = (t_sigdelwrite *)pd_findbyclass(x->sym, sigdelwrite_class); + x->deltime = f; + if (delwriter) { + x->delsamps = (int)(0.5 + x->sr * x->deltime + x->n - x->zerodel); + if (x->delsamps < x->n) x->delsamps = (int)x->n; + else if (x->delsamps > delwriter->cspace.c_n - DEFDELVS) + x->delsamps = (int)(delwriter->cspace.c_n - DEFDELVS); + } + if (SIMD_CHKCNT(x->delsamps)) x->copy_fp = copyvec_simd; + else x->copy_fp = copyvec_simd_unalignedsrc; +} +static t_int *sigdelread_perform(t_int *w) { + t_float *out = (t_float *)w[1]; + t_delwritectl *c = (t_delwritectl *)w[2]; + int delsamps = *(int *)w[3]; + int n = (int)w[4]; + int phase = c->c_phase - delsamps, nsamps = c->c_n; + float *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS); + if (phase < 0) phase += nsamps; + bp = vp + phase; + while (n--) { + *out++ = *bp++; + if (bp == ep) bp -= nsamps; + } + return w+5; +} +static t_int *sigdelread_perf8(t_int *w) { + t_float *out = (t_float *)w[1]; + t_delwritectl *c = (t_delwritectl *)w[2]; + int delsamps = *(int *)w[3]; + int n = (int)w[4]; + int phase = c->c_phase - delsamps, nsamps = c->c_n; + float *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS); + if (phase < 0) phase += nsamps; + bp = vp + phase; + if (phase + n > nsamps) + while (n--) { + *out++ = *bp++; + if (bp == ep) bp -= nsamps; + } + else copyvec_8(out, bp, n); + return w+5; +} +static t_int *sigdelread_perfsimd(t_int *w) { + t_float *out = (t_float *)w[1]; + t_delwritectl *c = (t_delwritectl *)w[2]; + int delsamps = *(int *)w[3]; + int n = (int)w[4]; + t_sigdelread *x = (t_sigdelread *)w[5]; + int phase = c->c_phase - delsamps, nsamps = c->c_n; + float *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS); + if (phase < 0) phase += nsamps; + bp = vp + phase; + if (phase + n > nsamps) + while (n--) { + *out++ = *bp++; + if (bp == ep) bp -= nsamps; + } + else x->copy_fp(out, bp, n); + return w+6; +} +static void sigdelread_dsp(t_sigdelread *x, t_signal **sp) { + t_sigdelwrite *delwriter = + (t_sigdelwrite *)pd_findbyclass(x->sym, sigdelwrite_class); + x->sr = sp[0]->sr * 0.001; + x->n = sp[0]->n; + if (delwriter) { + sigdelwrite_checkvecsize(delwriter, sp[0]->n); + x->zerodel = (delwriter->sortno == ugen_getsortno() ? + 0 : delwriter->vecsize); + sigdelread_float(x, x->deltime); + if (sp[0]->n & 7) + dsp_add(sigdelread_perform, 4, sp[0]->v, &delwriter->cspace, &x->delsamps, sp[0]->n); + else if (SIMD_CHECK1(sp[0]->n, sp[0]->v)) + dsp_add(sigdelread_perfsimd, 5, sp[0]->v, &delwriter->cspace, &x->delsamps, sp[0]->n, x); + else dsp_add(sigdelread_perf8, 4, sp[0]->v, &delwriter->cspace, &x->delsamps, sp[0]->n); + } else if (*x->sym->name) error("delread~: %s: no such delwrite~",x->sym->name); +} +static void sigdelread_setup() { + sigdelread_class = class_new2("delread~",sigdelread_new,0,sizeof(t_sigdelread),0,"SF"); + class_addmethod2(sigdelread_class, sigdelread_dsp,"dsp",""); + class_addfloat(sigdelread_class, sigdelread_float); +} + +/* ----------------------------- vd~ ----------------------------- */ +static t_class *sigvd_class; +struct t_sigvd : t_object { + t_symbol *sym; + t_float sr; /* samples per msec */ + int zerodel; /* 0 or vecsize depending on read/write order */ + float a; +}; +static void *sigvd_new(t_symbol *s) { + t_sigvd *x = (t_sigvd *)pd_new(sigvd_class); + if (!*s->name) s = gensym("vd~"); + x->sym = s; + x->sr = 1; + x->zerodel = 0; + outlet_new(x, &s_signal); + x->a = 0; + return x; +} +static t_int *sigvd_perform(t_int *w) { + t_float *in = (t_float *)w[1]; + t_float *out = (t_float *)w[2]; + t_delwritectl *ctl = (t_delwritectl *)w[3]; + t_sigvd *x = (t_sigvd *)w[4]; + int n = (int)w[5]; + + int nsamps = ctl->c_n; + float limit = nsamps - n - 1; + float fn = n-1; + float *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase; + float zerodel = x->zerodel; + while (n--) { + float delsamps = x->sr * *in++ - zerodel, frac; + int idelsamps; + float a, b, c, d, cminusb; + if (delsamps < 1.00001f) delsamps = 1.00001f; + if (delsamps > limit) delsamps = limit; + delsamps += fn; + fn = fn - 1.0f; + idelsamps = (int)delsamps; + frac = delsamps - (float)idelsamps; + bp = wp - idelsamps; + if (bp < vp + 4) bp += nsamps; + d = bp[-3]; + c = bp[-2]; + b = bp[-1]; + a = bp[0]; + cminusb = c-b; + *out++ = b + frac * ( + cminusb - 0.1666667f * (1.-frac) * ( + (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b) + ) + ); + } + return w+6; +} +static void sigvd_dsp(t_sigvd *x, t_signal **sp) { + t_sigdelwrite *delwriter = (t_sigdelwrite *)pd_findbyclass(x->sym, sigdelwrite_class); + x->sr = sp[0]->sr * 0.001; + if (delwriter) { + sigdelwrite_checkvecsize(delwriter, sp[0]->n); + x->zerodel = (delwriter->sortno == ugen_getsortno() ? 0 : delwriter->vecsize); + dsp_add(sigvd_perform, 5, sp[0]->v, sp[1]->v, &delwriter->cspace, x, sp[0]->n); + } else error("vd~: %s: no such delwrite~",x->sym->name); +} +static void sigvd_setup() { + sigvd_class = class_new2("vd~",sigvd_new,0,sizeof(t_sigvd),0,"S"); + class_addmethod2(sigvd_class, sigvd_dsp, "dsp",""); + CLASS_MAINSIGNALIN(sigvd_class, t_sigvd, a); +} + +#ifndef HAVE_LIBFFTW3F +/* ------------------------ fft~ and ifft~ -------------------------------- */ +/* ----------------------- rfft~ -------------------------------- */ +/* ----------------------- rifft~ -------------------------------- */ +static t_class *sigfft_class; struct t_sigfft : t_object {float a;}; +static t_class *sigifft_class; struct t_sigifft : t_object {float a;}; +static t_class *sigrfft_class; struct t_sigrfft : t_object {float a;}; +static t_class *sigrifft_class; struct t_sigrifft : t_object {float a;}; + +static void *sigfft_new() { + t_sigfft *x = (t_sigfft *)pd_new(sigfft_class); + outlet_new(x, &s_signal); + outlet_new(x, &s_signal); + inlet_new(x, x, &s_signal, &s_signal); x->a=0; return x;} +static void *sigifft_new() { + t_sigifft *x = (t_sigifft *)pd_new(sigifft_class); + outlet_new(x, &s_signal); + outlet_new(x, &s_signal); + inlet_new(x, x, &s_signal, &s_signal); x->a=0; return x;} +static void *sigrfft_new() { + t_sigrfft *x = (t_sigrfft *)pd_new(sigrfft_class); + outlet_new(x, &s_signal); + outlet_new(x, &s_signal); + x->a = 0; return x;} +static void *sigrifft_new() { + t_sigrifft *x = (t_sigrifft *)pd_new(sigrifft_class); + inlet_new(x, x, &s_signal, &s_signal); + outlet_new(x, &s_signal); + x->a = 0; return x;} + +static t_int *sigfft_swap(t_int *w) { + float *in1 = (t_float *)w[1]; + float *in2 = (t_float *)w[2]; + int n = w[3]; + for (;n--; in1++, in2++) { + float f = *in1; + *in1 = *in2; + *in2 = f; + } + return w+4; +} +static t_int * sigfft_perform(t_int *w) {float *in1=(t_float *)w[1], *in2=(t_float *)w[2]; int n=w[3]; mayer_fft(n,in1,in2); return w+4;} +static t_int * sigifft_perform(t_int *w) {float *in1=(t_float *)w[1], *in2=(t_float *)w[2]; int n=w[3]; mayer_ifft(n,in1,in2); return w+4;} +static t_int * sigrfft_perform(t_int *w) {float *in =(t_float *)w[1]; int n = w[2]; mayer_realfft(n, in); return w+3;} +static t_int *sigrifft_perform(t_int *w) {float *in =(t_float *)w[1]; int n = w[2]; mayer_realifft(n, in); return w+3;} + +static void sigfft_dspx(t_sigfft *x, t_signal **sp, t_int *(*f)(t_int *w)) { + int n = sp[0]->n; + float *in1 = sp[0]->v; + float *in2 = sp[1]->v; + float *out1 = sp[2]->v; + float *out2 = sp[3]->v; + if (out1 == in2 && out2 == in1) + dsp_add(sigfft_swap, 3, out1, out2, n); + else if (out1 == in2) { + dsp_add(copy_perform, 3, in2, out2, n); + dsp_add(copy_perform, 3, in1, out1, n); + } else { + if (out1 != in1) dsp_add(copy_perform, 3, in1, out1, n); + if (out2 != in2) dsp_add(copy_perform, 3, in2, out2, n); + } + dsp_add(f, 3, sp[2]->v, sp[3]->v, n); +} +static void sigfft_dsp(t_sigfft *x, t_signal **sp) {sigfft_dspx(x, sp, sigfft_perform);} +static void sigifft_dsp(t_sigfft *x, t_signal **sp) {sigfft_dspx(x, sp, sigifft_perform);} + +static t_int *sigrfft_flip(t_int *w) { + float *in = (t_float *)w[1]; + float *out = (t_float *)w[2]; + int n = w[3]; + while (n--) *(--out) = *in++; + *(--out) = 0; /* to hell with it */ + return w+4; +} +static void sigrfft_dsp(t_sigrfft *x, t_signal **sp) { + int n = sp[0]->n, n2 = (n>>1); + float *in1 = sp[0]->v; + float *out1 = sp[1]->v; + float *out2 = sp[2]->v; + if (n < 4) { + error("fft: minimum 4 points"); + return; + } + /* this probably never happens */ + if (in1 == out2) { + dsp_add(sigrfft_perform, 2, out2, n); + dsp_add(copy_perform, 3, out2, out1, n2); + dsp_add(sigrfft_flip, 3, out2 + (n2+1), out2 + n2, n2-1); + } else { + if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n); + dsp_add(sigrfft_perform, 2, out1, n); + dsp_add(sigrfft_flip, 3, out1 + (n2+1), out2 + n2, n2-1); + } + dsp_add_zero(out1 + n2, n2); + dsp_add_zero(out2 + n2, n2); +} + +static void sigrifft_dsp(t_sigrifft *x, t_signal **sp) { + int n = sp[0]->n, n2 = (n>>1); + float *in1 = sp[0]->v; + float *in2 = sp[1]->v; + float *out1 = sp[2]->v; + if (n < 4) {error("fft: minimum 4 points"); return;} + if (in2 == out1) { + dsp_add(sigrfft_flip, 3, out1+1, out1 + n, (n2-1)); + dsp_add(copy_perform, 3, in1, out1, n2); + } else { + if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n2); + dsp_add(sigrfft_flip, 3, in2+1, out1 + n, n2-1); + } + dsp_add(sigrifft_perform, 2, out1, n); +} +static void sigfft_setup() { + sigfft_class = class_new2("fft~", sigfft_new, 0,sizeof(t_sigfft), 0,""); + sigifft_class = class_new2("ifft~", sigifft_new, 0,sizeof(t_sigfft), 0,""); + sigrfft_class = class_new2("rfft~", sigrfft_new, 0,sizeof(t_sigrfft), 0,""); + sigrifft_class = class_new2("rifft~",sigrifft_new,0,sizeof(t_sigrifft),0,""); + CLASS_MAINSIGNALIN(sigfft_class, t_sigfft, a); + CLASS_MAINSIGNALIN(sigifft_class, t_sigfft, a); + CLASS_MAINSIGNALIN(sigrfft_class, t_sigrfft, a); + CLASS_MAINSIGNALIN(sigrifft_class,t_sigrifft,a); + class_addmethod2(sigfft_class, sigfft_dsp, "dsp",""); + class_addmethod2(sigifft_class, sigifft_dsp, "dsp",""); + class_addmethod2(sigrfft_class, sigrfft_dsp, "dsp",""); + class_addmethod2(sigrifft_class,sigrifft_dsp,"dsp",""); + class_sethelpsymbol(sigifft_class, gensym("fft~")); + class_sethelpsymbol(sigrfft_class, gensym("fft~")); + class_sethelpsymbol(sigrifft_class,gensym("fft~")); +} + +#else +/* Support for fftw3 by Tim Blechmann */ +/* ------------------------ fft~ and ifft~ -------------------------------- */ +/* ----------------------- rfft~ --------------------------------- */ +/* ----------------------- rifft~ -------------------------------- */ + +static t_class *sigfftw_class; struct t_sigfftw : t_object {float a; fftwf_plan plan; fftwf_iodim dim;}; +static t_class *sigifftw_class; struct t_sigifftw : t_object {float a; fftwf_plan plan; fftwf_iodim dim;}; +static t_class *sigrfftw_class; struct t_sigrfftw : t_object {float a; fftwf_plan plan; fftwf_iodim dim;}; +static t_class *sigrifftw_class;struct t_sigrifftw : t_object {float a; fftwf_plan plan; fftwf_iodim dim;}; + +static void *sigfftw_new() { + t_sigfftw *x = (t_sigfftw *)pd_new(sigfftw_class); outlet_new(x, &s_signal); outlet_new(x, &s_signal); + inlet_new(x, x, &s_signal, &s_signal); x->a=0; return x;} +static void *sigifftw_new() { + t_sigifftw *x = (t_sigifftw *)pd_new(sigfftw_class); outlet_new(x, &s_signal); outlet_new(x, &s_signal); + inlet_new(x, x, &s_signal, &s_signal); x->a=0; return x;} +static void *sigrfftw_new() { + t_sigrfftw *x = (t_sigrfftw *)pd_new(sigrfftw_class); + outlet_new(x, &s_signal); outlet_new(x, &s_signal); x->a=0; return x;} +static void *sigrifftw_new() { + t_sigrifftw *x = (t_sigrifftw *)pd_new(sigrifftw_class); + inlet_new(x, x, &s_signal, &s_signal); + outlet_new(x, &s_signal); x->a=0; return x;} + +static void sigfftw_free( t_sigfftw *x) {fftwf_destroy_plan(x->plan);} +static void sigifftw_free( t_sigifftw *x) {fftwf_destroy_plan(x->plan);} +static void sigrfftw_free( t_sigrfftw *x) {fftwf_destroy_plan(x->plan);} +static void sigrifftw_free(t_sigrifftw *x) {fftwf_destroy_plan(x->plan);} + +/* for compatibility reasons with the mayer fft, we'll have to invert some samples. this is ugly, but someone might rely on that. */ +static void sigrfftw_invert(t_sample * s, t_int n) { + while (n!=0) {--n; s[n]=-s[n];} +} +static t_int *sigfftw_perform(t_int *w) { + fftwf_execute(*(fftwf_plan *)w[1]); + return w+2; +} +static t_int *sigrfftw_perform(t_int *w) { + fftwf_execute(*(fftwf_plan*)w[1]); + sigrfftw_invert((t_sample*)w[2],(t_int)w[3]); + return w+4; +} +static t_int *sigrifftw_perform(t_int *w) { + sigrfftw_invert((t_sample *)w[2],w[3]); + fftwf_execute(*(fftwf_plan*)w[1]); + return w+4; +} + +static void sigfftw_dsp(t_sigfftw *x, t_signal **sp) { + int n = sp[0]->n; + float *in1 = sp[0]->v; + float *in2 = sp[1]->v; + float *out1 = sp[2]->v; + float *out2 = sp[3]->v; + x->dim.n=n; + x->dim.is=1; + x->dim.os=1; + x->plan = fftwf_plan_guru_split_dft(1, &(x->dim), 0, NULL, in1, in2, out1, out2, FFTW_ESTIMATE); + dsp_add(sigfftw_perform, 1, &x->plan); +} +static void sigifftw_dsp(t_sigfftw *x, t_signal **sp) { + int n = sp[0]->n; + float *in1 = sp[0]->v; + float *in2 = sp[1]->v; + float *out1 = sp[2]->v; + float *out2 = sp[3]->v; + x->dim.n=n; + x->dim.is=1; + x->dim.os=1; + x->plan = fftwf_plan_guru_split_dft(1, &(x->dim), 0, NULL, in2, in1, out2, out1, FFTW_ESTIMATE); + dsp_add(sigfftw_perform, 1, &x->plan); +} + +static void sigrfftw_dsp(t_sigrfftw *x, t_signal **sp) { + int n = sp[0]->n, n2 = (n>>1); + float *in = sp[0]->v; + float *out1 = sp[1]->v; + float *out2 = sp[2]->v; + if (n < 4) {error("fft: minimum 4 points"); return;} + x->dim.n=n; + x->dim.is=1; + x->dim.os=1; + x->plan = fftwf_plan_guru_split_dft_r2c(1, &(x->dim), 0, NULL, in, out1, out2, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); + dsp_add(sigrfftw_perform,3,&x->plan,out2+1,n2-1); + dsp_add_zero(out1 + n2, n2); + dsp_add_zero(out2 + n2, n2); +} + +static void sigrifftw_dsp(t_sigrifftw *x, t_signal **sp) { + int n = sp[0]->n, n2 = (n>>1); + float *in1 = sp[0]->v; + float *in2 = sp[1]->v; + float *out = sp[2]->v; + if (n < 4) {error("fft: minimum 4 points"); return;} + x->dim.n=n; + x->dim.is=1; + x->dim.os=1; + x->plan = fftwf_plan_guru_split_dft_c2r(1, &(x->dim), 0, NULL, in1, in2, out, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT); + dsp_add_zero(in1+ n/2, n/2); + dsp_add(sigrifftw_perform,3,&x->plan,in2,n2); +} +static void sigfftw_setup() { + sigfftw_class = class_new2( "fft~",sigfftw_new, sigfftw_free, sizeof(t_sigfftw), 0,""); + sigifftw_class = class_new2( "ifft~",sigifftw_new, sigifftw_free, sizeof(t_sigfftw), 0,""); + sigrfftw_class = class_new2( "rfft~",sigrfftw_new, sigrfftw_free, sizeof(t_sigrfftw), 0,""); + sigrifftw_class = class_new2("rifft~",sigrifftw_new,sigrifftw_free,sizeof(t_sigrifftw),0,""); + CLASS_MAINSIGNALIN(sigfftw_class, t_sigfftw, a); + CLASS_MAINSIGNALIN(sigifftw_class, t_sigfftw, a); + CLASS_MAINSIGNALIN(sigrfftw_class, t_sigrfftw, a); + CLASS_MAINSIGNALIN(sigrifftw_class,t_sigrifftw,a); + class_addmethod2(sigfftw_class, sigfftw_dsp, "dsp",""); + class_addmethod2(sigifftw_class, sigifftw_dsp, "dsp",""); + class_addmethod2(sigrfftw_class, sigrfftw_dsp, "dsp",""); + class_addmethod2(sigrifftw_class, sigrifftw_dsp,"dsp",""); + class_sethelpsymbol(sigifftw_class, gensym("fft~")); + class_sethelpsymbol(sigrfftw_class, gensym("fft~")); + class_sethelpsymbol(sigrifftw_class,gensym("fft~")); +} +#endif /* HAVE_LIBFFTW3F */ +/* end of FFTW support */ + +/* ----------------------- framp~ -------------------------------- */ +static t_class *sigframp_class; +struct t_sigframp : t_object { + float a; +}; +static void *sigframp_new() { + t_sigframp *x = (t_sigframp *)pd_new(sigframp_class); + inlet_new(x, x, &s_signal, &s_signal); + outlet_new(x, &s_signal); + outlet_new(x, &s_signal); + x->a = 0; + return x; +} +static t_int *sigframp_perform(t_int *w) { + float *inreal = (t_float *)w[1]; + float *inimag = (t_float *)w[2]; + float *outfreq = (t_float *)w[3]; + float *outamp = (t_float *)w[4]; + float lastreal = 0, currentreal = inreal[0], nextreal = inreal[1]; + float lastimag = 0, currentimag = inimag[0], nextimag = inimag[1]; + int n = w[5]; + int m = n + 1; + float fbin = 1, oneovern2 = 1.f/((float)n * (float)n); + inreal += 2; + inimag += 2; + *outamp++ = *outfreq++ = 0; + n -= 2; + while (n--) { + float re, im, pow, freq; + lastreal = currentreal; + currentreal = nextreal; + nextreal = *inreal++; + lastimag = currentimag; + currentimag = nextimag; + nextimag = *inimag++; + re = currentreal - 0.5f * (lastreal + nextreal); + im = currentimag - 0.5f * (lastimag + nextimag); + pow = re * re + im * im; + if (pow > 1e-19) { + float detune = ((lastreal - nextreal) * re + + (lastimag - nextimag) * im) / (2.0f * pow); + if (detune > 2 || detune < -2) freq = pow = 0; + else freq = fbin + detune; + } + else freq = pow = 0; + *outfreq++ = freq; + *outamp++ = oneovern2 * pow; + fbin += 1.0f; + } + while (m--) *outamp++ = *outfreq++ = 0; + return w+6; +} +t_int *sigsqrt_perform(t_int *w); +static void sigframp_dsp(t_sigframp *x, t_signal **sp) { + int n = sp[0]->n, n2 = (n>>1); + if (n < 4) { + error("framp: minimum 4 points"); + return; + } + dsp_add(sigframp_perform, 5, sp[0]->v, sp[1]->v, + sp[2]->v, sp[3]->v, n2); + dsp_add(sigsqrt_perform, 3, sp[3]->v, sp[3]->v, n2); +} +static void sigframp_setup() { + sigframp_class = class_new2("framp~",sigframp_new,0,sizeof(t_sigframp),0,""); + CLASS_MAINSIGNALIN(sigframp_class, t_sigframp, a); + class_addmethod2(sigframp_class, sigframp_dsp, "dsp",""); +} + +/* ---------------- hip~ - 1-pole 1-zero hipass filter. ----------------- */ +/* ---------------- lop~ - 1-pole lopass filter. ----------------- */ +t_class *sighip_class; struct t_hipctl {float x; float coef;}; +t_class *siglop_class; struct t_lopctl {float x; float coef;}; +struct t_sighip : t_object {float sr; float hz; t_hipctl cspace; t_hipctl *ctl; float a;}; +struct t_siglop : t_object {float sr; float hz; t_lopctl cspace; t_lopctl *ctl; float a;}; + +static void sighip_ft1(t_sighip *x, t_floatarg f) {x->hz = max(f,0.f); x->ctl->coef = clip(1-f*(2*3.14159)/x->sr,0.,1.);} +static void siglop_ft1(t_siglop *x, t_floatarg f) {x->hz = max(f,0.f); x->ctl->coef = clip( f*(2*3.14159)/x->sr,0.,1.);} + +static void *sighip_new(t_floatarg f) { + t_sighip *x = (t_sighip *)pd_new(sighip_class); + inlet_new(x, x, &s_float, gensym("ft1")); outlet_new(x, &s_signal); + x->sr = 44100; x->ctl = &x->cspace; x->cspace.x = 0; sighip_ft1(x, f); x->a = 0; return x;} +static void *siglop_new(t_floatarg f) { + t_siglop *x = (t_siglop *)pd_new(siglop_class); + inlet_new(x, x, &s_float, gensym("ft1")); outlet_new(x, &s_signal); + x->sr = 44100; x->ctl = &x->cspace; x->cspace.x = 0; siglop_ft1(x, f); x->a = 0; return x;} + +static void sighip_clear(t_sighip *x, t_floatarg q) {x->cspace.x = 0;} +static void siglop_clear(t_siglop *x, t_floatarg q) {x->cspace.x = 0;} + +static t_int *sighip_perform(t_int *w) { + float *in = (float *)w[1]; + float *out = (float *)w[2]; + t_hipctl *c = (t_hipctl *)w[3]; + int n = (t_int)w[4]; + float last = c->x; + float coef = c->coef; + if (coef < 1) { + for (int i = 0; i < n; i++) { + float noo = *in++ + coef * last; + *out++ = noo - last; + last = noo; + } + if (PD_BIGORSMALL(last)) last = 0; + c->x = last; + } else { + for (int i = 0; i < n; i++) *out++ = *in++; + c->x = 0; + } + return w+5; +} +static t_int *siglop_perform(t_int *w) { + float *in = (float *)w[1]; + float *out = (float *)w[2]; + t_lopctl *c = (t_lopctl *)w[3]; + int n = (t_int)w[4]; + float last = c->x; + float coef = c->coef; + float feedback = 1 - coef; + for (int i = 0; i < n; i++) last = *out++ = coef * *in++ + feedback * last; + if (PD_BIGORSMALL(last)) last = 0; + c->x = last; + return w+5; +} +static void sighip_dsp(t_sighip *x, t_signal **sp) { + x->sr = sp[0]->sr; sighip_ft1(x, x->hz); + dsp_add(sighip_perform, 4, sp[0]->v, sp[1]->v, x->ctl, sp[0]->n);} +static void siglop_dsp(t_siglop *x, t_signal **sp) { + x->sr = sp[0]->sr; siglop_ft1(x, x->hz); + dsp_add(siglop_perform, 4, sp[0]->v, sp[1]->v, x->ctl, sp[0]->n);} + +void sighip_setup() { + sighip_class = class_new2("hip~",sighip_new,0,sizeof(t_sighip),0,"F"); + CLASS_MAINSIGNALIN(sighip_class, t_sighip, a); + class_addmethod2(sighip_class, sighip_dsp, "dsp",""); + class_addmethod2(sighip_class, sighip_ft1, "ft1","f"); + class_addmethod2(sighip_class, sighip_clear,"clear",""); +} +void siglop_setup() { + siglop_class = class_new2("lop~",siglop_new,0,sizeof(t_siglop),0,"F"); + CLASS_MAINSIGNALIN(siglop_class, t_siglop, a); + class_addmethod2(siglop_class, siglop_dsp, "dsp",""); + class_addmethod2(siglop_class, siglop_ft1, "ft1","f"); + class_addmethod2(siglop_class, siglop_clear, "clear",""); +} + +/* ---------------- bp~ - 2-pole bandpass filter. ----------------- */ +struct t_bpctl { + float x1; + float x2; + float coef1; + float coef2; + float gain; +}; +struct t_sigbp : t_object { + float sr; + float freq; + float q; + t_bpctl cspace; + t_bpctl *ctl; + float a; +}; +t_class *sigbp_class; +static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q); +static void *sigbp_new(t_floatarg f, t_floatarg q) { + t_sigbp *x = (t_sigbp *)pd_new(sigbp_class); + inlet_new(x, x, &s_float, gensym("ft1")); + inlet_new(x, x, &s_float, gensym("ft2")); + outlet_new(x, &s_signal); + x->sr = 44100; + x->ctl = &x->cspace; + x->cspace.x1 = 0; + x->cspace.x2 = 0; + sigbp_docoef(x, f, q); + x->a = 0; + return x; +} +static float sigbp_qcos(float f) { + if (f >= -(0.5f*3.14159f) && f <= 0.5f*3.14159f) { + float g = f*f; + return ((g*g*g * (-1.0f/720.0f) + g*g*(1.0f/24.0f)) - g*0.5) + 1; + } else return 0; +} +static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q) { + float r, oneminusr, omega; + if (f < 0.001) f = 10; + if (q < 0) q = 0; + x->freq = f; + x->q = q; + omega = f * (2.0f * 3.14159f) / x->sr; + if (q < 0.001) oneminusr = 1.0f; + else oneminusr = omega/q; + if (oneminusr > 1.0f) oneminusr = 1.0f; + r = 1.0f - oneminusr; + x->ctl->coef1 = 2.0f * sigbp_qcos(omega) * r; + x->ctl->coef2 = - r * r; + x->ctl->gain = 2 * oneminusr * (oneminusr + r * omega); + /* post("r %f, omega %f, coef1 %f, coef2 %f", r, omega, x->ctl->coef1, x->ctl->coef2); */ +} +static void sigbp_ft1(t_sigbp *x, t_floatarg f) {sigbp_docoef(x, f, x->q);} +static void sigbp_ft2(t_sigbp *x, t_floatarg q) {sigbp_docoef(x, x->freq, q);} +static void sigbp_clear(t_sigbp *x, t_floatarg q) {x->ctl->x1 = x->ctl->x2 = 0;} +static t_int *sigbp_perform(t_int *w) { + float *in = (float *)w[1]; + float *out = (float *)w[2]; + t_bpctl *c = (t_bpctl *)w[3]; + int n = (t_int)w[4]; + float last = c->x1; + float prev = c->x2; + float coef1 = c->coef1; + float coef2 = c->coef2; + float gain = c->gain; + for (int i = 0; i < n; i++) { + float output = *in++ + coef1 * last + coef2 * prev; + *out++ = gain * output; + prev = last; + last = output; + } + if (PD_BIGORSMALL(last)) last = 0; + if (PD_BIGORSMALL(prev)) prev = 0; + c->x1 = last; + c->x2 = prev; + return w+5; +} +static void sigbp_dsp(t_sigbp *x, t_signal **sp) { + x->sr = sp[0]->sr; + sigbp_docoef(x, x->freq, x->q); + dsp_add(sigbp_perform, 4, sp[0]->v, sp[1]->v, x->ctl, sp[0]->n); + +} +void sigbp_setup() { + sigbp_class = class_new2("bp~",sigbp_new,0,sizeof(t_sigbp),0,"FF"); + CLASS_MAINSIGNALIN(sigbp_class, t_sigbp, a); + class_addmethod2(sigbp_class, sigbp_dsp, "dsp",""); + class_addmethod2(sigbp_class, sigbp_ft1, "ft1","f"); + class_addmethod2(sigbp_class, sigbp_ft2, "ft2","f"); + class_addmethod2(sigbp_class, sigbp_clear, "clear",""); +} + +/* ---------------- biquad~ - raw biquad filter ----------------- */ +struct t_biquadctl { + float x1; + float x2; + float fb1; + float fb2; + float ff1; + float ff2; + float ff3; +}; +struct t_sigbiquad : t_object { + float a; + t_biquadctl cspace; + t_biquadctl *ctl; +}; +t_class *sigbiquad_class; +static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv); +static void *sigbiquad_new(t_symbol *s, int argc, t_atom *argv) { + t_sigbiquad *x = (t_sigbiquad *)pd_new(sigbiquad_class); + outlet_new(x, &s_signal); + x->ctl = &x->cspace; + x->cspace.x1 = x->cspace.x2 = 0; + sigbiquad_list(x, s, argc, argv); + x->a = 0; + return x; +} +static t_int *sigbiquad_perform(t_int *w) { + float *in = (float *)w[1]; + float *out = (float *)w[2]; + t_biquadctl *c = (t_biquadctl *)w[3]; + int n = (t_int)w[4]; + float last = c->x1; + float prev = c->x2; + float fb1 = c->fb1; + float fb2 = c->fb2; + float ff1 = c->ff1; + float ff2 = c->ff2; + float ff3 = c->ff3; + for (int i = 0; i < n; i++) { + float output = *in++ + fb1 * last + fb2 * prev; + if (PD_BIGORSMALL(output)) output = 0; + *out++ = ff1 * output + ff2 * last + ff3 * prev; + prev = last; + last = output; + } + c->x1 = last; + c->x2 = prev; + return w+5; +} +/* tb: some loop unrolling & do some relaxed denormal bashing */ +/* (denormal bashing = non-Pentium4 penalised for Pentium4's failings) */ +static t_int *sigbiquad_perf8(t_int *w) { + float *in = (float *)w[1]; + float *out = (float *)w[2]; + t_biquadctl *c = (t_biquadctl *)w[3]; + int n = (t_int)w[4]>>3; + float last = c->x1; + float prev = c->x2; + float fb1 = c->fb1; + float fb2 = c->fb2; + float ff1 = c->ff1; + float ff2 = c->ff2; + float ff3 = c->ff3; + for (int i = 0; i < n; i++) { + float output = *in++ + fb1*last + fb2*prev; + if (PD_BIGORSMALL(output)) output = 0; + *out++ = ff1 * output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev; + if (PD_BIGORSMALL(output)) output = 0; + *out++ = ff1 * output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev; + *out++ = ff1 * output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev; + *out++ = ff1 * output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev; + output += 1e-10; + output -= 1e-10; + *out++ = ff1*output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev; + *out++ = ff1*output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev; + *out++ = ff1*output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev; + *out++ = ff1*output + ff2*last + ff3*prev; prev=last; last=output; + } + c->x1 = last; + c->x2 = prev; + return w+5; +} +static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv) { + float fb1 = atom_getfloatarg(0, argc, argv); + float fb2 = atom_getfloatarg(1, argc, argv); + float ff1 = atom_getfloatarg(2, argc, argv); + float ff2 = atom_getfloatarg(3, argc, argv); + float ff3 = atom_getfloatarg(4, argc, argv); + float discriminant = fb1 * fb1 + 4 * fb2; + t_biquadctl *c = x->ctl; + /* imaginary roots -- resonant filter */ + if (discriminant < 0) { + /* they're conjugates so we just check that the product is less than one */ + if (fb2 >= -1.0f) goto stable; + } else { /* real roots */ + /* check that the parabola 1 - fb1 x - fb2 x^2 has a + vertex between -1 and 1, and that it's nonnegative + at both ends, which implies both roots are in [1-,1]. */ + if (fb1 <= 2.0f && fb1 >= -2.0f && 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0) goto stable; + } + /* if unstable, just bash to zero */ + fb1 = fb2 = ff1 = ff2 = ff3 = 0; +stable: + c->fb1 = fb1; + c->fb2 = fb2; + c->ff1 = ff1; + c->ff2 = ff2; + c->ff3 = ff3; +} +static void sigbiquad_set(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv) { + t_biquadctl *c = x->ctl; + c->x1 = atom_getfloatarg(0, argc, argv); + c->x2 = atom_getfloatarg(1, argc, argv); +} +static void sigbiquad_dsp(t_sigbiquad *x, t_signal **sp) { + const int n = sp[0]->n; + if (n&7) dsp_add(sigbiquad_perform, 4, sp[0]->v, sp[1]->v, x->ctl, sp[0]->n); + else dsp_add(sigbiquad_perf8, 4, sp[0]->v, sp[1]->v, x->ctl, sp[0]->n); +} +void sigbiquad_setup() { + sigbiquad_class = class_new2("biquad~",sigbiquad_new,0,sizeof(t_sigbiquad),0,"*"); + CLASS_MAINSIGNALIN(sigbiquad_class, t_sigbiquad, a); + class_addmethod2(sigbiquad_class, sigbiquad_dsp, "dsp",""); + class_addlist(sigbiquad_class, sigbiquad_list); + class_addmethod2(sigbiquad_class, sigbiquad_set, "set","*"); + class_addmethod2(sigbiquad_class, sigbiquad_set, "clear","*"); +} + +/* ---------------- samphold~ - sample and hold ----------------- */ +struct t_sigsamphold : t_object { + float a; + float lastin; + float lastout; +}; +t_class *sigsamphold_class; +static void *sigsamphold_new() { + t_sigsamphold *x = (t_sigsamphold *)pd_new(sigsamphold_class); + inlet_new(x, x, &s_signal, &s_signal); + outlet_new(x, &s_signal); + x->lastin = 0; + x->lastout = 0; + x->a = 0; + return x; +} +static t_int *sigsamphold_perform(t_int *w) { + float *in1 = (float *)w[1]; + float *in2 = (float *)w[2]; + float *out = (float *)w[3]; + t_sigsamphold *x = (t_sigsamphold *)w[4]; + int n = (t_int)w[5]; + float lastin = x->lastin; + float lastout = x->lastout; + for (int i = 0; i < n; i++, *in1++) { + float next = *in2++; + if (next < lastin) lastout = *in1; + *out++ = lastout; + lastin = next; + } + x->lastin = lastin; + x->lastout = lastout; + return w+6; +} +static void sigsamphold_dsp(t_sigsamphold *x, t_signal **sp) { + dsp_add(sigsamphold_perform, 5, sp[0]->v, sp[1]->v, sp[2]->v, x, sp[0]->n); +} +static void sigsamphold_reset(t_sigsamphold *x, t_symbol *s, int argc, t_atom *argv) { + x->lastin = ((argc > 0 && (argv[0].a_type == A_FLOAT)) ? argv[0].a_w.w_float : 1e20); +} +static void sigsamphold_set(t_sigsamphold *x, t_float f) { + x->lastout = f; +} +void sigsamphold_setup() { + sigsamphold_class = class_new2("samphold~",sigsamphold_new,0,sizeof(t_sigsamphold),0,""); + CLASS_MAINSIGNALIN(sigsamphold_class, t_sigsamphold, a); + class_addmethod2(sigsamphold_class, sigsamphold_set, "set","F"); + class_addmethod2(sigsamphold_class, sigsamphold_reset, "reset","*"); + class_addmethod2(sigsamphold_class, sigsamphold_dsp, "dsp",""); +} + +/* ---------------- rpole~ - real one-pole filter (raw) ----------------- */ +/* ---------------- rzero~ - real one-zero filter (raw) ----------------- */ +/* --- rzero_rev~ - real, reverse one-zero filter (raw) ----------------- */ +t_class *sigrpole_class; struct t_sigrpole : t_object {float a; float last;}; +t_class *sigrzero_class; struct t_sigrzero : t_object {float a; float last;}; +t_class *sigrzrev_class; struct t_sigrzrev : t_object {float a; float last;}; + +static void *sigrpole_new(t_float f) { + t_sigrpole *x = (t_sigrpole *)pd_new(sigrpole_class); + pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), f); outlet_new(x, &s_signal); x->last=0; return x;} +static void *sigrzero_new(t_float f) { + t_sigrzero *x = (t_sigrzero *)pd_new(sigrzero_class); + pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), f); outlet_new(x, &s_signal); x->last=0; return x;} +static void *sigrzrev_new(t_float f) { + t_sigrzrev *x = (t_sigrzrev *)pd_new(sigrzrev_class); + pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), f); outlet_new(x, &s_signal); x->last=0; return x;} + +static t_int *sigrpole_perform(t_int *w) { + float *in1 = (float *)w[1]; float *in2 = (float *)w[2]; float *out = (float *)w[3]; + t_sigrpole *x = (t_sigrpole *)w[4]; int n = (t_int)w[5]; float last = x->last; + for (int i=0; ilast = last; + return w+6; +} +static t_int *sigrzero_perform(t_int *w) { + float *in1 = (float *)w[1]; float *in2 = (float *)w[2]; float *out = (float *)w[3]; + t_sigrzero *x = (t_sigrzero *)w[4]; int n = (t_int)w[5]; float last = x->last; + for (int i = 0; i < n; i++) { + float next = *in1++, coef = *in2++; + *out++ = next - coef*last; + last = next; + } + x->last = last; + return w+6; +} +static t_int *sigrzrev_perform(t_int *w) { + float *in1 = (float *)w[1]; float *in2 = (float *)w[2]; float *out = (float *)w[3]; + t_sigrzrev *x = (t_sigrzrev *)w[4]; int n = (t_int)w[5]; float last = x->last; + for (int i = 0; i < n; i++) { + float next = *in1++, coef = *in2++; + *out++ = last - coef*next; + last = next; + } + x->last = last; + return w+6; +} + +static void sigrpole_dsp(t_sigrpole *x, t_signal **sp) {dsp_add(sigrpole_perform, 5, sp[0]->v, sp[1]->v, sp[2]->v, x, sp[0]->n);} +static void sigrzero_dsp(t_sigrzero *x, t_signal **sp) {dsp_add(sigrzero_perform, 5, sp[0]->v, sp[1]->v, sp[2]->v, x, sp[0]->n);} +static void sigrzrev_dsp(t_sigrzrev *x, t_signal **sp) {dsp_add(sigrzrev_perform, 5, sp[0]->v, sp[1]->v, sp[2]->v, x, sp[0]->n);} +static void sigrpole_clear(t_sigrpole *x) {x->last = 0;} +static void sigrzero_clear(t_sigrzero *x) {x->last = 0;} +static void sigrzrev_clear(t_sigrzrev *x) {x->last = 0;} +static void sigrpole_set(t_sigrpole *x, t_float f) {x->last = f;} +static void sigrzero_set(t_sigrzero *x, t_float f) {x->last = f;} +static void sigrzrev_set(t_sigrzrev *x, t_float f) {x->last = f;} +void sigr_setup() { + sigrpole_class = class_new2("rpole~", sigrpole_new,0,sizeof(t_sigrpole),0,"F"); + sigrzero_class = class_new2("rzero~", sigrzero_new,0,sizeof(t_sigrzero),0,"F"); + sigrzrev_class = class_new2("rzero_rev~",sigrzrev_new,0,sizeof(t_sigrzrev),0,"F"); + CLASS_MAINSIGNALIN(sigrpole_class, t_sigrpole, a); + CLASS_MAINSIGNALIN(sigrzero_class, t_sigrzero, a); + CLASS_MAINSIGNALIN(sigrzrev_class, t_sigrzrev, a); + class_addmethod2(sigrpole_class, sigrpole_set, "set","F"); + class_addmethod2(sigrzero_class, sigrzero_set, "set","F"); + class_addmethod2(sigrzrev_class, sigrzrev_set, "set","F"); + class_addmethod2(sigrpole_class, sigrpole_clear,"clear",""); + class_addmethod2(sigrzero_class, sigrzero_clear,"clear",""); + class_addmethod2(sigrzrev_class, sigrzrev_clear,"clear",""); + class_addmethod2(sigrpole_class, sigrpole_dsp, "dsp",""); + class_addmethod2(sigrzero_class, sigrzero_dsp, "dsp",""); + class_addmethod2(sigrzrev_class, sigrzrev_dsp, "dsp",""); +} + +/* -------------- cpole~ - complex one-pole filter (raw) --------------- */ +/* -------------- czero~ - complex one-pole filter (raw) --------------- */ +/* ---------- czero_rev~ - complex one-pole filter (raw) --------------- */ + +t_class *sigcpole_class; struct t_sigcpole : t_object {float a; float lastre; float lastim;}; +t_class *sigczero_class; struct t_sigczero : t_object {float a; float lastre; float lastim;}; +t_class *sigczrev_class; struct t_sigczrev : t_object {float a; float lastre; float lastim;}; + +static void *sigcpole_new(t_float re, t_float im) { + t_sigcpole *x = (t_sigcpole *)pd_new(sigcpole_class); + inlet_new(x, x, &s_signal, &s_signal); + pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), re); + pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), im); + outlet_new(x, &s_signal); + outlet_new(x, &s_signal); + x->lastre = x->lastim = 0; + x->a = 0; + return x; +} +static void *sigczero_new(t_float re, t_float im) { + t_sigczero *x = (t_sigczero *)pd_new(sigczero_class); + inlet_new(x, x, &s_signal, &s_signal); + pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), re); + pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), im); + outlet_new(x, &s_signal); + outlet_new(x, &s_signal); + x->lastre = x->lastim = 0; + x->a = 0; + return x; +} +static void *sigczrev_new(t_float re, t_float im) { + t_sigczrev *x = (t_sigczrev *)pd_new(sigczrev_class); + inlet_new(x, x, &s_signal, &s_signal); + pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), re); + pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), im); + outlet_new(x, &s_signal); + outlet_new(x, &s_signal); + x->lastre = x->lastim = 0; + x->a = 0; + return x; +} + +static t_int *sigcpole_perform(t_int *w) { + float *inre1 = (float *)w[1], *inim1 = (float *)w[2]; + float *inre2 = (float *)w[3], *inim2 = (float *)w[4]; + float *outre = (float *)w[5], *outim = (float *)w[6]; + t_sigcpole *x = (t_sigcpole *)w[7]; + int n = (t_int)w[8]; + float lastre = x->lastre; + float lastim = x->lastim; + for (int i = 0; i < n; i++) { + float nextre = *inre1++, nextim = *inim1++; + float coefre = *inre2++, coefim = *inim2++; + float tempre = *outre++ = nextre + lastre * coefre - lastim * coefim; + lastim = *outim++ = nextim + lastre * coefim + lastim * coefre; + lastre = tempre; + } + if (PD_BIGORSMALL(lastre)) lastre = 0; + if (PD_BIGORSMALL(lastim)) lastim = 0; + x->lastre = lastre; + x->lastim = lastim; + return w+9; +} +static t_int *sigczero_perform(t_int *w) { + float *inre1 = (float *)w[1], *inim1 = (float *)w[2]; + float *inre2 = (float *)w[3], *inim2 = (float *)w[4]; + float *outre = (float *)w[5], *outim = (float *)w[6]; + t_sigczero *x = (t_sigczero *)w[7]; + int n = (t_int)w[8]; + float lastre = x->lastre; + float lastim = x->lastim; + for (int i = 0; i < n; i++) { + float nextre = *inre1++, nextim = *inim1++; + float coefre = *inre2++, coefim = *inim2++; + *outre++ = nextre - lastre * coefre + lastim * coefim; + *outim++ = nextim - lastre * coefim - lastim * coefre; + lastre = nextre; + lastim = nextim; + } + x->lastre = lastre; + x->lastim = lastim; + return w+9; +} +static t_int *sigczrev_perform(t_int *w) { + float *inre1 = (float *)w[1], *inim1 = (float *)w[2]; + float *inre2 = (float *)w[3], *inim2 = (float *)w[4]; + float *outre = (float *)w[5], *outim = (float *)w[6]; + t_sigczrev *x = (t_sigczrev *)w[7]; + int n = (t_int)w[8]; + float lastre = x->lastre; + float lastim = x->lastim; + for (int i = 0; i < n; i++) { + float nextre = *inre1++, nextim = *inim1++; + float coefre = *inre2++, coefim = *inim2++; + /* transfer function is (A bar) - Z^-1, for the same frequency response as 1 - AZ^-1 from czero_tilde. */ + *outre++ = lastre - nextre * coefre - nextim * coefim; + *outim++ = lastim - nextre * coefim + nextim * coefre; + lastre = nextre; + lastim = nextim; + } + x->lastre = lastre; + x->lastim = lastim; + return w+9; +} + +static void sigcpole_dsp(t_sigcpole *x, t_signal **sp) { + dsp_add(sigcpole_perform, 8, sp[0]->v, sp[1]->v, sp[2]->v, sp[3]->v, sp[4]->v, sp[5]->v, x, sp[0]->n);} +static void sigczero_dsp(t_sigczero *x, t_signal **sp) { + dsp_add(sigczero_perform, 8, sp[0]->v, sp[1]->v, sp[2]->v, sp[3]->v, sp[4]->v, sp[5]->v, x, sp[0]->n);} +static void sigczrev_dsp(t_sigczrev *x, t_signal **sp) { + dsp_add(sigczrev_perform, 8, sp[0]->v, sp[1]->v, sp[2]->v, sp[3]->v, sp[4]->v, sp[5]->v, x, sp[0]->n);} + +static void sigcpole_clear(t_sigcpole *x) {x->lastre = x->lastim = 0;} +static void sigczero_clear(t_sigczero *x) {x->lastre = x->lastim = 0;} +static void sigczrev_clear(t_sigczrev *x) {x->lastre = x->lastim = 0;} +static void sigcpole_set(t_sigcpole *x, t_float re, t_float im) {x->lastre = re; x->lastim = im;} +static void sigczero_set(t_sigczero *x, t_float re, t_float im) {x->lastre = re; x->lastim = im;} +static void sigczrev_set(t_sigczrev *x, t_float re, t_float im) {x->lastre = re; x->lastim = im;} + +void sigc_setup() { + sigcpole_class = class_new2("cpole~", sigcpole_new,0,sizeof(t_sigcpole),0,"FF"); + sigczero_class = class_new2("czero~", sigczero_new,0,sizeof(t_sigczero),0,"FF"); + sigczrev_class = class_new2("czero_rev~",sigczrev_new,0,sizeof(t_sigczrev),0,"FF"); + CLASS_MAINSIGNALIN(sigcpole_class, t_sigcpole, a); + CLASS_MAINSIGNALIN(sigczero_class, t_sigczero, a); + CLASS_MAINSIGNALIN(sigczrev_class, t_sigczrev, a); + class_addmethod2(sigcpole_class, sigcpole_set, "set","FF"); + class_addmethod2(sigczero_class, sigczero_set, "set","FF"); + class_addmethod2(sigczrev_class, sigczrev_set, "set","FF"); + class_addmethod2(sigcpole_class, sigcpole_clear,"clear",""); + class_addmethod2(sigczero_class, sigczero_clear, "clear",""); + class_addmethod2(sigczrev_class, sigczrev_clear, "clear",""); + class_addmethod2(sigcpole_class, sigcpole_dsp, "dsp",""); + class_addmethod2(sigczero_class, sigczero_dsp, "dsp",""); + class_addmethod2(sigczrev_class, sigczrev_dsp, "dsp",""); +} + +/* ----------------------------- send~ ----------------------------- */ +static t_class *sigsend_class; +struct t_sigsend : t_object { + t_symbol *sym; + int n; + float *vec; + float a; +}; +static void *sigsend_new(t_symbol *s) { + t_sigsend *x = (t_sigsend *)pd_new(sigsend_class); + pd_bind(x, s); + x->sym = s; + x->n = DEFSENDVS; + x->vec = (float *)getalignedbytes(DEFSENDVS * sizeof(float)); + memset((char *)(x->vec), 0, DEFSENDVS * sizeof(float)); + x->a = 0; + return x; +} +static t_int *sigsend_perform(t_int *w) { + testcopyvec((t_float *)w[2],(t_float *)w[1],w[3]); + return w+4; +} +/* T.Grill - SIMD version */ +static t_int *sigsend_perfsimd(t_int *w) { + testcopyvec_simd((t_float *)w[2],(t_float *)w[1],w[3]); + return w+4; +} +static void sigsend_dsp(t_sigsend *x, t_signal **sp) { + const int n = x->n; + if(n != sp[0]->n) {error("sigsend %s: unexpected vector size", x->sym->name); return;} + if(SIMD_CHECK1(n,sp[0]->v)) /* x->vec is aligned in any case */ + dsp_add(sigsend_perfsimd, 3, sp[0]->v, x->vec, n); + else dsp_add(sigsend_perform, 3, sp[0]->v, x->vec, n); +} +static void sigsend_free(t_sigsend *x) { + pd_unbind(x, x->sym); + freealignedbytes(x->vec,x->n* sizeof(float)); +} +static void sigsend_setup() { + sigsend_class = class_new2("send~",sigsend_new,sigsend_free,sizeof(t_sigsend),0,"S"); + class_addcreator2("s~",sigsend_new,"S"); + CLASS_MAINSIGNALIN(sigsend_class, t_sigsend, a); + class_addmethod2(sigsend_class, sigsend_dsp,"dsp",""); +} + +/* ----------------------------- receive~ ----------------------------- */ +static t_class *sigreceive_class; +struct t_sigreceive : t_object { + t_symbol *sym; + t_float *wherefrom; + int n; +}; +static void *sigreceive_new(t_symbol *s) { + t_sigreceive *x = (t_sigreceive *)pd_new(sigreceive_class); + x->n = DEFSENDVS; /* LATER find our vector size correctly */ + x->sym = s; + x->wherefrom = 0; + outlet_new(x, &s_signal); + return x; +} +static t_int *sigreceive_perform(t_int *w) { + t_sigreceive *x = (t_sigreceive *)w[1]; + t_float *out = (t_float *)w[2]; + int n = (int)w[3]; + t_float *in = x->wherefrom; + if (in) { + while (n--) *out++ = *in++; + } else { + while (n--) *out++ = 0; + } + return w+4; +} +/* tb: vectorized receive function */ +static t_int *sigreceive_perf8(t_int *w) { + t_sigreceive *x = (t_sigreceive *)w[1]; + t_float *in = x->wherefrom; + if (in) copyvec_8((t_float *)w[2],in,w[3]); + else zerovec_8((t_float *)w[2],w[3]); + return w+4; +} +/* T.Grill - SIMD version */ +static t_int *sigreceive_perfsimd(t_int *w) { + t_sigreceive *x = (t_sigreceive *)w[1]; + t_float *in = x->wherefrom; + if(in) copyvec_simd((t_float *)w[2],in,w[3]); + else zerovec_simd((t_float *)w[2],w[3]); + return w+4; +} +static void sigreceive_set(t_sigreceive *x, t_symbol *s) { + t_sigsend *sender = (t_sigsend *)pd_findbyclass((x->sym = s), + sigsend_class); + if (sender) { + if (sender->n == x->n) + x->wherefrom = sender->vec; + else { + error("receive~ %s: vector size mismatch", x->sym->name); + x->wherefrom = 0; + } + } else { + error("receive~ %s: no matching send", x->sym->name); + x->wherefrom = 0; + } +} +static void sigreceive_dsp(t_sigreceive *x, t_signal **sp) { + const int n = x->n; + if (sp[0]->n != n) {error("receive~ %s: vector size mismatch", x->sym->name); return;} + sigreceive_set(x, x->sym); + /* x->wherefrom is aligned because we aligned the sender memory buffer */ + if(n&7) dsp_add(sigreceive_perform, 3, x, sp[0]->v, n); + else if(SIMD_CHECK1(n,sp[0]->v)) + dsp_add(sigreceive_perfsimd, 3, x, sp[0]->v, n); + else dsp_add(sigreceive_perf8, 3, x, sp[0]->v, n); +} +static void sigreceive_setup() { + sigreceive_class = class_new2("receive~",sigreceive_new,0,sizeof(t_sigreceive),0,"S"); + class_addcreator2("r~",sigreceive_new,"S"); + class_addmethod2(sigreceive_class, sigreceive_set, "set","s"); + class_addmethod2(sigreceive_class, sigreceive_dsp, "dsp",""); + class_sethelpsymbol(sigreceive_class, gensym("send~")); +} + +/* ----------------------------- catch~ ----------------------------- */ +static t_class *sigcatch_class; +struct t_sigcatch : t_object { + t_symbol *sym; + int n; + float *vec; +}; +static void *sigcatch_new(t_symbol *s) { + t_sigcatch *x = (t_sigcatch *)pd_new(sigcatch_class); + pd_bind(x, s); + x->sym = s; + x->n = DEFSENDVS; + x->vec = (float *)getalignedbytes(DEFSENDVS * sizeof(float)); + memset((char *)(x->vec), 0, DEFSENDVS * sizeof(float)); + outlet_new(x, &s_signal); + return x; +} +static t_int *sigcatch_perform(t_int *w) { + t_float *in = (t_float *)w[1]; + t_float *out = (t_float *)w[2]; + int n = (int)w[3]; + while (n--) *out++ = *in, *in++ = 0; + return w+4; +} +/* tb: vectorized catch function */ +static t_int *sigcatch_perf8(t_int *w) { + copyvec_8((t_float *)w[2],(t_float *)w[1],w[3]); + zerovec_8((t_float *)w[1],w[3]); + return w+4; +} +/* T.Grill: SIMD catch function */ +static t_int *sigcatch_perfsimd(t_int *w) { + copyvec_simd((t_float *)w[2],(t_float *)w[1],w[3]); + zerovec_simd((t_float *)w[1],w[3]); + return w+4; +} +static void sigcatch_dsp(t_sigcatch *x, t_signal **sp) { + const int n = sp[0]->n; + if (x->n != n) {error("sigcatch %s: unexpected vector size", x->sym->name); return;} + if(n&7) dsp_add(sigcatch_perform, 3, x->vec, sp[0]->v, n); + else if(SIMD_CHECK2(n,x->vec,sp[0]->v)) + dsp_add(sigcatch_perfsimd, 3, x->vec, sp[0]->v, n); + else dsp_add(sigcatch_perf8, 3, x->vec, sp[0]->v, n); +} +static void sigcatch_free(t_sigcatch *x) { + pd_unbind(x, x->sym); + freealignedbytes(x->vec,x->n*sizeof(float)); +} +static void sigcatch_setup() { + sigcatch_class = class_new2("catch~",sigcatch_new,sigcatch_free,sizeof(t_sigcatch),CLASS_NOINLET,"S"); + class_addmethod2(sigcatch_class, sigcatch_dsp, "dsp",""); + class_sethelpsymbol(sigcatch_class, gensym("throw~")); +} + +/* ----------------------------- throw~ ----------------------------- */ +static t_class *sigthrow_class; +struct t_sigthrow : t_object { + t_symbol *sym; + t_float *whereto; + int n; + t_float a; +}; +static void *sigthrow_new(t_symbol *s) { + t_sigthrow *x = (t_sigthrow *)pd_new(sigthrow_class); + x->sym = s; + x->whereto = 0; + x->n = DEFSENDVS; + x->a = 0; + return x; +} +static t_int *sigthrow_perform(t_int *w) { + t_sigthrow *x = (t_sigthrow *)w[1]; + t_float *out = x->whereto; + if(out) testaddvec(out,(t_float *)w[2],w[3]); + return w+4; +} +/* T.Grill - SIMD version */ +static t_int *sigthrow_perfsimd(t_int *w) { + t_sigthrow *x = (t_sigthrow *)w[1]; + t_float *out = x->whereto; + if(out) testaddvec_simd(out,(t_float *)w[2],w[3]); + return w+4; +} +static void sigthrow_set(t_sigthrow *x, t_symbol *s) { + x->sym = s; + t_sigcatch *catcher = (t_sigcatch *)pd_findbyclass(s,sigcatch_class); + x->whereto = 0; + if (catcher) { + if (catcher->n == x->n) x->whereto = catcher->vec; + else error("throw~ %s: vector size mismatch", x->sym->name); + } else error("throw~ %s: no matching catch", x->sym->name); +} +static void sigthrow_dsp(t_sigthrow *x, t_signal **sp) { + const int n = x->n; + if (sp[0]->n != n) {error("throw~ %s: vector size mismatch", x->sym->name); return;} + sigthrow_set(x, x->sym); + if(SIMD_CHECK1(n,sp[0]->v)) /* the memory of the catcher is aligned in any case */ + dsp_add(sigthrow_perfsimd, 3, x, sp[0]->v, n); + else dsp_add(sigthrow_perform, 3, x, sp[0]->v, n); +} +static void sigthrow_setup() { + sigthrow_class = class_new2("throw~",sigthrow_new,0,sizeof(t_sigthrow),0,"S"); + class_addmethod2(sigthrow_class, sigthrow_set, "set","s"); + CLASS_MAINSIGNALIN(sigthrow_class, t_sigthrow, a); + class_addmethod2(sigthrow_class, sigthrow_dsp, "dsp",""); +} + +/* ------------------------- clip~ -------------------------- */ +static t_class *clip_class; +struct t_clip : t_object { + float a; + t_sample lo; + t_sample hi; +}; +static void *clip_new(t_floatarg lo, t_floatarg hi) { + t_clip *x = (t_clip *)pd_new(clip_class); + x->lo = lo; + x->hi = hi; + outlet_new(x, &s_signal); + floatinlet_new(x, &x->lo); + floatinlet_new(x, &x->hi); + x->a = 0; + return x; +} +/* T.Grill - changed function interface so that class pointer needn't be passed */ +t_int *clip_perform(t_int *w) { + t_float *in = (t_float *)w[1]; + t_float *out = (t_float *)w[2]; + const t_float lo = *(t_float *)w[3],hi = *(t_float *)w[4]; + int n = (int)w[5]; + while (n--) *out++ = clip(*in++,lo,hi); + return w+6; +} +static void clip_dsp(t_clip *x, t_signal **sp) { + if(SIMD_CHECK2(sp[0]->n,sp[0]->v,sp[1]->v)) + dsp_add(clip_perf_simd, 5, sp[0]->v, sp[1]->v, &x->lo, &x->hi, sp[0]->n); + else dsp_add(clip_perform, 5, sp[0]->v, sp[1]->v, &x->lo, &x->hi, sp[0]->n); +} +static void clip_setup() { + clip_class = class_new2("clip~",clip_new,0,sizeof(t_clip),0,"FF"); + CLASS_MAINSIGNALIN(clip_class, t_clip, a); + class_addmethod2(clip_class, clip_dsp, "dsp",""); +} + +/* sigrsqrt - reciprocal square root good to 8 mantissa bits */ +/* sigsqrt - square root good to 8 mantissa bits */ + +#define DUMTAB1SIZE 256 +#define DUMTAB2SIZE 1024 +static float rsqrt_exptab[DUMTAB1SIZE], rsqrt_mantissatab[DUMTAB2SIZE]; +static void init_rsqrt() { + for (int i = 0; i < DUMTAB1SIZE; i++) { + float f; + long l = (i ? (i == DUMTAB1SIZE-1 ? DUMTAB1SIZE-2 : i) : 1)<< 23; + *(int *)(&f) = l; + rsqrt_exptab[i] = 1./sqrt(f); + } + for (int i = 0; i < DUMTAB2SIZE; i++) { + float f = 1 + (1./DUMTAB2SIZE) * i; + rsqrt_mantissatab[i] = 1./sqrt(f); + } +} +/* these are used in externs like "bonk" */ +float q8_rsqrt(float f) { + long l = *(long *)(&f); + if (f < 0) return 0; + return rsqrt_exptab[(l >> 23) & 0xff] * + rsqrt_mantissatab[(l >> 13) & 0x3ff]; +} +float q8_sqrt(float f) { + long l = *(long *)(&f); + if (f < 0) return 0; + return f * rsqrt_exptab[(l >> 23) & 0xff] * + rsqrt_mantissatab[(l >> 13) & 0x3ff]; +} + +/* the old names are OK unless we're in IRIX N32 */ +#ifndef N32 +float qsqrt(float f) {return q8_sqrt(f);} +float qrsqrt(float f) {return q8_rsqrt(f);} +#endif +static t_class *sigrsqrt_class; struct t_sigrsqrt : t_object {float a;}; +static t_class * sigsqrt_class; struct t_sigsqrt : t_object {float a;}; +static void *sigrsqrt_new() { + t_sigrsqrt *x = (t_sigrsqrt *)pd_new(sigrsqrt_class); + outlet_new(x, &s_signal); + x->a = 0; + return x; +} +static void *sigsqrt_new() { + t_sigsqrt *x = (t_sigsqrt *)pd_new(sigsqrt_class); + outlet_new(x, &s_signal); + x->a = 0; + return x; +} + +static t_int *sigrsqrt_perform(t_int *w) { + float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2); + t_int n = *(t_int *)(w+3); + while (n--) { + float f = *in; + long l = *(long *)(in++); + if (f < 0) *out++ = 0; + else { + float g = rsqrt_exptab[(l >> 23) & 0xff] * + rsqrt_mantissatab[(l >> 13) & 0x3ff]; + *out++ = 1.5 * g - 0.5 * g * g * g * f; + } + } + return w+4; +} +/* not static; also used in d_fft.c */ +t_int *sigsqrt_perform(t_int *w) { + float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2); + t_int n = *(t_int *)(w+3); + while (n--) { + float f = *in; + long l = *(long *)(in++); + if (f < 0) *out++ = 0; + else { + float g = rsqrt_exptab[(l >> 23) & 0xff] * + rsqrt_mantissatab[(l >> 13) & 0x3ff]; + *out++ = f * (1.5 * g - 0.5 * g * g * g * f); + } + } + return w+4; +} + +static void sigrsqrt_dsp(t_sigrsqrt *x, t_signal **sp) { + if(SIMD_CHECK2(sp[0]->n,sp[0]->v,sp[1]->v)) + dsp_add(sigrsqrt_perf_simd, 3, sp[0]->v, sp[1]->v, sp[0]->n); + else dsp_add(sigrsqrt_perform, 3, sp[0]->v, sp[1]->v, sp[0]->n); +} +static void sigsqrt_dsp(t_sigsqrt *x, t_signal **sp) { + if(SIMD_CHECK2(sp[0]->n,sp[0]->v,sp[1]->v)) + dsp_add(sigsqrt_perf_simd, 3, sp[0]->v, sp[1]->v, sp[0]->n); + else dsp_add(sigsqrt_perform, 3, sp[0]->v, sp[1]->v, sp[0]->n); +} + +void sigsqrt_setup() { + init_rsqrt(); + sigrsqrt_class = class_new2("rsqrt~",sigrsqrt_new,0,sizeof(t_sigrsqrt),0,""); + sigsqrt_class = class_new2( "sqrt~", sigsqrt_new,0, sizeof(t_sigsqrt),0,""); + CLASS_MAINSIGNALIN(sigrsqrt_class,t_sigrsqrt,a); + CLASS_MAINSIGNALIN( sigsqrt_class, t_sigsqrt,a); + class_addmethod2( sigsqrt_class, sigsqrt_dsp,"dsp",""); + class_addmethod2(sigrsqrt_class,sigrsqrt_dsp,"dsp",""); + class_addcreator2("q8_rsqrt~",sigrsqrt_new,""); + class_addcreator2("q8_sqrt~", sigsqrt_new,""); +} + +/* ------------------------------ wrap~ -------------------------- */ +struct t_sigwrap : t_object {float a;}; +t_class *sigwrap_class; +static void *sigwrap_new() { + t_sigwrap *x = (t_sigwrap *)pd_new(sigwrap_class); + outlet_new(x, &s_signal); + x->a = 0; + return x; +} +static t_int *sigwrap_perform(t_int *w) { + float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2); + t_int n = *(t_int *)(w+3); + while (n--) { + float f = *in++; + int k = (int)f; + if (f > 0) *out++ = f-k; + else *out++ = f - (k-1); + } + return w+4; +} +static void sigwrap_dsp(t_sigwrap *x, t_signal **sp) { + if(SIMD_CHECK2(sp[0]->n,sp[0]->v,sp[1]->v)) + dsp_add(sigwrap_perf_simd, 3, sp[0]->v, sp[1]->v, sp[0]->n); + else dsp_add(sigwrap_perform, 3, sp[0]->v, sp[1]->v, sp[0]->n); +} +void sigwrap_setup() { + sigwrap_class = class_new2("wrap~",sigwrap_new,0,sizeof(t_sigwrap),0,""); + CLASS_MAINSIGNALIN(sigwrap_class, t_sigwrap, a); + class_addmethod2(sigwrap_class, sigwrap_dsp, "dsp",""); +} + +/* ------------------------------ mtof_tilde~ and such -------------------------- */ +struct t_func1 : t_object {float a;}; +t_class *mtof_tilde_class, *ftom_tilde_class; +t_class *dbtorms_tilde_class, *rmstodb_tilde_class; +t_class *dbtopow_tilde_class, *powtodb_tilde_class; + +#define FUNC1(NAME,EXPR) \ +static t_int *NAME##_perform(t_int *w) { \ + float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2); \ + for (t_int n = *(t_int *)(w+3); n--; in++, out++) { float a = *in; *out = (EXPR); } \ + return w+4;} \ +static void *NAME##_new() {t_func1 *x = (t_func1 *)pd_new(NAME##_class); \ + outlet_new(x,&s_signal); x->a = 0; return x;} \ +static void NAME##_dsp(t_func1 *x, t_signal **sp) { \ + dsp_add(NAME##_perform, 3, sp[0]->v, sp[1]->v, sp[0]->n);} + + +FUNC1(mtof_tilde, a<=-1500 ? 0 : 8.17579891564 * exp(.0577622650 * min(a,1499.f))) +FUNC1(ftom_tilde, a>0 ? 17.3123405046 * log(.12231220585 * a) : -1500) +FUNC1(dbtorms_tilde, a<=0 ? 0 : exp((LOGTEN * 0.05) * (min(a,485.f)-100.))) +FUNC1(dbtopow_tilde, a<=0 ? 0 : max(100 + 20./LOGTEN * log(a),0.)) +FUNC1(rmstodb_tilde, a<=0 ? 0 : exp((LOGTEN * 0.1) * (min(a,870.f)-100.))) +FUNC1(powtodb_tilde, a<=0 ? 0 : max(100 + 10./LOGTEN * log(a),0.)) + +#define FUNC1DECL(NAME,SYM) \ + NAME##_class = class_new2(SYM,NAME##_new,0,sizeof(t_func1),0,""); \ + CLASS_MAINSIGNALIN(NAME##_class,t_func1,a); \ + class_addmethod2(NAME##_class, NAME##_dsp, "dsp",""); + +void mtof_tilde_setup() { + FUNC1DECL(mtof_tilde,"mtof~") + FUNC1DECL(ftom_tilde,"ftom~") + FUNC1DECL(dbtorms_tilde,"dbtorms~") + FUNC1DECL(dbtopow_tilde,"dbtopow~") + FUNC1DECL(rmstodb_tilde,"rmstodb~") + FUNC1DECL(powtodb_tilde,"powtodb~") + t_symbol *s = gensym("acoustics~.pd"); + class_sethelpsymbol(mtof_tilde_class, s); + class_sethelpsymbol(ftom_tilde_class, s); + class_sethelpsymbol(dbtorms_tilde_class, s); + class_sethelpsymbol(rmstodb_tilde_class, s); + class_sethelpsymbol(dbtopow_tilde_class, s); + class_sethelpsymbol(powtodb_tilde_class, s); +} + +static t_class *print_class; +struct t_print : t_object { + float a; + t_symbol *sym; + int count; +}; +static t_int *print_perform(t_int *w) { + t_print *x = (t_print *)w[1]; + t_float *in = (t_float *)w[2]; + int n = (int)w[3]; + if (x->count) { + post("%s:", x->sym->name); + if (n == 1) post("%8g", in[0]); + else if (n == 2) post("%8g %8g", in[0], in[1]); + else if (n == 4) post("%8g %8g %8g %8g", in[0], in[1], in[2], in[3]); + else while (n > 0) { + post("%-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g", + in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7]); + n -= 8; + in += 8; + } + x->count--; + } + return w+4; +} +static void print_dsp(t_print *x, t_signal **sp) { + dsp_add(print_perform, 3, x, sp[0]->v, sp[0]->n); +} +static void print_float(t_print *x, t_float f) {x->count = max(0,(int)f);} +static void print_bang(t_print *x) {x->count = 1;} +static void *print_new(t_symbol *s) { + t_print *x = (t_print *)pd_new(print_class); + x->sym = s->name[0] ? s : gensym("print~"); + x->count = 0; + x->a = 0; + return x; +} +static void print_setup() { + print_class = class_new2("print~",print_new,0,sizeof(t_print),0,"S"); + CLASS_MAINSIGNALIN(print_class, t_print, a); + class_addmethod2(print_class, print_dsp, "dsp",""); + class_addbang(print_class, print_bang); + class_addfloat(print_class, print_float); +} + +/* ------------------------ bang~ -------------------------- */ +static t_class *bang_tilde_class; +struct t_bang : t_object { + t_clock *clock; +}; +static t_int *bang_tilde_perform(t_int *w) { + t_bang *x = (t_bang *)w[1]; + clock_delay(x->clock, 0); + return w+2; +} +static void bang_tilde_dsp(t_bang *x, t_signal **sp) {dsp_add(bang_tilde_perform, 1, x);} +static void bang_tilde_tick(t_bang *x) {outlet_bang(x->outlet);} +static void bang_tilde_free(t_bang *x) {clock_free(x->clock);} +static void *bang_tilde_new(t_symbol *s) { + t_bang *x = (t_bang *)pd_new(bang_tilde_class); + x->clock = clock_new(x, bang_tilde_tick); + outlet_new(x, &s_bang); + return x; +} +static void bang_tilde_setup() { + bang_tilde_class = class_new2("bang~",bang_tilde_new,bang_tilde_free,sizeof(t_bang),0,""); + class_addmethod2(bang_tilde_class, bang_tilde_dsp, "dsp",""); +} + +/* -------------------------- phasor~ ------------------------------ */ +static t_class *phasor_class; +/* in the style of R. Hoeldrich (ICMC 1995 Banff) */ +struct t_phasor : t_object { + double phase; + float conv; + float a; /* scalar frequency */ +}; +static void *phasor_new(t_floatarg f) { + t_phasor *x = (t_phasor *)pd_new(phasor_class); + x->a = f; + inlet_new(x, x, &s_float, gensym("ft1")); + x->phase = 0; + x->conv = 0; + outlet_new(x, &s_signal); + return x; +} +static t_int *phasor_perform(t_int *w) { + t_phasor *x = (t_phasor *)w[1]; + t_float *in = (t_float *)w[2]; + t_float *out = (t_float *)w[3]; + int n = (int)w[4]; + double dphase = x->phase + UNITBIT32; + union tabfudge tf; + int normhipart; + float conv = x->conv; + tf.d = UNITBIT32; + normhipart = tf.i[HIOFFSET]; + tf.d = dphase; + while (n--) { + tf.i[HIOFFSET] = normhipart; + dphase += *in++ * conv; + *out++ = tf.d - UNITBIT32; + tf.d = dphase; + } + tf.i[HIOFFSET] = normhipart; + x->phase = tf.d - UNITBIT32; + return w+5; +} +static void phasor_dsp(t_phasor *x, t_signal **sp) { + x->conv = 1./sp[0]->sr; + dsp_add(phasor_perform, 4, x, sp[0]->v, sp[1]->v, sp[0]->n); +} +static void phasor_ft1(t_phasor *x, t_float f) { + x->phase = f; +} +static void phasor_setup() { + phasor_class = class_new2("phasor~",phasor_new,0,sizeof(t_phasor),0,"F"); + CLASS_MAINSIGNALIN(phasor_class, t_phasor, a); + class_addmethod2(phasor_class, phasor_dsp, "dsp",""); + class_addmethod2(phasor_class, phasor_ft1,"ft1","f"); +} +/* */ + +/* ------------------------ cos~ ----------------------------- */ +float *cos_table; +static t_class *cos_class; +struct t_cos : t_object { + float a; +}; +static void *cos_new() { + t_cos *x = (t_cos *)pd_new(cos_class); + outlet_new(x,&s_signal); + x->a = 0; + return x; +} +static t_int *cos_perform(t_int *w) { + t_float *in = (t_float *)w[1]; + t_float *out = (t_float *)w[2]; + int n = (int)w[3]; + float *tab = cos_table, *addr, f1, f2, frac; + double dphase; + int normhipart; + union tabfudge tf; + tf.d = UNITBIT32; + normhipart = tf.i[HIOFFSET]; + +#if 0 /* this is the readable version of the code. */ + while (n--) { + dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32; + tf.d = dphase; + addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1)); + tf.i[HIOFFSET] = normhipart; + frac = tf.d - UNITBIT32; + f1 = addr[0]; + f2 = addr[1]; + *out++ = f1 + frac * (f2 - f1); + } +#else /* this is the same, unwrapped by hand. */ + dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32; + tf.d = dphase; + addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1)); + tf.i[HIOFFSET] = normhipart; + while (--n) { + dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32; + frac = tf.d - UNITBIT32; + tf.d = dphase; + f1 = addr[0]; + f2 = addr[1]; + addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1)); + *out++ = f1 + frac * (f2 - f1); + tf.i[HIOFFSET] = normhipart; + } + frac = tf.d - UNITBIT32; + f1 = addr[0]; + f2 = addr[1]; + *out++ = f1 + frac * (f2 - f1); +#endif + return w+4; +} +static void cos_dsp(t_cos *x, t_signal **sp) { + dsp_add(cos_perform, 3, sp[0]->v, sp[1]->v, sp[0]->n); +} +static void cos_maketable() { + float phsinc = (2. * 3.14159) / COSTABSIZE; + union tabfudge tf; + if (cos_table) return; + cos_table = (float *)getbytes(sizeof(float) * (COSTABSIZE+1)); + float phase=0; + float *fp = cos_table; + for (int i = COSTABSIZE + 1; i--; fp++, phase += phsinc) *fp = cos(phase); + /* here we check at startup whether the byte alignment + is as we declared it. If not, the code has to be recompiled the other way. */ + tf.d = UNITBIT32 + 0.5; + if ((unsigned)tf.i[LOWOFFSET] != 0x80000000) bug("cos~: unexpected machine alignment"); +} +static void cos_setup() { + cos_class = class_new2("cos~",cos_new,0,sizeof(t_cos),0,"F"); + CLASS_MAINSIGNALIN(cos_class, t_cos, a); + class_addmethod2(cos_class, cos_dsp, "dsp",""); + cos_maketable(); +} + +/* ------------------------ osc~ ----------------------------- */ +static t_class *osc_class; +struct t_osc : t_object { + double phase; + float conv; + float a; /* frequency if scalar */ +}; +static void *osc_new(t_floatarg f) { + t_osc *x = (t_osc *)pd_new(osc_class); + x->a = f; + outlet_new(x,&s_signal); + inlet_new(x, x, &s_float, gensym("ft1")); + inlet_settip(x->inlet,gensym("phase")); + x->phase = 0; + x->conv = 0; + return x; +} +static t_int *osc_perform(t_int *w) { + t_osc *x = (t_osc *)w[1]; + t_float *in = (t_float *)w[2]; + t_float *out = (t_float *)w[3]; + int n = (int)w[4]; + float *tab = cos_table, *addr, f1, f2, frac; + double dphase = x->phase + UNITBIT32; + int normhipart; + union tabfudge tf; + float conv = x->conv; + tf.d = UNITBIT32; + normhipart = tf.i[HIOFFSET]; +#if 0 + while (n--) { + tf.d = dphase; + dphase += *in++ * conv; + addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1)); + tf.i[HIOFFSET] = normhipart; + frac = tf.d - UNITBIT32; + f1 = addr[0]; + f2 = addr[1]; + *out++ = f1 + frac * (f2 - f1); + } +#else + tf.d = dphase; + dphase += *in++ * conv; + addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1)); + tf.i[HIOFFSET] = normhipart; + frac = tf.d - UNITBIT32; + while (--n) { + tf.d = dphase; + f1 = addr[0]; + dphase += *in++ * conv; + f2 = addr[1]; + addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1)); + tf.i[HIOFFSET] = normhipart; + *out++ = f1 + frac * (f2 - f1); + frac = tf.d - UNITBIT32; + } + f1 = addr[0]; + f2 = addr[1]; + *out++ = f1 + frac * (f2 - f1); +#endif + tf.d = UNITBIT32 * COSTABSIZE; + normhipart = tf.i[HIOFFSET]; + tf.d = dphase + (UNITBIT32 * COSTABSIZE - UNITBIT32); + tf.i[HIOFFSET] = normhipart; + x->phase = tf.d - UNITBIT32 * COSTABSIZE; + return w+5; +} +static void osc_dsp(t_osc *x, t_signal **sp) { + x->conv = COSTABSIZE/sp[0]->sr; + dsp_add(osc_perform, 4, x, sp[0]->v, sp[1]->v, sp[0]->n); +} +static void osc_ft1(t_osc *x, t_float f) { + x->phase = COSTABSIZE * f; +} +static void osc_setup() { + osc_class = class_new2("osc~",osc_new,0,sizeof(t_osc),0,"F"); + CLASS_MAINSIGNALIN(osc_class, t_osc, a); + class_addmethod2(osc_class, osc_dsp, "dsp",""); + class_addmethod2(osc_class, osc_ft1, "ft1","f"); + class_settip(osc_class,gensym("frequency")); + cos_maketable(); +} + +/* ---------------- vcf~ - 2-pole bandpass filter. ----------------- */ +struct t_vcfctl { + float re; + float im; + float q; + float isr; +}; +struct t_sigvcf : t_object { + t_vcfctl cspace; + t_vcfctl *ctl; + float a; +}; +t_class *sigvcf_class; +static void *sigvcf_new(t_floatarg q) { + t_sigvcf *x = (t_sigvcf *)pd_new(sigvcf_class); + inlet_new(x, x, &s_signal, &s_signal); + inlet_new(x, x, &s_float, gensym("ft1")); + outlet_new(x, &s_signal); + outlet_new(x, &s_signal); + x->ctl = &x->cspace; + x->cspace.re = 0; + x->cspace.im = 0; + x->cspace.q = q; + x->cspace.isr = 0; + x->a = 0; + return x; +} +static void sigvcf_ft1(t_sigvcf *x, t_floatarg f) { + x->ctl->q = (f > 0 ? f : 0.f); +} +static t_int *sigvcf_perform(t_int *w) { + float *in1 = (float *)w[1]; + float *in2 = (float *)w[2]; + float *out1 = (float *)w[3]; + float *out2 = (float *)w[4]; + t_vcfctl *c = (t_vcfctl *)w[5]; + int n = (t_int)w[6]; + float re = c->re, re2; + float im = c->im; + float q = c->q; + float qinv = (q > 0? 1.0f/q : 0); + float ampcorrect = 2.0f - 2.0f / (q + 2.0f); + float isr = c->isr; + float coefr, coefi; + float *tab = cos_table, *addr, f1, f2, frac; + double dphase; + int normhipart, tabindex; + union tabfudge tf; + tf.d = UNITBIT32; + normhipart = tf.i[HIOFFSET]; + for (int i = 0; i < n; i++) { + float cf, cfindx, r, oneminusr; + cf = *in2++ * isr; + if (cf < 0) cf = 0; + cfindx = cf * (float)(COSTABSIZE/6.28318f); + r = (qinv > 0 ? 1 - cf * qinv : 0); + if (r < 0) r = 0; + oneminusr = 1.0f - r; + dphase = ((double)(cfindx)) + UNITBIT32; + tf.d = dphase; + tabindex = tf.i[HIOFFSET] & (COSTABSIZE-1); + addr = tab + tabindex; + tf.i[HIOFFSET] = normhipart; + frac = tf.d - UNITBIT32; + f1 = addr[0]; f2 = addr[1]; coefr = r * (f1 + frac * (f2 - f1)); + addr = tab + ((tabindex - (COSTABSIZE/4)) & (COSTABSIZE-1)); + f1 = addr[0]; f2 = addr[1]; coefi = r * (f1 + frac * (f2 - f1)); + f1 = *in1++; + re2 = re; + *out1++ = re = ampcorrect * oneminusr * f1 + coefr * re2 - coefi * im; + *out2++ = im = coefi * re2 + coefr * im; + } + if (PD_BIGORSMALL(re)) re = 0; + if (PD_BIGORSMALL(im)) im = 0; + c->re = re; + c->im = im; + return w+7; +} +static void sigvcf_dsp(t_sigvcf *x, t_signal **sp) { + x->ctl->isr = 6.28318f/sp[0]->sr; + dsp_add(sigvcf_perform, 6, sp[0]->v, sp[1]->v, sp[2]->v, sp[3]->v, x->ctl, sp[0]->n); + +} +void sigvcf_setup() { + sigvcf_class = class_new2("vcf~",sigvcf_new,0,sizeof(t_sigvcf),0,"F"); + CLASS_MAINSIGNALIN(sigvcf_class, t_sigvcf, a); + class_addmethod2(sigvcf_class, sigvcf_dsp, "dsp",""); + class_addmethod2(sigvcf_class, sigvcf_ft1, "ft1","f"); +} + +/* -------------------------- noise~ ------------------------------ */ +static t_class *noise_class; +struct t_noise : t_object { + int val; +}; +static void *noise_new() { + t_noise *x = (t_noise *)pd_new(noise_class); + static int init = 307; + x->val = (init *= 1319); + outlet_new(x, &s_signal); + return x; +} +static t_int *noise_perform(t_int *w) { + t_float *out = (t_float *)w[1]; + int *vp = (int *)w[2]; + int n = (int)w[3]; + int val = *vp; + while (n--) { + *out++ = ((float)((val & 0x7fffffff) - 0x40000000)) * (float)(1.0 / 0x40000000); + val = val * 435898247 + 382842987; + } + *vp = val; + return w+4; +} +static void noise_dsp(t_noise *x, t_signal **sp) { + dsp_add(noise_perform, 3, sp[0]->v, &x->val, sp[0]->n); +} +static void noise_setup() { + noise_class = class_new2("noise~",noise_new,0,sizeof(t_noise),0,""); + class_addmethod2(noise_class, noise_dsp, "dsp",""); +} +void builtins_dsp_setup() { + plus_setup(); + minus_setup(); + times_setup(); + over_setup(); + max_setup(); + min_setup(); + lt_setup(); + gt_setup(); + le_setup(); + ge_setup(); + eq_setup(); + ne_setup(); + //abs_setup(); + + tab_tilde_setup(); + tabosc4_tilde_setup(); + tabsend_setup(); + tabreceive_setup(); + tabread_setup(); + tabread4_setup(); + tabwrite_setup(); + + sig_tilde_setup(); + line_tilde_setup(); snapshot_tilde_setup(); + vline_tilde_setup(); vsnapshot_tilde_setup(); + env_tilde_setup(); + threshold_tilde_setup(); + + dac_setup(); + adc_setup(); + + sigdelwrite_setup(); + sigdelread_setup(); + sigvd_setup(); + + sigframp_setup(); +#ifdef HAVE_LIBFFTW3F + sigfftw_setup(); /* added by Tim Blechmann to support fftw */ +#else + sigfft_setup(); +#endif /* HAVE_LIBFFTW3F */ + + sighip_setup(); + siglop_setup(); + sigbp_setup(); + sigbiquad_setup(); + sigsamphold_setup(); + sigr_setup(); + sigc_setup(); + + sigsend_setup(); + sigreceive_setup(); + sigcatch_setup(); + sigthrow_setup(); + + clip_setup(); + sigsqrt_setup(); + sigwrap_setup(); + mtof_tilde_setup(); + print_setup(); + bang_tilde_setup(); + + phasor_setup(); + cos_setup(); + osc_setup(); + sigvcf_setup(); + noise_setup(); +} -- cgit v1.2.1