From 17ec1deb74e2e934dc11fb4d9a2f8c6cef34c5a7 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Mon, 9 Jul 2007 20:45:58 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r7949, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/moonlib/; revision=7950 --- tabenv.c | 294 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 tabenv.c (limited to 'tabenv.c') diff --git a/tabenv.c b/tabenv.c new file mode 100644 index 0000000..9b52fbe --- /dev/null +++ b/tabenv.c @@ -0,0 +1,294 @@ +/* +Copyright (C) 2002 Antoine Rousseau + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "m_pd.h" +#include "math.h" + + +/* ---------------- tabenv - table envelope computer. ----------------- */ +/*------- (in fact it's a mix between env~ and tabplay~)----------------*/ + +#define MAXOVERLAP 10 +#define MAXVSTAKEN 64 + +typedef struct tabenv +{ + /*env part*/ + t_object x_obj; /* header */ + t_outlet *x_outlet; /* a "float" outlet */ + t_clock *x_clock; /* a "clock" object */ + float *x_buf; /* a Hanning window */ + int x_phase; /* number of points since last output */ + int x_period; /* requested period of output */ + int x_realperiod; /* period rounded up to vecsize multiple */ + int x_npoints; /* analysis window size in samples */ + float x_result; /* result to output */ + float x_sumbuf[MAXOVERLAP]; /* summing buffer */ + float x_f; + + /*tabplay part*/ + int x_tabphase; + int x_nsampsintab; + int x_limit; + float *x_vec; + t_symbol *x_arrayname; +} t_tabenv; + +t_class *tabenv_class; +static void tabenv_tick(t_tabenv *x); + +static void *tabenv_new(t_symbol *s,t_floatarg fnpoints, t_floatarg fperiod) +{ + int npoints = fnpoints; + int period = fperiod; + t_tabenv *x; + float *buf; + int i; + + if (npoints < 1) npoints = 1024; + if (period < 1) period = npoints/2; + if (period < npoints / MAXOVERLAP + 1) + period = npoints / MAXOVERLAP + 1; + if (!(buf = getbytes(sizeof(float) * (npoints + MAXVSTAKEN)))) + { + error("env: couldn't allocate buffer"); + return (0); + } + x = (t_tabenv *)pd_new(tabenv_class); + x->x_buf = buf; + x->x_npoints = npoints; + x->x_phase = 0; + x->x_period = period; + for (i = 0; i < MAXOVERLAP; i++) x->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->x_clock = clock_new(x, (t_method)tabenv_tick); + x->x_outlet = outlet_new(&x->x_obj, gensym("float")); + x->x_f = 0; + + /* tabplay */ + x->x_tabphase = 0x7fffffff; + x->x_limit = 0; + x->x_arrayname = s; + + return (x); +} + +static t_int *sigenv_perform(t_int *w) +{ + t_tabenv *x = (t_tabenv *)(w[1]); + t_float *in = (t_float *)(w[2]); + int n = (int)(w[3]); + int count; + float *sump; + in += n; + for (count = x->x_phase, sump = x->x_sumbuf; + count < x->x_npoints; count += x->x_realperiod, sump++) + { + float *hp = x->x_buf + count; + float *fp = in; + float sum = *sump; + int i; + + for (i = 0; i < n; i++) + { + fp--; + sum += *hp++ * (*fp * *fp); + } + *sump = sum; + } + sump[0] = 0; + x->x_phase -= n; + if (x->x_phase < 0) + { + x->x_result = x->x_sumbuf[0]; + for (count = x->x_realperiod, sump = x->x_sumbuf; + count < x->x_npoints; count += x->x_realperiod, sump++) + sump[0] = sump[1]; + sump[0] = 0; + x->x_phase = x->x_realperiod - n; + clock_delay(x->x_clock, 0L); + } + return (w+4); +} + +static t_int *tabplay_tilde_perform(t_int *w) +{ + t_tabenv *x = (t_tabenv *)(w[1]); + t_float *out = (t_float *)(w[2]), *fp; + int n = (int)(w[3]), phase = x->x_phase, + endphase = (x->x_nsampsintab < x->x_limit ? + x->x_nsampsintab : x->x_limit), nxfer, n3; + if (!x->x_vec || phase >= endphase) + goto zero; + + nxfer = endphase - phase; + fp = x->x_vec + phase; + if (nxfer > n) + nxfer = n; + n3 = n - nxfer; + phase += nxfer; + while (nxfer--) + *out++ = *fp++; + if (phase >= endphase) + { + clock_delay(x->x_clock, 0); + x->x_phase = 0x7fffffff; + while (n3--) + *out++ = 0; + } + else x->x_phase = phase; + + return (w+4); +zero: + while (n--) *out++ = 0; + return (w+4); +} + + +static void tabenv_perform_64(t_tabenv *x,t_float *in) +{ + int n = 64; + int count; + float *sump; + in += n; + for (count = x->x_phase, sump = x->x_sumbuf; + count < x->x_npoints; count += x->x_realperiod, sump++) + { + float *hp = x->x_buf + count; + float *fp = in; + float sum = *sump; + int i; + + for (i = 0; i < n; i++) + { + fp--; + sum += *hp++ * (*fp * *fp); + } + *sump = sum; + } + sump[0] = 0; + x->x_phase -= n; + if (x->x_phase < 0) + { + x->x_result = x->x_sumbuf[0]; + for (count = x->x_realperiod, sump = x->x_sumbuf; + count < x->x_npoints; count += x->x_realperiod, sump++) + sump[0] = sump[1]; + sump[0] = 0; + x->x_phase = x->x_realperiod - n; + /*clock_delay(x->x_clock, 0L);*/ + outlet_float(x->x_outlet, powtodb(x->x_result)); + } +} + + +static void tabenv_set(t_tabenv *x, t_symbol *s) +{ + t_garray *a; + + x->x_arrayname = s; + if (!(a = (t_garray *)pd_findbyclass(x->x_arrayname, garray_class))) + { + if (*s->s_name) pd_error(x, "tabenv: %s: no such array", + x->x_arrayname->s_name); + x->x_vec = 0; + } + else if (!garray_getfloatarray(a, &x->x_nsampsintab, &x->x_vec)) + { + error("%s: bad template for tabenv", x->x_arrayname->s_name); + x->x_vec = 0; + } + else garray_usedindsp(a); +} + +static void sigenv_dsp(t_tabenv *x, t_signal **sp) +{ + if (x->x_period % sp[0]->s_n) x->x_realperiod = + x->x_period + sp[0]->s_n - (x->x_period % sp[0]->s_n); + else x->x_realperiod = x->x_period; + dsp_add(sigenv_perform, 3, x, sp[0]->s_vec, sp[0]->s_n); + if (sp[0]->s_n > MAXVSTAKEN) bug("sigenv_dsp"); +} + +static void tabenv_list(t_tabenv *x, t_symbol *s, + int argc, t_atom *argv) +{ + long start = atom_getfloatarg(0, argc, argv); + long length = atom_getfloatarg(1, argc, argv); + float *limitp,*p; + int i; + + tabenv_set(x, x->x_arrayname); + + if (start < 0) start = 0; + if (length <= 0) + x->x_limit = 0x7fffffff; + else + x->x_limit = start + length; + x->x_tabphase = start; + + if(length <= 0) length = x->x_nsampsintab - 1; + if(start >= x->x_nsampsintab) start = x->x_nsampsintab - 1; + if((start + length) >= x->x_nsampsintab) + length = x->x_nsampsintab - 1 - start; + + limitp = x->x_vec + start + length - 63; + /*limitp = x->x_vec + 2048;*/ + /*if (x->x_period % length) x->x_realperiod = + x->x_period + length - (x->x_period % length); + else*/ x->x_realperiod = x->x_period; + + for(p = x->x_vec + start; p < limitp ; p += 64) + tabenv_perform_64( x , p ); +} + +static void tabenv_reset(t_tabenv *x) +{ + int i; + x->x_phase = 0; + for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0; +} + +static void tabenv_tick(t_tabenv *x) /* callback function for the env clock */ +{ + outlet_float(x->x_outlet, powtodb(x->x_result)); +} + +static void tabenv_ff(t_tabenv *x) /* cleanup on free */ +{ + clock_free(x->x_clock); + freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float)); +} + + +void tabenv_setup(void ) +{ + tabenv_class = class_new(gensym("tabenv"), (t_newmethod)tabenv_new, + (t_method)tabenv_ff, sizeof(t_tabenv), 0, A_DEFSYM, A_DEFFLOAT, A_DEFFLOAT, 0); + CLASS_MAINSIGNALIN(tabenv_class, t_tabenv, x_f); + class_addmethod(tabenv_class, (t_method)tabenv_reset, + gensym("reset"), 0); + class_addmethod(tabenv_class, (t_method)tabenv_set, + gensym("set"), A_DEFSYM, 0); + class_addlist(tabenv_class, tabenv_list); + +} + -- cgit v1.2.1