forked from len0rd/rockbox
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21626 a1c6a512-1295-4272-9138-f99709370657
788 lines
20 KiB
C
788 lines
20 KiB
C
/* 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. */
|
|
|
|
/* sig~ and line~ control-to-signal converters;
|
|
snapshot~ signal-to-control converter.
|
|
*/
|
|
|
|
#include "m_pd.h"
|
|
#include "math.h"
|
|
|
|
/* -------------------------- sig~ ------------------------------ */
|
|
static t_class *sig_tilde_class;
|
|
|
|
typedef struct _sig
|
|
{
|
|
t_object x_obj;
|
|
float x_f;
|
|
} t_sig;
|
|
|
|
static 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);
|
|
}
|
|
|
|
static 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
|
|
dsp_add(sig_tilde_perf8, 3, in, out, n);
|
|
}
|
|
|
|
static void sig_tilde_float(t_sig *x, t_float f)
|
|
{
|
|
x->x_f = f;
|
|
}
|
|
|
|
static void sig_tilde_dsp(t_sig *x, t_signal **sp)
|
|
{
|
|
dsp_add(sig_tilde_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n);
|
|
}
|
|
|
|
static void *sig_tilde_new(t_floatarg f)
|
|
{
|
|
t_sig *x = (t_sig *)pd_new(sig_tilde_class);
|
|
x->x_f = f;
|
|
outlet_new(&x->x_obj, gensym("signal"));
|
|
return (x);
|
|
}
|
|
|
|
#ifndef ROCKBOX
|
|
static
|
|
#endif
|
|
void sig_tilde_setup(void)
|
|
{
|
|
sig_tilde_class = class_new(gensym("sig~"), (t_newmethod)sig_tilde_new, 0,
|
|
sizeof(t_sig), 0, A_DEFFLOAT, 0);
|
|
class_addfloat(sig_tilde_class, (t_method)sig_tilde_float);
|
|
class_addmethod(sig_tilde_class, (t_method)sig_tilde_dsp, gensym("dsp"), 0);
|
|
}
|
|
|
|
|
|
#ifndef FIXEDPOINT
|
|
|
|
/* -------------------------- line~ ------------------------------ */
|
|
static t_class *line_tilde_class;
|
|
|
|
typedef struct _line
|
|
{
|
|
t_object x_obj;
|
|
float x_target;
|
|
float x_value;
|
|
float x_biginc;
|
|
float x_inc;
|
|
float x_1overn;
|
|
float x_dspticktomsec;
|
|
float x_inletvalue;
|
|
float x_inletwas;
|
|
int x_ticksleft;
|
|
int x_retarget;
|
|
} t_line;
|
|
|
|
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->x_value;
|
|
|
|
if (PD_BIGORSMALL(f))
|
|
x->x_value = f = 0;
|
|
if (x->x_retarget)
|
|
{
|
|
int nticks = x->x_inletwas * x->x_dspticktomsec;
|
|
if (!nticks) nticks = 1;
|
|
x->x_ticksleft = nticks;
|
|
x->x_biginc = (x->x_target - x->x_value)/(float)nticks;
|
|
x->x_inc = x->x_1overn * x->x_biginc;
|
|
x->x_retarget = 0;
|
|
}
|
|
if (x->x_ticksleft)
|
|
{
|
|
float f = x->x_value;
|
|
while (n--) *out++ = f, f += x->x_inc;
|
|
x->x_value += x->x_biginc;
|
|
x->x_ticksleft--;
|
|
}
|
|
else
|
|
{
|
|
x->x_value = x->x_target;
|
|
while (n--) *out++ = x->x_value;
|
|
}
|
|
return (w+4);
|
|
}
|
|
|
|
static void line_tilde_float(t_line *x, t_float f)
|
|
{
|
|
if (x->x_inletvalue <= 0)
|
|
{
|
|
x->x_target = x->x_value = f;
|
|
x->x_ticksleft = x->x_retarget = 0;
|
|
}
|
|
else
|
|
{
|
|
x->x_target = f;
|
|
x->x_retarget = 1;
|
|
x->x_inletwas = x->x_inletvalue;
|
|
x->x_inletvalue = 0;
|
|
}
|
|
}
|
|
|
|
static void line_tilde_stop(t_line *x)
|
|
{
|
|
x->x_target = x->x_value;
|
|
x->x_ticksleft = x->x_retarget = 0;
|
|
}
|
|
|
|
static void line_tilde_dsp(t_line *x, t_signal **sp)
|
|
{
|
|
dsp_add(line_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
|
|
x->x_1overn = 1./sp[0]->s_n;
|
|
x->x_dspticktomsec = sp[0]->s_sr / (1000 * sp[0]->s_n);
|
|
}
|
|
|
|
static void *line_tilde_new(void)
|
|
{
|
|
t_line *x = (t_line *)pd_new(line_tilde_class);
|
|
outlet_new(&x->x_obj, gensym("signal"));
|
|
floatinlet_new(&x->x_obj, &x->x_inletvalue);
|
|
x->x_ticksleft = x->x_retarget = 0;
|
|
x->x_value = x->x_target = x->x_inletvalue = x->x_inletwas = 0;
|
|
return (x);
|
|
}
|
|
|
|
static void line_tilde_setup(void)
|
|
{
|
|
line_tilde_class = class_new(gensym("line~"), line_tilde_new, 0,
|
|
sizeof(t_line), 0, 0);
|
|
class_addfloat(line_tilde_class, (t_method)line_tilde_float);
|
|
class_addmethod(line_tilde_class, (t_method)line_tilde_dsp,
|
|
gensym("dsp"), 0);
|
|
class_addmethod(line_tilde_class, (t_method)line_tilde_stop,
|
|
gensym("stop"), 0);
|
|
}
|
|
|
|
/* -------------------------- vline~ ------------------------------ */
|
|
static t_class *vline_tilde_class;
|
|
|
|
typedef struct _vseg
|
|
{
|
|
double s_targettime;
|
|
double s_starttime;
|
|
float s_target;
|
|
struct _vseg *s_next;
|
|
} t_vseg;
|
|
|
|
typedef struct _vline
|
|
{
|
|
t_object x_obj;
|
|
double x_value;
|
|
double x_inc;
|
|
double x_referencetime;
|
|
double x_samppermsec;
|
|
double x_msecpersamp;
|
|
double x_targettime;
|
|
float x_target;
|
|
float x_inlet1;
|
|
float x_inlet2;
|
|
t_vseg *x_list;
|
|
} t_vline;
|
|
|
|
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->x_value;
|
|
double inc = x->x_inc;
|
|
double msecpersamp = x->x_msecpersamp;
|
|
double samppermsec = x->x_samppermsec;
|
|
double timenow = clock_gettimesince(x->x_referencetime) - n * msecpersamp;
|
|
t_vseg *s = x->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->x_targettime <= timenext)
|
|
f = x->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->x_inc = inc;
|
|
x->x_target = s->s_target;
|
|
x->x_targettime = s->s_targettime;
|
|
x->x_list = s->s_next;
|
|
t_freebytes(s, sizeof(*s));
|
|
s = x->x_list;
|
|
goto checknext;
|
|
}
|
|
}
|
|
if (x->x_targettime <= timenext)
|
|
f = x->x_target, inc = x->x_inc = 0, x->x_targettime = 1e20;
|
|
*out++ = f;
|
|
f = f + inc;
|
|
timenow = timenext;
|
|
}
|
|
x->x_value = f;
|
|
return (w+4);
|
|
}
|
|
|
|
static void vline_tilde_stop(t_vline *x)
|
|
{
|
|
t_vseg *s1, *s2;
|
|
for (s1 = x->x_list; s1; s1 = s2)
|
|
s2 = s1->s_next, t_freebytes(s1, sizeof(*s1));
|
|
x->x_list = 0;
|
|
x->x_inc = 0;
|
|
x->x_inlet1 = x->x_inlet2 = 0;
|
|
x->x_target = x->x_value;
|
|
x->x_targettime = 1e20;
|
|
}
|
|
|
|
static void vline_tilde_float(t_vline *x, t_float f)
|
|
{
|
|
double timenow = clock_gettimesince(x->x_referencetime);
|
|
float inlet1 = (x->x_inlet1 < 0 ? 0 : x->x_inlet1);
|
|
float inlet2 = x->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->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->x_list || x->x_list->s_starttime > starttime ||
|
|
(x->x_list->s_starttime == starttime &&
|
|
(x->x_list->s_targettime > x->x_list->s_starttime || inlet1 <= 0)))
|
|
{
|
|
deletefrom = x->x_list;
|
|
x->x_list = snew;
|
|
}
|
|
else
|
|
{
|
|
for (s1 = x->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;
|
|
t_freebytes(deletefrom, sizeof(*deletefrom));
|
|
deletefrom = s1;
|
|
}
|
|
snew->s_next = 0;
|
|
snew->s_target = f;
|
|
snew->s_starttime = starttime;
|
|
snew->s_targettime = starttime + inlet1;
|
|
x->x_inlet1 = x->x_inlet2 = 0;
|
|
}
|
|
|
|
static void vline_tilde_dsp(t_vline *x, t_signal **sp)
|
|
{
|
|
dsp_add(vline_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
|
|
x->x_samppermsec = ((double)(sp[0]->s_sr)) / 1000;
|
|
x->x_msecpersamp = ((double)1000) / sp[0]->s_sr;
|
|
}
|
|
|
|
static void *vline_tilde_new(void)
|
|
{
|
|
t_vline *x = (t_vline *)pd_new(vline_tilde_class);
|
|
outlet_new(&x->x_obj, gensym("signal"));
|
|
floatinlet_new(&x->x_obj, &x->x_inlet1);
|
|
floatinlet_new(&x->x_obj, &x->x_inlet2);
|
|
x->x_inlet1 = x->x_inlet2 = 0;
|
|
x->x_value = x->x_inc = 0;
|
|
x->x_referencetime = clock_getlogicaltime();
|
|
x->x_list = 0;
|
|
x->x_samppermsec = 0;
|
|
x->x_targettime = 1e20;
|
|
return (x);
|
|
}
|
|
|
|
static void vline_tilde_setup(void)
|
|
{
|
|
vline_tilde_class = class_new(gensym("vline~"), vline_tilde_new,
|
|
(t_method)vline_tilde_stop, sizeof(t_vline), 0, 0);
|
|
class_addfloat(vline_tilde_class, (t_method)vline_tilde_float);
|
|
class_addmethod(vline_tilde_class, (t_method)vline_tilde_dsp,
|
|
gensym("dsp"), 0);
|
|
class_addmethod(vline_tilde_class, (t_method)vline_tilde_stop,
|
|
gensym("stop"), 0);
|
|
}
|
|
|
|
/* -------------------------- snapshot~ ------------------------------ */
|
|
static t_class *snapshot_tilde_class;
|
|
|
|
typedef struct _snapshot
|
|
{
|
|
t_object x_obj;
|
|
t_sample x_value;
|
|
float x_f;
|
|
} t_snapshot;
|
|
|
|
static void *snapshot_tilde_new(void)
|
|
{
|
|
t_snapshot *x = (t_snapshot *)pd_new(snapshot_tilde_class);
|
|
x->x_value = 0;
|
|
outlet_new(&x->x_obj, &s_float);
|
|
x->x_f = 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]->s_vec + (sp[0]->s_n-1),
|
|
&x->x_value);
|
|
}
|
|
|
|
static void snapshot_tilde_bang(t_snapshot *x)
|
|
{
|
|
outlet_float(x->x_obj.ob_outlet, x->x_value);
|
|
}
|
|
|
|
static void snapshot_tilde_set(t_snapshot *x, t_floatarg f)
|
|
{
|
|
x->x_value = f;
|
|
}
|
|
|
|
static void snapshot_tilde_setup(void)
|
|
{
|
|
snapshot_tilde_class = class_new(gensym("snapshot~"), snapshot_tilde_new, 0,
|
|
sizeof(t_snapshot), 0, 0);
|
|
CLASS_MAINSIGNALIN(snapshot_tilde_class, t_snapshot, x_f);
|
|
class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_dsp,
|
|
gensym("dsp"), 0);
|
|
class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_set,
|
|
gensym("set"), A_DEFFLOAT, 0);
|
|
class_addbang(snapshot_tilde_class, snapshot_tilde_bang);
|
|
}
|
|
|
|
/* -------------------------- vsnapshot~ ------------------------------ */
|
|
static t_class *vsnapshot_tilde_class;
|
|
|
|
typedef struct _vsnapshot
|
|
{
|
|
t_object x_obj;
|
|
int x_n;
|
|
int x_gotone;
|
|
t_sample *x_vec;
|
|
float x_f;
|
|
float x_sampspermsec;
|
|
double x_time;
|
|
} t_vsnapshot;
|
|
|
|
static void *vsnapshot_tilde_new(void)
|
|
{
|
|
t_vsnapshot *x = (t_vsnapshot *)pd_new(vsnapshot_tilde_class);
|
|
outlet_new(&x->x_obj, &s_float);
|
|
x->x_f = 0;
|
|
x->x_n = 0;
|
|
x->x_vec = 0;
|
|
x->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->x_vec;
|
|
int n = x->x_n, i;
|
|
for (i = 0; i < n; i++)
|
|
out[i] = in[i];
|
|
x->x_time = clock_getlogicaltime();
|
|
x->x_gotone = 1;
|
|
return (w+3);
|
|
}
|
|
|
|
static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp)
|
|
{
|
|
int n = sp[0]->s_n;
|
|
if (n != x->x_n)
|
|
{
|
|
if (x->x_vec)
|
|
t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
|
|
x->x_vec = (t_sample *)getbytes(n * sizeof(t_sample));
|
|
x->x_gotone = 0;
|
|
x->x_n = n;
|
|
}
|
|
x->x_sampspermsec = sp[0]->s_sr / 1000;
|
|
dsp_add(vsnapshot_tilde_perform, 2, sp[0]->s_vec, x);
|
|
}
|
|
|
|
static void vsnapshot_tilde_bang(t_vsnapshot *x)
|
|
{
|
|
float val;
|
|
if (x->x_gotone)
|
|
{
|
|
int indx = clock_gettimesince(x->x_time) * x->x_sampspermsec;
|
|
if (indx < 0)
|
|
indx = 0;
|
|
else if (indx >= x->x_n)
|
|
indx = x->x_n - 1;
|
|
val = x->x_vec[indx];
|
|
}
|
|
else val = 0;
|
|
outlet_float(x->x_obj.ob_outlet, val);
|
|
}
|
|
|
|
static void vsnapshot_tilde_ff(t_vsnapshot *x)
|
|
{
|
|
if (x->x_vec)
|
|
t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
|
|
}
|
|
|
|
static void vsnapshot_tilde_setup(void)
|
|
{
|
|
vsnapshot_tilde_class = class_new(gensym("vsnapshot~"),
|
|
vsnapshot_tilde_new, (t_method)vsnapshot_tilde_ff,
|
|
sizeof(t_vsnapshot), 0, 0);
|
|
CLASS_MAINSIGNALIN(vsnapshot_tilde_class, t_vsnapshot, x_f);
|
|
class_addmethod(vsnapshot_tilde_class, (t_method)vsnapshot_tilde_dsp, gensym("dsp"), 0);
|
|
class_addbang(vsnapshot_tilde_class, vsnapshot_tilde_bang);
|
|
}
|
|
|
|
|
|
/* ---------------- env~ - simple envelope follower. ----------------- */
|
|
|
|
#define MAXOVERLAP 10
|
|
#define MAXVSTAKEN 64
|
|
|
|
typedef struct sigenv
|
|
{
|
|
t_object x_obj; /* header */
|
|
void *x_outlet; /* a "float" outlet */
|
|
void *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;
|
|
} t_sigenv;
|
|
|
|
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 = fnpoints;
|
|
int period = fperiod;
|
|
t_sigenv *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_sigenv *)pd_new(env_tilde_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)env_tilde_tick);
|
|
x->x_outlet = outlet_new(&x->x_obj, gensym("float"));
|
|
x->x_f = 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]);
|
|
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 void env_tilde_dsp(t_sigenv *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(env_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
|
|
if (sp[0]->s_n > MAXVSTAKEN) bug("env_tilde_dsp");
|
|
}
|
|
|
|
static void env_tilde_tick(t_sigenv *x) /* callback function for the clock */
|
|
{
|
|
outlet_float(x->x_outlet, powtodb(x->x_result));
|
|
}
|
|
|
|
static void env_tilde_ff(t_sigenv *x) /* cleanup on free */
|
|
{
|
|
clock_free(x->x_clock);
|
|
freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float));
|
|
}
|
|
|
|
|
|
void env_tilde_setup(void )
|
|
{
|
|
env_tilde_class = class_new(gensym("env~"), (t_newmethod)env_tilde_new,
|
|
(t_method)env_tilde_ff, sizeof(t_sigenv), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
|
|
CLASS_MAINSIGNALIN(env_tilde_class, t_sigenv, x_f);
|
|
class_addmethod(env_tilde_class, (t_method)env_tilde_dsp, gensym("dsp"), 0);
|
|
}
|
|
|
|
/* --------------------- threshold~ ----------------------------- */
|
|
|
|
static t_class *threshold_tilde_class;
|
|
|
|
typedef struct _threshold_tilde
|
|
{
|
|
t_object x_obj;
|
|
t_outlet *x_outlet1; /* bang out for high thresh */
|
|
t_outlet *x_outlet2; /* bang out for low thresh */
|
|
t_clock *x_clock; /* wakeup for message output */
|
|
float x_f; /* scalar inlet */
|
|
int x_state; /* 1 = high, 0 = low */
|
|
float x_hithresh; /* value of high threshold */
|
|
float x_lothresh; /* value of low threshold */
|
|
float x_deadwait; /* msec remaining in dead period */
|
|
float x_msecpertick; /* msec per DSP tick */
|
|
float x_hideadtime; /* hi dead time in msec */
|
|
float x_lodeadtime; /* lo dead time in msec */
|
|
} t_threshold_tilde;
|
|
|
|
static void threshold_tilde_tick(t_threshold_tilde *x);
|
|
static void threshold_tilde_set(t_threshold_tilde *x,
|
|
t_floatarg hithresh, t_floatarg hideadtime,
|
|
t_floatarg lothresh, t_floatarg 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->x_state = 0; /* low state */
|
|
x->x_deadwait = 0; /* no dead time */
|
|
x->x_clock = clock_new(x, (t_method)threshold_tilde_tick);
|
|
x->x_outlet1 = outlet_new(&x->x_obj, &s_bang);
|
|
x->x_outlet2 = outlet_new(&x->x_obj, &s_bang);
|
|
inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
|
|
x->x_msecpertick = 0.;
|
|
x->x_f = 0;
|
|
threshold_tilde_set(x, hithresh, hideadtime, lothresh, lodeadtime);
|
|
return (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->x_hithresh = hithresh;
|
|
x->x_hideadtime = hideadtime;
|
|
x->x_lothresh = lothresh;
|
|
x->x_lodeadtime = lodeadtime;
|
|
}
|
|
|
|
/* 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->x_state = (f != 0);
|
|
x->x_deadwait = 0;
|
|
}
|
|
|
|
static void threshold_tilde_tick(t_threshold_tilde *x)
|
|
{
|
|
if (x->x_state)
|
|
outlet_bang(x->x_outlet1);
|
|
else outlet_bang(x->x_outlet2);
|
|
}
|
|
|
|
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->x_deadwait > 0)
|
|
x->x_deadwait -= x->x_msecpertick;
|
|
else if (x->x_state)
|
|
{
|
|
/* we're high; look for low sample */
|
|
for (; n--; in1++)
|
|
{
|
|
if (*in1 < x->x_lothresh)
|
|
{
|
|
clock_delay(x->x_clock, 0L);
|
|
x->x_state = 0;
|
|
x->x_deadwait = x->x_lodeadtime;
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* we're low; look for high sample */
|
|
for (; n--; in1++)
|
|
{
|
|
if (*in1 >= x->x_hithresh)
|
|
{
|
|
clock_delay(x->x_clock, 0L);
|
|
x->x_state = 1;
|
|
x->x_deadwait = x->x_hideadtime;
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
done:
|
|
return (w+4);
|
|
}
|
|
|
|
void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp)
|
|
{
|
|
x->x_msecpertick = 1000. * sp[0]->s_n / sp[0]->s_sr;
|
|
dsp_add(threshold_tilde_perform, 3, sp[0]->s_vec, x, sp[0]->s_n);
|
|
}
|
|
|
|
static void threshold_tilde_ff(t_threshold_tilde *x)
|
|
{
|
|
clock_free(x->x_clock);
|
|
}
|
|
|
|
static void threshold_tilde_setup( void)
|
|
{
|
|
threshold_tilde_class = class_new(gensym("threshold~"),
|
|
(t_newmethod)threshold_tilde_new, (t_method)threshold_tilde_ff,
|
|
sizeof(t_threshold_tilde), 0,
|
|
A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
|
|
CLASS_MAINSIGNALIN(threshold_tilde_class, t_threshold_tilde, x_f);
|
|
class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_set,
|
|
gensym("set"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
|
|
class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_ft1,
|
|
gensym("ft1"), A_FLOAT, 0);
|
|
class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_dsp,
|
|
gensym("dsp"), 0);
|
|
}
|
|
|
|
/* ------------------------ global setup routine ------------------------- */
|
|
|
|
void d_ctl_setup(void)
|
|
{
|
|
sig_tilde_setup();
|
|
line_tilde_setup();
|
|
vline_tilde_setup();
|
|
snapshot_tilde_setup();
|
|
vsnapshot_tilde_setup();
|
|
env_tilde_setup();
|
|
threshold_tilde_setup();
|
|
}
|
|
|
|
#endif
|
|
|