/* * multiline~: interpolating signal multiplier * * (c) 1999-2011 IOhannes m zmölnig, forum::für::umläute, institute of electronic music and acoustics (iem) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ /* a multiline that MULTIplicates MULTIple signals with "ramped floats" (--> like "line~") this is kind of multiplying some streams with the square diagonal matrix : diag*~ for smooth-results we do this line~ thing 1403:forum::für::umläute:2001 */ /* i am not sure, whether there is a difference between loop-unrolling by hand or by compiler * i somehow have the feeling, that doing it by hand increases(!) performance for about 2% * anyhow, if you think that the compiler can do this job better, just disable the UNROLLED define below */ #define UNROLLED #include "zexy.h" /* --------------------------- multiline~ ---------------------------------- */ static t_class *mline_class; typedef struct _mline { t_object x_obj; t_float time; int ticksleft; int retarget; t_float msec2tick; t_sample *value; t_sample *target; t_sample *increment; /* single precision is really a bad */ t_sample **sigIN; t_sample **sigOUT; t_sample *sigBUF; int sigNUM; } t_mline; /* the message thing */ static void mline_list(t_mline *x, t_symbol* UNUSED(s), int argc, t_atom *argv) { if (argc>x->sigNUM)x->time=atom_getfloat(argv+argc-1); if (x->time <= 0) { if (argc==1) { t_float f = atom_getfloat(argv); int i=x->sigNUM; while(i--)x->target[i]=x->value[i]=f; } else { int offset = (argcsigNUM)?x->sigNUM-argc:0; int i=offset?argc:x->sigNUM; while(i--)x->target[i+offset]=x->value[i+offset]=atom_getfloat(argv++); } x->ticksleft=x->retarget=x->time=0; } else { if (argc==1) { int i = x->sigNUM; t_float f = atom_getfloat(argv); for(i=0;isigNUM;i++)x->target[i]=f; } else { int offset = (argcsigNUM)?x->sigNUM-argc:0; int i=offset?argc:x->sigNUM; while(i--)x->target[i+offset]=atom_getfloat(argv++); } x->retarget = 1; } } static void mline_stop(t_mline *x) { int i = x->sigNUM; while (i--) x->target[i] = x->value[i]; x->ticksleft = x->retarget = 0; } /* the dsp thing */ static t_int *mline_perform(t_int *w) { t_mline *x = (t_mline *)(w[1]); int n = (int)(w[2]); t_sample **out = x->sigOUT; t_sample **in = x->sigIN; t_sample *buf = x->sigBUF, *sigBUF = buf; t_sample *inc = x->increment, *increment = inc; t_sample *val = x->value, *value = val; t_sample *tgt = x->target, *target = tgt; int sigNUM = x->sigNUM; if (x->retarget) { int nticks = x->time * x->msec2tick; if (!nticks) nticks = 1; x->ticksleft = nticks; x->retarget = 0; } if (x->ticksleft) { int N=n-1; t_sample oneovernos = 1./(x->ticksleft*n); int i=sigNUM; while(i--)*inc++=(*tgt++-*val++)*oneovernos; n=-1; while (n++ticksleft) { val = value; tgt = target; i = sigNUM; while(i--)*val++=*tgt++; } } else { /* no ticks left */ int i = sigNUM; while (n--) { i = sigNUM; val = value; buf = sigBUF; while (i--)*buf++=in[i][n]**val++; i = sigNUM; buf = sigBUF; while (i--)out[i][n]=*buf++; } } return (w+3); } static void mline_dsp(t_mline *x, t_signal **sp) { int i = x->sigNUM, n = 0; t_sample **dummy = x->sigIN; while(i--)*dummy++=sp[n++]->s_vec; i = x->sigNUM; dummy =x->sigOUT; while(i--)*dummy++=sp[n++]->s_vec; x->msec2tick = sp[0]->s_sr / (1000.f * sp[0]->s_n); dsp_add(mline_perform, 2, x, sp[0]->s_n); } /* setup/setdown things */ static void mline_free(t_mline *x) { freebytes(x->value, sizeof(x->value)); freebytes(x->target, sizeof(x->target)); freebytes(x->increment, sizeof(x->increment)); freebytes(x->sigIN, sizeof(x->sigIN)); freebytes(x->sigOUT, sizeof(x->sigOUT)); freebytes(x->sigBUF, sizeof(x->sigBUF)); } static void *mline_new(t_symbol* UNUSED(s), int argc, t_atom *argv) { t_mline *x = (t_mline *)pd_new(mline_class); int i; if (!argc) { argc = 1; x->time = 0; } else { x->time = atom_getfloat(argv+argc-1); if (x->time < 0) x->time = 0; argc--; if (!argc) argc = 1; } x->sigNUM = argc; i = argc-1; outlet_new(&x->x_obj, gensym("signal")); while (i--) { inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("signal"), gensym("signal")); outlet_new(&x->x_obj, gensym("signal")); } inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("")); floatinlet_new(&x->x_obj, &x->time); x->sigIN = (t_sample **)getbytes(x->sigNUM * sizeof(t_sample **)); x->sigOUT = (t_sample **)getbytes(x->sigNUM * sizeof(t_sample **)); x->sigBUF = (t_sample *)getbytes(x->sigNUM * sizeof(t_sample *)); x->value = (t_sample *)getbytes(x->sigNUM * sizeof(t_sample *)); x->target = (t_sample *)getbytes(x->sigNUM * sizeof(t_sample *)); x->increment = (t_sample *)getbytes(x->sigNUM * sizeof(t_sample *)); i = x->sigNUM; while (i--) { x->sigIN[i] = x->sigOUT[i] = 0; x->increment[i] = 0; x->value[x->sigNUM-i-1] = x->target[x->sigNUM-i-1] = atom_getfloat(argv+i); } x->msec2tick = x->ticksleft = x->retarget = 0; return (x); } static void mline_help(t_mline*x) { post("\n"HEARTSYMBOL" multiline~\t:: ramped multiplication of multiple signals"); } void multiline_tilde_setup(void) { mline_class = class_new(gensym("multiline~"), (t_newmethod)mline_new, (t_method)mline_free, sizeof(t_mline), 0, A_GIMME, 0); class_addmethod(mline_class, (t_method)mline_dsp, gensym("dsp"), 0); class_addmethod(mline_class, nullfn, gensym("signal"), 0); class_addmethod(mline_class, (t_method)mline_list, gensym(""), A_GIMME, 0); class_addmethod(mline_class, (t_method)mline_stop, gensym("stop"), 0); class_addmethod (mline_class, (t_method)mline_help, gensym("help"), A_NULL); zexy_register("multiline_tilde"); }