aboutsummaryrefslogtreecommitdiff
path: root/tabenv.c
diff options
context:
space:
mode:
Diffstat (limited to 'tabenv.c')
-rw-r--r--tabenv.c294
1 files changed, 294 insertions, 0 deletions
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);
+
+}
+