Add FS #10214. Initial commit of the original PDa code for the GSoC Pure Data plugin...
[kugel-rb.git] / apps / plugins / pdbox / PDa / src / d_ctl.c
blobd3262af80043317fdf1d3a51d2a4841fa269ca87
1 /* Copyright (c) 1997-1999 Miller Puckette.
2 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
3 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
5 /* sig~ and line~ control-to-signal converters;
6 snapshot~ signal-to-control converter.
7 */
9 #include "m_pd.h"
10 #include "math.h"
12 /* -------------------------- sig~ ------------------------------ */
13 static t_class *sig_tilde_class;
15 typedef struct _sig
17 t_object x_obj;
18 float x_f;
19 } t_sig;
21 static t_int *sig_tilde_perform(t_int *w)
23 t_float f = *(t_float *)(w[1]);
24 t_float *out = (t_float *)(w[2]);
25 int n = (int)(w[3]);
26 while (n--)
27 *out++ = f;
28 return (w+4);
31 static t_int *sig_tilde_perf8(t_int *w)
33 t_float f = *(t_float *)(w[1]);
34 t_float *out = (t_float *)(w[2]);
35 int n = (int)(w[3]);
37 for (; n; n -= 8, out += 8)
39 out[0] = f;
40 out[1] = f;
41 out[2] = f;
42 out[3] = f;
43 out[4] = f;
44 out[5] = f;
45 out[6] = f;
46 out[7] = f;
48 return (w+4);
51 void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n)
53 if (n&7)
54 dsp_add(sig_tilde_perform, 3, in, out, n);
55 else
56 dsp_add(sig_tilde_perf8, 3, in, out, n);
59 static void sig_tilde_float(t_sig *x, t_float f)
61 x->x_f = f;
64 static void sig_tilde_dsp(t_sig *x, t_signal **sp)
66 dsp_add(sig_tilde_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n);
69 static void *sig_tilde_new(t_floatarg f)
71 t_sig *x = (t_sig *)pd_new(sig_tilde_class);
72 x->x_f = f;
73 outlet_new(&x->x_obj, gensym("signal"));
74 return (x);
77 static void sig_tilde_setup(void)
79 sig_tilde_class = class_new(gensym("sig~"), (t_newmethod)sig_tilde_new, 0,
80 sizeof(t_sig), 0, A_DEFFLOAT, 0);
81 class_addfloat(sig_tilde_class, (t_method)sig_tilde_float);
82 class_addmethod(sig_tilde_class, (t_method)sig_tilde_dsp, gensym("dsp"), 0);
86 #ifndef FIXEDPOINT
88 /* -------------------------- line~ ------------------------------ */
89 static t_class *line_tilde_class;
91 typedef struct _line
93 t_object x_obj;
94 float x_target;
95 float x_value;
96 float x_biginc;
97 float x_inc;
98 float x_1overn;
99 float x_dspticktomsec;
100 float x_inletvalue;
101 float x_inletwas;
102 int x_ticksleft;
103 int x_retarget;
104 } t_line;
106 static t_int *line_tilde_perform(t_int *w)
108 t_line *x = (t_line *)(w[1]);
109 t_float *out = (t_float *)(w[2]);
110 int n = (int)(w[3]);
111 float f = x->x_value;
113 if (PD_BIGORSMALL(f))
114 x->x_value = f = 0;
115 if (x->x_retarget)
117 int nticks = x->x_inletwas * x->x_dspticktomsec;
118 if (!nticks) nticks = 1;
119 x->x_ticksleft = nticks;
120 x->x_biginc = (x->x_target - x->x_value)/(float)nticks;
121 x->x_inc = x->x_1overn * x->x_biginc;
122 x->x_retarget = 0;
124 if (x->x_ticksleft)
126 float f = x->x_value;
127 while (n--) *out++ = f, f += x->x_inc;
128 x->x_value += x->x_biginc;
129 x->x_ticksleft--;
131 else
133 x->x_value = x->x_target;
134 while (n--) *out++ = x->x_value;
136 return (w+4);
139 static void line_tilde_float(t_line *x, t_float f)
141 if (x->x_inletvalue <= 0)
143 x->x_target = x->x_value = f;
144 x->x_ticksleft = x->x_retarget = 0;
146 else
148 x->x_target = f;
149 x->x_retarget = 1;
150 x->x_inletwas = x->x_inletvalue;
151 x->x_inletvalue = 0;
155 static void line_tilde_stop(t_line *x)
157 x->x_target = x->x_value;
158 x->x_ticksleft = x->x_retarget = 0;
161 static void line_tilde_dsp(t_line *x, t_signal **sp)
163 dsp_add(line_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
164 x->x_1overn = 1./sp[0]->s_n;
165 x->x_dspticktomsec = sp[0]->s_sr / (1000 * sp[0]->s_n);
168 static void *line_tilde_new(void)
170 t_line *x = (t_line *)pd_new(line_tilde_class);
171 outlet_new(&x->x_obj, gensym("signal"));
172 floatinlet_new(&x->x_obj, &x->x_inletvalue);
173 x->x_ticksleft = x->x_retarget = 0;
174 x->x_value = x->x_target = x->x_inletvalue = x->x_inletwas = 0;
175 return (x);
178 static void line_tilde_setup(void)
180 line_tilde_class = class_new(gensym("line~"), line_tilde_new, 0,
181 sizeof(t_line), 0, 0);
182 class_addfloat(line_tilde_class, (t_method)line_tilde_float);
183 class_addmethod(line_tilde_class, (t_method)line_tilde_dsp,
184 gensym("dsp"), 0);
185 class_addmethod(line_tilde_class, (t_method)line_tilde_stop,
186 gensym("stop"), 0);
189 /* -------------------------- vline~ ------------------------------ */
190 static t_class *vline_tilde_class;
192 typedef struct _vseg
194 double s_targettime;
195 double s_starttime;
196 float s_target;
197 struct _vseg *s_next;
198 } t_vseg;
200 typedef struct _vline
202 t_object x_obj;
203 double x_value;
204 double x_inc;
205 double x_referencetime;
206 double x_samppermsec;
207 double x_msecpersamp;
208 double x_targettime;
209 float x_target;
210 float x_inlet1;
211 float x_inlet2;
212 t_vseg *x_list;
213 } t_vline;
215 static t_int *vline_tilde_perform(t_int *w)
217 t_vline *x = (t_vline *)(w[1]);
218 t_float *out = (t_float *)(w[2]);
219 int n = (int)(w[3]), i;
220 double f = x->x_value;
221 double inc = x->x_inc;
222 double msecpersamp = x->x_msecpersamp;
223 double samppermsec = x->x_samppermsec;
224 double timenow = clock_gettimesince(x->x_referencetime) - n * msecpersamp;
225 t_vseg *s = x->x_list;
226 for (i = 0; i < n; i++)
228 double timenext = timenow + msecpersamp;
229 checknext:
230 if (s)
232 /* has starttime elapsed? If so update value and increment */
233 if (s->s_starttime < timenext)
235 if (x->x_targettime <= timenext)
236 f = x->x_target, inc = 0;
237 /* if zero-length segment bash output value */
238 if (s->s_targettime <= s->s_starttime)
240 f = s->s_target;
241 inc = 0;
243 else
245 double incpermsec = (s->s_target - f)/
246 (s->s_targettime - s->s_starttime);
247 f = f + incpermsec * (timenext - s->s_starttime);
248 inc = incpermsec * msecpersamp;
250 x->x_inc = inc;
251 x->x_target = s->s_target;
252 x->x_targettime = s->s_targettime;
253 x->x_list = s->s_next;
254 t_freebytes(s, sizeof(*s));
255 s = x->x_list;
256 goto checknext;
259 if (x->x_targettime <= timenext)
260 f = x->x_target, inc = x->x_inc = 0, x->x_targettime = 1e20;
261 *out++ = f;
262 f = f + inc;
263 timenow = timenext;
265 x->x_value = f;
266 return (w+4);
269 static void vline_tilde_stop(t_vline *x)
271 t_vseg *s1, *s2;
272 for (s1 = x->x_list; s1; s1 = s2)
273 s2 = s1->s_next, t_freebytes(s1, sizeof(*s1));
274 x->x_list = 0;
275 x->x_inc = 0;
276 x->x_inlet1 = x->x_inlet2 = 0;
277 x->x_target = x->x_value;
278 x->x_targettime = 1e20;
281 static void vline_tilde_float(t_vline *x, t_float f)
283 double timenow = clock_gettimesince(x->x_referencetime);
284 float inlet1 = (x->x_inlet1 < 0 ? 0 : x->x_inlet1);
285 float inlet2 = x->x_inlet2;
286 double starttime = timenow + inlet2;
287 t_vseg *s1, *s2, *deletefrom = 0, *snew;
288 if (PD_BIGORSMALL(f))
289 f = 0;
291 /* negative delay input means stop and jump immediately to new value */
292 if (inlet2 < 0)
294 x->x_value = f;
295 vline_tilde_stop(x);
296 return;
298 snew = (t_vseg *)t_getbytes(sizeof(*snew));
299 /* check if we supplant the first item in the list. We supplant
300 an item by having an earlier starttime, or an equal starttime unless
301 the equal one was instantaneous and the new one isn't (in which case
302 we'll do a jump-and-slide starting at that time.) */
303 if (!x->x_list || x->x_list->s_starttime > starttime ||
304 (x->x_list->s_starttime == starttime &&
305 (x->x_list->s_targettime > x->x_list->s_starttime || inlet1 <= 0)))
307 deletefrom = x->x_list;
308 x->x_list = snew;
310 else
312 for (s1 = x->x_list; s2 = s1->s_next; s1 = s2)
314 if (s2->s_starttime > starttime ||
315 (s2->s_starttime == starttime &&
316 (s2->s_targettime > s2->s_starttime || inlet1 <= 0)))
318 deletefrom = s2;
319 s1->s_next = snew;
320 goto didit;
323 s1->s_next = snew;
324 deletefrom = 0;
325 didit: ;
327 while (deletefrom)
329 s1 = deletefrom->s_next;
330 t_freebytes(deletefrom, sizeof(*deletefrom));
331 deletefrom = s1;
333 snew->s_next = 0;
334 snew->s_target = f;
335 snew->s_starttime = starttime;
336 snew->s_targettime = starttime + inlet1;
337 x->x_inlet1 = x->x_inlet2 = 0;
340 static void vline_tilde_dsp(t_vline *x, t_signal **sp)
342 dsp_add(vline_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
343 x->x_samppermsec = ((double)(sp[0]->s_sr)) / 1000;
344 x->x_msecpersamp = ((double)1000) / sp[0]->s_sr;
347 static void *vline_tilde_new(void)
349 t_vline *x = (t_vline *)pd_new(vline_tilde_class);
350 outlet_new(&x->x_obj, gensym("signal"));
351 floatinlet_new(&x->x_obj, &x->x_inlet1);
352 floatinlet_new(&x->x_obj, &x->x_inlet2);
353 x->x_inlet1 = x->x_inlet2 = 0;
354 x->x_value = x->x_inc = 0;
355 x->x_referencetime = clock_getlogicaltime();
356 x->x_list = 0;
357 x->x_samppermsec = 0;
358 x->x_targettime = 1e20;
359 return (x);
362 static void vline_tilde_setup(void)
364 vline_tilde_class = class_new(gensym("vline~"), vline_tilde_new,
365 (t_method)vline_tilde_stop, sizeof(t_vline), 0, 0);
366 class_addfloat(vline_tilde_class, (t_method)vline_tilde_float);
367 class_addmethod(vline_tilde_class, (t_method)vline_tilde_dsp,
368 gensym("dsp"), 0);
369 class_addmethod(vline_tilde_class, (t_method)vline_tilde_stop,
370 gensym("stop"), 0);
373 /* -------------------------- snapshot~ ------------------------------ */
374 static t_class *snapshot_tilde_class;
376 typedef struct _snapshot
378 t_object x_obj;
379 t_sample x_value;
380 float x_f;
381 } t_snapshot;
383 static void *snapshot_tilde_new(void)
385 t_snapshot *x = (t_snapshot *)pd_new(snapshot_tilde_class);
386 x->x_value = 0;
387 outlet_new(&x->x_obj, &s_float);
388 x->x_f = 0;
389 return (x);
392 static t_int *snapshot_tilde_perform(t_int *w)
394 t_float *in = (t_float *)(w[1]);
395 t_float *out = (t_float *)(w[2]);
396 *out = *in;
397 return (w+3);
400 static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp)
402 dsp_add(snapshot_tilde_perform, 2, sp[0]->s_vec + (sp[0]->s_n-1),
403 &x->x_value);
406 static void snapshot_tilde_bang(t_snapshot *x)
408 outlet_float(x->x_obj.ob_outlet, x->x_value);
411 static void snapshot_tilde_set(t_snapshot *x, t_floatarg f)
413 x->x_value = f;
416 static void snapshot_tilde_setup(void)
418 snapshot_tilde_class = class_new(gensym("snapshot~"), snapshot_tilde_new, 0,
419 sizeof(t_snapshot), 0, 0);
420 CLASS_MAINSIGNALIN(snapshot_tilde_class, t_snapshot, x_f);
421 class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_dsp,
422 gensym("dsp"), 0);
423 class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_set,
424 gensym("set"), A_DEFFLOAT, 0);
425 class_addbang(snapshot_tilde_class, snapshot_tilde_bang);
428 /* -------------------------- vsnapshot~ ------------------------------ */
429 static t_class *vsnapshot_tilde_class;
431 typedef struct _vsnapshot
433 t_object x_obj;
434 int x_n;
435 int x_gotone;
436 t_sample *x_vec;
437 float x_f;
438 float x_sampspermsec;
439 double x_time;
440 } t_vsnapshot;
442 static void *vsnapshot_tilde_new(void)
444 t_vsnapshot *x = (t_vsnapshot *)pd_new(vsnapshot_tilde_class);
445 outlet_new(&x->x_obj, &s_float);
446 x->x_f = 0;
447 x->x_n = 0;
448 x->x_vec = 0;
449 x->x_gotone = 0;
450 return (x);
453 static t_int *vsnapshot_tilde_perform(t_int *w)
455 t_float *in = (t_float *)(w[1]);
456 t_vsnapshot *x = (t_vsnapshot *)(w[2]);
457 t_float *out = x->x_vec;
458 int n = x->x_n, i;
459 for (i = 0; i < n; i++)
460 out[i] = in[i];
461 x->x_time = clock_getlogicaltime();
462 x->x_gotone = 1;
463 return (w+3);
466 static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp)
468 int n = sp[0]->s_n;
469 if (n != x->x_n)
471 if (x->x_vec)
472 t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
473 x->x_vec = (t_sample *)getbytes(n * sizeof(t_sample));
474 x->x_gotone = 0;
475 x->x_n = n;
477 x->x_sampspermsec = sp[0]->s_sr / 1000;
478 dsp_add(vsnapshot_tilde_perform, 2, sp[0]->s_vec, x);
481 static void vsnapshot_tilde_bang(t_vsnapshot *x)
483 float val;
484 if (x->x_gotone)
486 int indx = clock_gettimesince(x->x_time) * x->x_sampspermsec;
487 if (indx < 0)
488 indx = 0;
489 else if (indx >= x->x_n)
490 indx = x->x_n - 1;
491 val = x->x_vec[indx];
493 else val = 0;
494 outlet_float(x->x_obj.ob_outlet, val);
497 static void vsnapshot_tilde_ff(t_vsnapshot *x)
499 if (x->x_vec)
500 t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
503 static void vsnapshot_tilde_setup(void)
505 vsnapshot_tilde_class = class_new(gensym("vsnapshot~"),
506 vsnapshot_tilde_new, (t_method)vsnapshot_tilde_ff,
507 sizeof(t_vsnapshot), 0, 0);
508 CLASS_MAINSIGNALIN(vsnapshot_tilde_class, t_vsnapshot, x_f);
509 class_addmethod(vsnapshot_tilde_class, (t_method)vsnapshot_tilde_dsp, gensym("dsp"), 0);
510 class_addbang(vsnapshot_tilde_class, vsnapshot_tilde_bang);
514 /* ---------------- env~ - simple envelope follower. ----------------- */
516 #define MAXOVERLAP 10
517 #define MAXVSTAKEN 64
519 typedef struct sigenv
521 t_object x_obj; /* header */
522 void *x_outlet; /* a "float" outlet */
523 void *x_clock; /* a "clock" object */
524 float *x_buf; /* a Hanning window */
525 int x_phase; /* number of points since last output */
526 int x_period; /* requested period of output */
527 int x_realperiod; /* period rounded up to vecsize multiple */
528 int x_npoints; /* analysis window size in samples */
529 float x_result; /* result to output */
530 float x_sumbuf[MAXOVERLAP]; /* summing buffer */
531 float x_f;
532 } t_sigenv;
534 t_class *env_tilde_class;
535 static void env_tilde_tick(t_sigenv *x);
537 static void *env_tilde_new(t_floatarg fnpoints, t_floatarg fperiod)
539 int npoints = fnpoints;
540 int period = fperiod;
541 t_sigenv *x;
542 float *buf;
543 int i;
545 if (npoints < 1) npoints = 1024;
546 if (period < 1) period = npoints/2;
547 if (period < npoints / MAXOVERLAP + 1)
548 period = npoints / MAXOVERLAP + 1;
549 if (!(buf = getbytes(sizeof(float) * (npoints + MAXVSTAKEN))))
551 error("env: couldn't allocate buffer");
552 return (0);
554 x = (t_sigenv *)pd_new(env_tilde_class);
555 x->x_buf = buf;
556 x->x_npoints = npoints;
557 x->x_phase = 0;
558 x->x_period = period;
559 for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
560 for (i = 0; i < npoints; i++)
561 buf[i] = (1. - cos((2 * 3.14159 * i) / npoints))/npoints;
562 for (; i < npoints+MAXVSTAKEN; i++) buf[i] = 0;
563 x->x_clock = clock_new(x, (t_method)env_tilde_tick);
564 x->x_outlet = outlet_new(&x->x_obj, gensym("float"));
565 x->x_f = 0;
566 return (x);
569 static t_int *env_tilde_perform(t_int *w)
571 t_sigenv *x = (t_sigenv *)(w[1]);
572 t_float *in = (t_float *)(w[2]);
573 int n = (int)(w[3]);
574 int count;
575 float *sump;
576 in += n;
577 for (count = x->x_phase, sump = x->x_sumbuf;
578 count < x->x_npoints; count += x->x_realperiod, sump++)
580 float *hp = x->x_buf + count;
581 float *fp = in;
582 float sum = *sump;
583 int i;
585 for (i = 0; i < n; i++)
587 fp--;
588 sum += *hp++ * (*fp * *fp);
590 *sump = sum;
592 sump[0] = 0;
593 x->x_phase -= n;
594 if (x->x_phase < 0)
596 x->x_result = x->x_sumbuf[0];
597 for (count = x->x_realperiod, sump = x->x_sumbuf;
598 count < x->x_npoints; count += x->x_realperiod, sump++)
599 sump[0] = sump[1];
600 sump[0] = 0;
601 x->x_phase = x->x_realperiod - n;
602 clock_delay(x->x_clock, 0L);
604 return (w+4);
607 static void env_tilde_dsp(t_sigenv *x, t_signal **sp)
609 if (x->x_period % sp[0]->s_n) x->x_realperiod =
610 x->x_period + sp[0]->s_n - (x->x_period % sp[0]->s_n);
611 else x->x_realperiod = x->x_period;
612 dsp_add(env_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
613 if (sp[0]->s_n > MAXVSTAKEN) bug("env_tilde_dsp");
616 static void env_tilde_tick(t_sigenv *x) /* callback function for the clock */
618 outlet_float(x->x_outlet, powtodb(x->x_result));
621 static void env_tilde_ff(t_sigenv *x) /* cleanup on free */
623 clock_free(x->x_clock);
624 freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float));
628 void env_tilde_setup(void )
630 env_tilde_class = class_new(gensym("env~"), (t_newmethod)env_tilde_new,
631 (t_method)env_tilde_ff, sizeof(t_sigenv), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
632 CLASS_MAINSIGNALIN(env_tilde_class, t_sigenv, x_f);
633 class_addmethod(env_tilde_class, (t_method)env_tilde_dsp, gensym("dsp"), 0);
636 /* --------------------- threshold~ ----------------------------- */
638 static t_class *threshold_tilde_class;
640 typedef struct _threshold_tilde
642 t_object x_obj;
643 t_outlet *x_outlet1; /* bang out for high thresh */
644 t_outlet *x_outlet2; /* bang out for low thresh */
645 t_clock *x_clock; /* wakeup for message output */
646 float x_f; /* scalar inlet */
647 int x_state; /* 1 = high, 0 = low */
648 float x_hithresh; /* value of high threshold */
649 float x_lothresh; /* value of low threshold */
650 float x_deadwait; /* msec remaining in dead period */
651 float x_msecpertick; /* msec per DSP tick */
652 float x_hideadtime; /* hi dead time in msec */
653 float x_lodeadtime; /* lo dead time in msec */
654 } t_threshold_tilde;
656 static void threshold_tilde_tick(t_threshold_tilde *x);
657 static void threshold_tilde_set(t_threshold_tilde *x,
658 t_floatarg hithresh, t_floatarg hideadtime,
659 t_floatarg lothresh, t_floatarg lodeadtime);
661 static t_threshold_tilde *threshold_tilde_new(t_floatarg hithresh,
662 t_floatarg hideadtime, t_floatarg lothresh, t_floatarg lodeadtime)
664 t_threshold_tilde *x = (t_threshold_tilde *)
665 pd_new(threshold_tilde_class);
666 x->x_state = 0; /* low state */
667 x->x_deadwait = 0; /* no dead time */
668 x->x_clock = clock_new(x, (t_method)threshold_tilde_tick);
669 x->x_outlet1 = outlet_new(&x->x_obj, &s_bang);
670 x->x_outlet2 = outlet_new(&x->x_obj, &s_bang);
671 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
672 x->x_msecpertick = 0.;
673 x->x_f = 0;
674 threshold_tilde_set(x, hithresh, hideadtime, lothresh, lodeadtime);
675 return (x);
678 /* "set" message to specify thresholds and dead times */
679 static void threshold_tilde_set(t_threshold_tilde *x,
680 t_floatarg hithresh, t_floatarg hideadtime,
681 t_floatarg lothresh, t_floatarg lodeadtime)
683 if (lothresh > hithresh)
684 lothresh = hithresh;
685 x->x_hithresh = hithresh;
686 x->x_hideadtime = hideadtime;
687 x->x_lothresh = lothresh;
688 x->x_lodeadtime = lodeadtime;
691 /* number in inlet sets state -- note incompatible with JMAX which used
692 "int" message for this, impossible here because of auto signal conversion */
693 static void threshold_tilde_ft1(t_threshold_tilde *x, t_floatarg f)
695 x->x_state = (f != 0);
696 x->x_deadwait = 0;
699 static void threshold_tilde_tick(t_threshold_tilde *x)
701 if (x->x_state)
702 outlet_bang(x->x_outlet1);
703 else outlet_bang(x->x_outlet2);
706 static t_int *threshold_tilde_perform(t_int *w)
708 float *in1 = (float *)(w[1]);
709 t_threshold_tilde *x = (t_threshold_tilde *)(w[2]);
710 int n = (t_int)(w[3]);
711 if (x->x_deadwait > 0)
712 x->x_deadwait -= x->x_msecpertick;
713 else if (x->x_state)
715 /* we're high; look for low sample */
716 for (; n--; in1++)
718 if (*in1 < x->x_lothresh)
720 clock_delay(x->x_clock, 0L);
721 x->x_state = 0;
722 x->x_deadwait = x->x_lodeadtime;
723 goto done;
727 else
729 /* we're low; look for high sample */
730 for (; n--; in1++)
732 if (*in1 >= x->x_hithresh)
734 clock_delay(x->x_clock, 0L);
735 x->x_state = 1;
736 x->x_deadwait = x->x_hideadtime;
737 goto done;
741 done:
742 return (w+4);
745 void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp)
747 x->x_msecpertick = 1000. * sp[0]->s_n / sp[0]->s_sr;
748 dsp_add(threshold_tilde_perform, 3, sp[0]->s_vec, x, sp[0]->s_n);
751 static void threshold_tilde_ff(t_threshold_tilde *x)
753 clock_free(x->x_clock);
756 static void threshold_tilde_setup( void)
758 threshold_tilde_class = class_new(gensym("threshold~"),
759 (t_newmethod)threshold_tilde_new, (t_method)threshold_tilde_ff,
760 sizeof(t_threshold_tilde), 0,
761 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
762 CLASS_MAINSIGNALIN(threshold_tilde_class, t_threshold_tilde, x_f);
763 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_set,
764 gensym("set"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
765 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_ft1,
766 gensym("ft1"), A_FLOAT, 0);
767 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_dsp,
768 gensym("dsp"), 0);
771 /* ------------------------ global setup routine ------------------------- */
773 void d_ctl_setup(void)
775 sig_tilde_setup();
776 line_tilde_setup();
777 vline_tilde_setup();
778 snapshot_tilde_setup();
779 vsnapshot_tilde_setup();
780 env_tilde_setup();
781 threshold_tilde_setup();
784 #endif
785 /* Copyright (c) 1997-1999 Miller Puckette.
786 * For information on usage and redistribution, and for a DISCLAIMER OF ALL
787 * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
789 /* sig~ and line~ control-to-signal converters;
790 snapshot~ signal-to-control converter.
793 #include "m_pd.h"
794 #include "math.h"
796 /* -------------------------- sig~ ------------------------------ */
797 static t_class *sig_tilde_class;
799 typedef struct _sig
801 t_object x_obj;
802 float x_f;
803 } t_sig;
805 static t_int *sig_tilde_perform(t_int *w)
807 t_float f = *(t_float *)(w[1]);
808 t_float *out = (t_float *)(w[2]);
809 int n = (int)(w[3]);
810 while (n--)
811 *out++ = f;
812 return (w+4);
815 static t_int *sig_tilde_perf8(t_int *w)
817 t_float f = *(t_float *)(w[1]);
818 t_float *out = (t_float *)(w[2]);
819 int n = (int)(w[3]);
821 for (; n; n -= 8, out += 8)
823 out[0] = f;
824 out[1] = f;
825 out[2] = f;
826 out[3] = f;
827 out[4] = f;
828 out[5] = f;
829 out[6] = f;
830 out[7] = f;
832 return (w+4);
835 void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n)
837 if (n&7)
838 dsp_add(sig_tilde_perform, 3, in, out, n);
839 else
840 dsp_add(sig_tilde_perf8, 3, in, out, n);
843 static void sig_tilde_float(t_sig *x, t_float f)
845 x->x_f = f;
848 static void sig_tilde_dsp(t_sig *x, t_signal **sp)
850 dsp_add(sig_tilde_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n);
853 static void *sig_tilde_new(t_floatarg f)
855 t_sig *x = (t_sig *)pd_new(sig_tilde_class);
856 x->x_f = f;
857 outlet_new(&x->x_obj, gensym("signal"));
858 return (x);
861 static void sig_tilde_setup(void)
863 sig_tilde_class = class_new(gensym("sig~"), (t_newmethod)sig_tilde_new, 0,
864 sizeof(t_sig), 0, A_DEFFLOAT, 0);
865 class_addfloat(sig_tilde_class, (t_method)sig_tilde_float);
866 class_addmethod(sig_tilde_class, (t_method)sig_tilde_dsp, gensym("dsp"), 0);
870 #ifndef FIXEDPOINT
872 /* -------------------------- line~ ------------------------------ */
873 static t_class *line_tilde_class;
875 typedef struct _line
877 t_object x_obj;
878 float x_target;
879 float x_value;
880 float x_biginc;
881 float x_inc;
882 float x_1overn;
883 float x_dspticktomsec;
884 float x_inletvalue;
885 float x_inletwas;
886 int x_ticksleft;
887 int x_retarget;
888 } t_line;
890 static t_int *line_tilde_perform(t_int *w)
892 t_line *x = (t_line *)(w[1]);
893 t_float *out = (t_float *)(w[2]);
894 int n = (int)(w[3]);
895 float f = x->x_value;
897 if (PD_BIGORSMALL(f))
898 x->x_value = f = 0;
899 if (x->x_retarget)
901 int nticks = x->x_inletwas * x->x_dspticktomsec;
902 if (!nticks) nticks = 1;
903 x->x_ticksleft = nticks;
904 x->x_biginc = (x->x_target - x->x_value)/(float)nticks;
905 x->x_inc = x->x_1overn * x->x_biginc;
906 x->x_retarget = 0;
908 if (x->x_ticksleft)
910 float f = x->x_value;
911 while (n--) *out++ = f, f += x->x_inc;
912 x->x_value += x->x_biginc;
913 x->x_ticksleft--;
915 else
917 x->x_value = x->x_target;
918 while (n--) *out++ = x->x_value;
920 return (w+4);
923 static void line_tilde_float(t_line *x, t_float f)
925 if (x->x_inletvalue <= 0)
927 x->x_target = x->x_value = f;
928 x->x_ticksleft = x->x_retarget = 0;
930 else
932 x->x_target = f;
933 x->x_retarget = 1;
934 x->x_inletwas = x->x_inletvalue;
935 x->x_inletvalue = 0;
939 static void line_tilde_stop(t_line *x)
941 x->x_target = x->x_value;
942 x->x_ticksleft = x->x_retarget = 0;
945 static void line_tilde_dsp(t_line *x, t_signal **sp)
947 dsp_add(line_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
948 x->x_1overn = 1./sp[0]->s_n;
949 x->x_dspticktomsec = sp[0]->s_sr / (1000 * sp[0]->s_n);
952 static void *line_tilde_new(void)
954 t_line *x = (t_line *)pd_new(line_tilde_class);
955 outlet_new(&x->x_obj, gensym("signal"));
956 floatinlet_new(&x->x_obj, &x->x_inletvalue);
957 x->x_ticksleft = x->x_retarget = 0;
958 x->x_value = x->x_target = x->x_inletvalue = x->x_inletwas = 0;
959 return (x);
962 static void line_tilde_setup(void)
964 line_tilde_class = class_new(gensym("line~"), line_tilde_new, 0,
965 sizeof(t_line), 0, 0);
966 class_addfloat(line_tilde_class, (t_method)line_tilde_float);
967 class_addmethod(line_tilde_class, (t_method)line_tilde_dsp,
968 gensym("dsp"), 0);
969 class_addmethod(line_tilde_class, (t_method)line_tilde_stop,
970 gensym("stop"), 0);
973 /* -------------------------- vline~ ------------------------------ */
974 static t_class *vline_tilde_class;
976 typedef struct _vseg
978 double s_targettime;
979 double s_starttime;
980 float s_target;
981 struct _vseg *s_next;
982 } t_vseg;
984 typedef struct _vline
986 t_object x_obj;
987 double x_value;
988 double x_inc;
989 double x_referencetime;
990 double x_samppermsec;
991 double x_msecpersamp;
992 double x_targettime;
993 float x_target;
994 float x_inlet1;
995 float x_inlet2;
996 t_vseg *x_list;
997 } t_vline;
999 static t_int *vline_tilde_perform(t_int *w)
1001 t_vline *x = (t_vline *)(w[1]);
1002 t_float *out = (t_float *)(w[2]);
1003 int n = (int)(w[3]), i;
1004 double f = x->x_value;
1005 double inc = x->x_inc;
1006 double msecpersamp = x->x_msecpersamp;
1007 double samppermsec = x->x_samppermsec;
1008 double timenow = clock_gettimesince(x->x_referencetime) - n * msecpersamp;
1009 t_vseg *s = x->x_list;
1010 for (i = 0; i < n; i++)
1012 double timenext = timenow + msecpersamp;
1013 checknext:
1014 if (s)
1016 /* has starttime elapsed? If so update value and increment */
1017 if (s->s_starttime < timenext)
1019 if (x->x_targettime <= timenext)
1020 f = x->x_target, inc = 0;
1021 /* if zero-length segment bash output value */
1022 if (s->s_targettime <= s->s_starttime)
1024 f = s->s_target;
1025 inc = 0;
1027 else
1029 double incpermsec = (s->s_target - f)/
1030 (s->s_targettime - s->s_starttime);
1031 f = f + incpermsec * (timenext - s->s_starttime);
1032 inc = incpermsec * msecpersamp;
1034 x->x_inc = inc;
1035 x->x_target = s->s_target;
1036 x->x_targettime = s->s_targettime;
1037 x->x_list = s->s_next;
1038 t_freebytes(s, sizeof(*s));
1039 s = x->x_list;
1040 goto checknext;
1043 if (x->x_targettime <= timenext)
1044 f = x->x_target, inc = x->x_inc = 0, x->x_targettime = 1e20;
1045 *out++ = f;
1046 f = f + inc;
1047 timenow = timenext;
1049 x->x_value = f;
1050 return (w+4);
1053 static void vline_tilde_stop(t_vline *x)
1055 t_vseg *s1, *s2;
1056 for (s1 = x->x_list; s1; s1 = s2)
1057 s2 = s1->s_next, t_freebytes(s1, sizeof(*s1));
1058 x->x_list = 0;
1059 x->x_inc = 0;
1060 x->x_inlet1 = x->x_inlet2 = 0;
1061 x->x_target = x->x_value;
1062 x->x_targettime = 1e20;
1065 static void vline_tilde_float(t_vline *x, t_float f)
1067 double timenow = clock_gettimesince(x->x_referencetime);
1068 float inlet1 = (x->x_inlet1 < 0 ? 0 : x->x_inlet1);
1069 float inlet2 = x->x_inlet2;
1070 double starttime = timenow + inlet2;
1071 t_vseg *s1, *s2, *deletefrom = 0, *snew;
1072 if (PD_BIGORSMALL(f))
1073 f = 0;
1075 /* negative delay input means stop and jump immediately to new value */
1076 if (inlet2 < 0)
1078 x->x_value = f;
1079 vline_tilde_stop(x);
1080 return;
1082 snew = (t_vseg *)t_getbytes(sizeof(*snew));
1083 /* check if we supplant the first item in the list. We supplant
1084 an item by having an earlier starttime, or an equal starttime unless
1085 the equal one was instantaneous and the new one isn't (in which case
1086 we'll do a jump-and-slide starting at that time.) */
1087 if (!x->x_list || x->x_list->s_starttime > starttime ||
1088 (x->x_list->s_starttime == starttime &&
1089 (x->x_list->s_targettime > x->x_list->s_starttime || inlet1 <= 0)))
1091 deletefrom = x->x_list;
1092 x->x_list = snew;
1094 else
1096 for (s1 = x->x_list; s2 = s1->s_next; s1 = s2)
1098 if (s2->s_starttime > starttime ||
1099 (s2->s_starttime == starttime &&
1100 (s2->s_targettime > s2->s_starttime || inlet1 <= 0)))
1102 deletefrom = s2;
1103 s1->s_next = snew;
1104 goto didit;
1107 s1->s_next = snew;
1108 deletefrom = 0;
1109 didit: ;
1111 while (deletefrom)
1113 s1 = deletefrom->s_next;
1114 t_freebytes(deletefrom, sizeof(*deletefrom));
1115 deletefrom = s1;
1117 snew->s_next = 0;
1118 snew->s_target = f;
1119 snew->s_starttime = starttime;
1120 snew->s_targettime = starttime + inlet1;
1121 x->x_inlet1 = x->x_inlet2 = 0;
1124 static void vline_tilde_dsp(t_vline *x, t_signal **sp)
1126 dsp_add(vline_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
1127 x->x_samppermsec = ((double)(sp[0]->s_sr)) / 1000;
1128 x->x_msecpersamp = ((double)1000) / sp[0]->s_sr;
1131 static void *vline_tilde_new(void)
1133 t_vline *x = (t_vline *)pd_new(vline_tilde_class);
1134 outlet_new(&x->x_obj, gensym("signal"));
1135 floatinlet_new(&x->x_obj, &x->x_inlet1);
1136 floatinlet_new(&x->x_obj, &x->x_inlet2);
1137 x->x_inlet1 = x->x_inlet2 = 0;
1138 x->x_value = x->x_inc = 0;
1139 x->x_referencetime = clock_getlogicaltime();
1140 x->x_list = 0;
1141 x->x_samppermsec = 0;
1142 x->x_targettime = 1e20;
1143 return (x);
1146 static void vline_tilde_setup(void)
1148 vline_tilde_class = class_new(gensym("vline~"), vline_tilde_new,
1149 (t_method)vline_tilde_stop, sizeof(t_vline), 0, 0);
1150 class_addfloat(vline_tilde_class, (t_method)vline_tilde_float);
1151 class_addmethod(vline_tilde_class, (t_method)vline_tilde_dsp,
1152 gensym("dsp"), 0);
1153 class_addmethod(vline_tilde_class, (t_method)vline_tilde_stop,
1154 gensym("stop"), 0);
1157 /* -------------------------- snapshot~ ------------------------------ */
1158 static t_class *snapshot_tilde_class;
1160 typedef struct _snapshot
1162 t_object x_obj;
1163 t_sample x_value;
1164 float x_f;
1165 } t_snapshot;
1167 static void *snapshot_tilde_new(void)
1169 t_snapshot *x = (t_snapshot *)pd_new(snapshot_tilde_class);
1170 x->x_value = 0;
1171 outlet_new(&x->x_obj, &s_float);
1172 x->x_f = 0;
1173 return (x);
1176 static t_int *snapshot_tilde_perform(t_int *w)
1178 t_float *in = (t_float *)(w[1]);
1179 t_float *out = (t_float *)(w[2]);
1180 *out = *in;
1181 return (w+3);
1184 static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp)
1186 dsp_add(snapshot_tilde_perform, 2, sp[0]->s_vec + (sp[0]->s_n-1),
1187 &x->x_value);
1190 static void snapshot_tilde_bang(t_snapshot *x)
1192 outlet_float(x->x_obj.ob_outlet, x->x_value);
1195 static void snapshot_tilde_set(t_snapshot *x, t_floatarg f)
1197 x->x_value = f;
1200 static void snapshot_tilde_setup(void)
1202 snapshot_tilde_class = class_new(gensym("snapshot~"), snapshot_tilde_new, 0,
1203 sizeof(t_snapshot), 0, 0);
1204 CLASS_MAINSIGNALIN(snapshot_tilde_class, t_snapshot, x_f);
1205 class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_dsp,
1206 gensym("dsp"), 0);
1207 class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_set,
1208 gensym("set"), A_DEFFLOAT, 0);
1209 class_addbang(snapshot_tilde_class, snapshot_tilde_bang);
1212 /* -------------------------- vsnapshot~ ------------------------------ */
1213 static t_class *vsnapshot_tilde_class;
1215 typedef struct _vsnapshot
1217 t_object x_obj;
1218 int x_n;
1219 int x_gotone;
1220 t_sample *x_vec;
1221 float x_f;
1222 float x_sampspermsec;
1223 double x_time;
1224 } t_vsnapshot;
1226 static void *vsnapshot_tilde_new(void)
1228 t_vsnapshot *x = (t_vsnapshot *)pd_new(vsnapshot_tilde_class);
1229 outlet_new(&x->x_obj, &s_float);
1230 x->x_f = 0;
1231 x->x_n = 0;
1232 x->x_vec = 0;
1233 x->x_gotone = 0;
1234 return (x);
1237 static t_int *vsnapshot_tilde_perform(t_int *w)
1239 t_float *in = (t_float *)(w[1]);
1240 t_vsnapshot *x = (t_vsnapshot *)(w[2]);
1241 t_float *out = x->x_vec;
1242 int n = x->x_n, i;
1243 for (i = 0; i < n; i++)
1244 out[i] = in[i];
1245 x->x_time = clock_getlogicaltime();
1246 x->x_gotone = 1;
1247 return (w+3);
1250 static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp)
1252 int n = sp[0]->s_n;
1253 if (n != x->x_n)
1255 if (x->x_vec)
1256 t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
1257 x->x_vec = (t_sample *)getbytes(n * sizeof(t_sample));
1258 x->x_gotone = 0;
1259 x->x_n = n;
1261 x->x_sampspermsec = sp[0]->s_sr / 1000;
1262 dsp_add(vsnapshot_tilde_perform, 2, sp[0]->s_vec, x);
1265 static void vsnapshot_tilde_bang(t_vsnapshot *x)
1267 float val;
1268 if (x->x_gotone)
1270 int indx = clock_gettimesince(x->x_time) * x->x_sampspermsec;
1271 if (indx < 0)
1272 indx = 0;
1273 else if (indx >= x->x_n)
1274 indx = x->x_n - 1;
1275 val = x->x_vec[indx];
1277 else val = 0;
1278 outlet_float(x->x_obj.ob_outlet, val);
1281 static void vsnapshot_tilde_ff(t_vsnapshot *x)
1283 if (x->x_vec)
1284 t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
1287 static void vsnapshot_tilde_setup(void)
1289 vsnapshot_tilde_class = class_new(gensym("vsnapshot~"),
1290 vsnapshot_tilde_new, (t_method)vsnapshot_tilde_ff,
1291 sizeof(t_vsnapshot), 0, 0);
1292 CLASS_MAINSIGNALIN(vsnapshot_tilde_class, t_vsnapshot, x_f);
1293 class_addmethod(vsnapshot_tilde_class, (t_method)vsnapshot_tilde_dsp, gensym("dsp"), 0);
1294 class_addbang(vsnapshot_tilde_class, vsnapshot_tilde_bang);
1298 /* ---------------- env~ - simple envelope follower. ----------------- */
1300 #define MAXOVERLAP 10
1301 #define MAXVSTAKEN 64
1303 typedef struct sigenv
1305 t_object x_obj; /* header */
1306 void *x_outlet; /* a "float" outlet */
1307 void *x_clock; /* a "clock" object */
1308 float *x_buf; /* a Hanning window */
1309 int x_phase; /* number of points since last output */
1310 int x_period; /* requested period of output */
1311 int x_realperiod; /* period rounded up to vecsize multiple */
1312 int x_npoints; /* analysis window size in samples */
1313 float x_result; /* result to output */
1314 float x_sumbuf[MAXOVERLAP]; /* summing buffer */
1315 float x_f;
1316 } t_sigenv;
1318 t_class *env_tilde_class;
1319 static void env_tilde_tick(t_sigenv *x);
1321 static void *env_tilde_new(t_floatarg fnpoints, t_floatarg fperiod)
1323 int npoints = fnpoints;
1324 int period = fperiod;
1325 t_sigenv *x;
1326 float *buf;
1327 int i;
1329 if (npoints < 1) npoints = 1024;
1330 if (period < 1) period = npoints/2;
1331 if (period < npoints / MAXOVERLAP + 1)
1332 period = npoints / MAXOVERLAP + 1;
1333 if (!(buf = getbytes(sizeof(float) * (npoints + MAXVSTAKEN))))
1335 error("env: couldn't allocate buffer");
1336 return (0);
1338 x = (t_sigenv *)pd_new(env_tilde_class);
1339 x->x_buf = buf;
1340 x->x_npoints = npoints;
1341 x->x_phase = 0;
1342 x->x_period = period;
1343 for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
1344 for (i = 0; i < npoints; i++)
1345 buf[i] = (1. - cos((2 * 3.14159 * i) / npoints))/npoints;
1346 for (; i < npoints+MAXVSTAKEN; i++) buf[i] = 0;
1347 x->x_clock = clock_new(x, (t_method)env_tilde_tick);
1348 x->x_outlet = outlet_new(&x->x_obj, gensym("float"));
1349 x->x_f = 0;
1350 return (x);
1353 static t_int *env_tilde_perform(t_int *w)
1355 t_sigenv *x = (t_sigenv *)(w[1]);
1356 t_float *in = (t_float *)(w[2]);
1357 int n = (int)(w[3]);
1358 int count;
1359 float *sump;
1360 in += n;
1361 for (count = x->x_phase, sump = x->x_sumbuf;
1362 count < x->x_npoints; count += x->x_realperiod, sump++)
1364 float *hp = x->x_buf + count;
1365 float *fp = in;
1366 float sum = *sump;
1367 int i;
1369 for (i = 0; i < n; i++)
1371 fp--;
1372 sum += *hp++ * (*fp * *fp);
1374 *sump = sum;
1376 sump[0] = 0;
1377 x->x_phase -= n;
1378 if (x->x_phase < 0)
1380 x->x_result = x->x_sumbuf[0];
1381 for (count = x->x_realperiod, sump = x->x_sumbuf;
1382 count < x->x_npoints; count += x->x_realperiod, sump++)
1383 sump[0] = sump[1];
1384 sump[0] = 0;
1385 x->x_phase = x->x_realperiod - n;
1386 clock_delay(x->x_clock, 0L);
1388 return (w+4);
1391 static void env_tilde_dsp(t_sigenv *x, t_signal **sp)
1393 if (x->x_period % sp[0]->s_n) x->x_realperiod =
1394 x->x_period + sp[0]->s_n - (x->x_period % sp[0]->s_n);
1395 else x->x_realperiod = x->x_period;
1396 dsp_add(env_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
1397 if (sp[0]->s_n > MAXVSTAKEN) bug("env_tilde_dsp");
1400 static void env_tilde_tick(t_sigenv *x) /* callback function for the clock */
1402 outlet_float(x->x_outlet, powtodb(x->x_result));
1405 static void env_tilde_ff(t_sigenv *x) /* cleanup on free */
1407 clock_free(x->x_clock);
1408 freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float));
1412 void env_tilde_setup(void )
1414 env_tilde_class = class_new(gensym("env~"), (t_newmethod)env_tilde_new,
1415 (t_method)env_tilde_ff, sizeof(t_sigenv), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
1416 CLASS_MAINSIGNALIN(env_tilde_class, t_sigenv, x_f);
1417 class_addmethod(env_tilde_class, (t_method)env_tilde_dsp, gensym("dsp"), 0);
1420 /* --------------------- threshold~ ----------------------------- */
1422 static t_class *threshold_tilde_class;
1424 typedef struct _threshold_tilde
1426 t_object x_obj;
1427 t_outlet *x_outlet1; /* bang out for high thresh */
1428 t_outlet *x_outlet2; /* bang out for low thresh */
1429 t_clock *x_clock; /* wakeup for message output */
1430 float x_f; /* scalar inlet */
1431 int x_state; /* 1 = high, 0 = low */
1432 float x_hithresh; /* value of high threshold */
1433 float x_lothresh; /* value of low threshold */
1434 float x_deadwait; /* msec remaining in dead period */
1435 float x_msecpertick; /* msec per DSP tick */
1436 float x_hideadtime; /* hi dead time in msec */
1437 float x_lodeadtime; /* lo dead time in msec */
1438 } t_threshold_tilde;
1440 static void threshold_tilde_tick(t_threshold_tilde *x);
1441 static void threshold_tilde_set(t_threshold_tilde *x,
1442 t_floatarg hithresh, t_floatarg hideadtime,
1443 t_floatarg lothresh, t_floatarg lodeadtime);
1445 static t_threshold_tilde *threshold_tilde_new(t_floatarg hithresh,
1446 t_floatarg hideadtime, t_floatarg lothresh, t_floatarg lodeadtime)
1448 t_threshold_tilde *x = (t_threshold_tilde *)
1449 pd_new(threshold_tilde_class);
1450 x->x_state = 0; /* low state */
1451 x->x_deadwait = 0; /* no dead time */
1452 x->x_clock = clock_new(x, (t_method)threshold_tilde_tick);
1453 x->x_outlet1 = outlet_new(&x->x_obj, &s_bang);
1454 x->x_outlet2 = outlet_new(&x->x_obj, &s_bang);
1455 inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ft1"));
1456 x->x_msecpertick = 0.;
1457 x->x_f = 0;
1458 threshold_tilde_set(x, hithresh, hideadtime, lothresh, lodeadtime);
1459 return (x);
1462 /* "set" message to specify thresholds and dead times */
1463 static void threshold_tilde_set(t_threshold_tilde *x,
1464 t_floatarg hithresh, t_floatarg hideadtime,
1465 t_floatarg lothresh, t_floatarg lodeadtime)
1467 if (lothresh > hithresh)
1468 lothresh = hithresh;
1469 x->x_hithresh = hithresh;
1470 x->x_hideadtime = hideadtime;
1471 x->x_lothresh = lothresh;
1472 x->x_lodeadtime = lodeadtime;
1475 /* number in inlet sets state -- note incompatible with JMAX which used
1476 "int" message for this, impossible here because of auto signal conversion */
1477 static void threshold_tilde_ft1(t_threshold_tilde *x, t_floatarg f)
1479 x->x_state = (f != 0);
1480 x->x_deadwait = 0;
1483 static void threshold_tilde_tick(t_threshold_tilde *x)
1485 if (x->x_state)
1486 outlet_bang(x->x_outlet1);
1487 else outlet_bang(x->x_outlet2);
1490 static t_int *threshold_tilde_perform(t_int *w)
1492 float *in1 = (float *)(w[1]);
1493 t_threshold_tilde *x = (t_threshold_tilde *)(w[2]);
1494 int n = (t_int)(w[3]);
1495 if (x->x_deadwait > 0)
1496 x->x_deadwait -= x->x_msecpertick;
1497 else if (x->x_state)
1499 /* we're high; look for low sample */
1500 for (; n--; in1++)
1502 if (*in1 < x->x_lothresh)
1504 clock_delay(x->x_clock, 0L);
1505 x->x_state = 0;
1506 x->x_deadwait = x->x_lodeadtime;
1507 goto done;
1511 else
1513 /* we're low; look for high sample */
1514 for (; n--; in1++)
1516 if (*in1 >= x->x_hithresh)
1518 clock_delay(x->x_clock, 0L);
1519 x->x_state = 1;
1520 x->x_deadwait = x->x_hideadtime;
1521 goto done;
1525 done:
1526 return (w+4);
1529 void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp)
1531 x->x_msecpertick = 1000. * sp[0]->s_n / sp[0]->s_sr;
1532 dsp_add(threshold_tilde_perform, 3, sp[0]->s_vec, x, sp[0]->s_n);
1535 static void threshold_tilde_ff(t_threshold_tilde *x)
1537 clock_free(x->x_clock);
1540 static void threshold_tilde_setup( void)
1542 threshold_tilde_class = class_new(gensym("threshold~"),
1543 (t_newmethod)threshold_tilde_new, (t_method)threshold_tilde_ff,
1544 sizeof(t_threshold_tilde), 0,
1545 A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
1546 CLASS_MAINSIGNALIN(threshold_tilde_class, t_threshold_tilde, x_f);
1547 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_set,
1548 gensym("set"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
1549 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_ft1,
1550 gensym("ft1"), A_FLOAT, 0);
1551 class_addmethod(threshold_tilde_class, (t_method)threshold_tilde_dsp,
1552 gensym("dsp"), 0);
1555 /* ------------------------ global setup routine ------------------------- */
1557 void d_ctl_setup(void)
1559 sig_tilde_setup();
1560 line_tilde_setup();
1561 vline_tilde_setup();
1562 snapshot_tilde_setup();
1563 vsnapshot_tilde_setup();
1564 env_tilde_setup();
1565 threshold_tilde_setup();
1568 #endif