summaryrefslogtreecommitdiff
path: root/apps/plugins/pdbox/PDa/src/d_ctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/d_ctl.c')
-rw-r--r--apps/plugins/pdbox/PDa/src/d_ctl.c1568
1 files changed, 1568 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/d_ctl.c b/apps/plugins/pdbox/PDa/src/d_ctl.c
new file mode 100644
index 0000000000..d3262af800
--- /dev/null
+++ b/apps/plugins/pdbox/PDa/src/d_ctl.c
@@ -0,0 +1,1568 @@
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. */
4
5/* sig~ and line~ control-to-signal converters;
6 snapshot~ signal-to-control converter.
7*/
8
9#include "m_pd.h"
10#include "math.h"
11
12/* -------------------------- sig~ ------------------------------ */
13static t_class *sig_tilde_class;
14
15typedef struct _sig
16{
17 t_object x_obj;
18 float x_f;
19} t_sig;
20
21static t_int *sig_tilde_perform(t_int *w)
22{
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);
29}
30
31static t_int *sig_tilde_perf8(t_int *w)
32{
33 t_float f = *(t_float *)(w[1]);
34 t_float *out = (t_float *)(w[2]);
35 int n = (int)(w[3]);
36
37 for (; n; n -= 8, out += 8)
38 {
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;
47 }
48 return (w+4);
49}
50
51void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n)
52{
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);
57}
58
59static void sig_tilde_float(t_sig *x, t_float f)
60{
61 x->x_f = f;
62}
63
64static void sig_tilde_dsp(t_sig *x, t_signal **sp)
65{
66 dsp_add(sig_tilde_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n);
67}
68
69static void *sig_tilde_new(t_floatarg f)
70{
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);
75}
76
77static void sig_tilde_setup(void)
78{
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);
83}
84
85
86#ifndef FIXEDPOINT
87
88/* -------------------------- line~ ------------------------------ */
89static t_class *line_tilde_class;
90
91typedef struct _line
92{
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;
105
106static t_int *line_tilde_perform(t_int *w)
107{
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;
112
113 if (PD_BIGORSMALL(f))
114 x->x_value = f = 0;
115 if (x->x_retarget)
116 {
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;
123 }
124 if (x->x_ticksleft)
125 {
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--;
130 }
131 else
132 {
133 x->x_value = x->x_target;
134 while (n--) *out++ = x->x_value;
135 }
136 return (w+4);
137}
138
139static void line_tilde_float(t_line *x, t_float f)
140{
141 if (x->x_inletvalue <= 0)
142 {
143 x->x_target = x->x_value = f;
144 x->x_ticksleft = x->x_retarget = 0;
145 }
146 else
147 {
148 x->x_target = f;
149 x->x_retarget = 1;
150 x->x_inletwas = x->x_inletvalue;
151 x->x_inletvalue = 0;
152 }
153}
154
155static void line_tilde_stop(t_line *x)
156{
157 x->x_target = x->x_value;
158 x->x_ticksleft = x->x_retarget = 0;
159}
160
161static void line_tilde_dsp(t_line *x, t_signal **sp)
162{
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);
166}
167
168static void *line_tilde_new(void)
169{
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);
176}
177
178static void line_tilde_setup(void)
179{
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);
187}
188
189/* -------------------------- vline~ ------------------------------ */
190static t_class *vline_tilde_class;
191
192typedef struct _vseg
193{
194 double s_targettime;
195 double s_starttime;
196 float s_target;
197 struct _vseg *s_next;
198} t_vseg;
199
200typedef struct _vline
201{
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;
214
215static t_int *vline_tilde_perform(t_int *w)
216{
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++)
227 {
228 double timenext = timenow + msecpersamp;
229 checknext:
230 if (s)
231 {
232 /* has starttime elapsed? If so update value and increment */
233 if (s->s_starttime < timenext)
234 {
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)
239 {
240 f = s->s_target;
241 inc = 0;
242 }
243 else
244 {
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;
249 }
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;
257 }
258 }
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;
264 }
265 x->x_value = f;
266 return (w+4);
267}
268
269static void vline_tilde_stop(t_vline *x)
270{
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;
279}
280
281static void vline_tilde_float(t_vline *x, t_float f)
282{
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;
290
291 /* negative delay input means stop and jump immediately to new value */
292 if (inlet2 < 0)
293 {
294 x->x_value = f;
295 vline_tilde_stop(x);
296 return;
297 }
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)))
306 {
307 deletefrom = x->x_list;
308 x->x_list = snew;
309 }
310 else
311 {
312 for (s1 = x->x_list; s2 = s1->s_next; s1 = s2)
313 {
314 if (s2->s_starttime > starttime ||
315 (s2->s_starttime == starttime &&
316 (s2->s_targettime > s2->s_starttime || inlet1 <= 0)))
317 {
318 deletefrom = s2;
319 s1->s_next = snew;
320 goto didit;
321 }
322 }
323 s1->s_next = snew;
324 deletefrom = 0;
325 didit: ;
326 }
327 while (deletefrom)
328 {
329 s1 = deletefrom->s_next;
330 t_freebytes(deletefrom, sizeof(*deletefrom));
331 deletefrom = s1;
332 }
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;
338}
339
340static void vline_tilde_dsp(t_vline *x, t_signal **sp)
341{
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;
345}
346
347static void *vline_tilde_new(void)
348{
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);
360}
361
362static void vline_tilde_setup(void)
363{
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);
371}
372
373/* -------------------------- snapshot~ ------------------------------ */
374static t_class *snapshot_tilde_class;
375
376typedef struct _snapshot
377{
378 t_object x_obj;
379 t_sample x_value;
380 float x_f;
381} t_snapshot;
382
383static void *snapshot_tilde_new(void)
384{
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);
390}
391
392static t_int *snapshot_tilde_perform(t_int *w)
393{
394 t_float *in = (t_float *)(w[1]);
395 t_float *out = (t_float *)(w[2]);
396 *out = *in;
397 return (w+3);
398}
399
400static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp)
401{
402 dsp_add(snapshot_tilde_perform, 2, sp[0]->s_vec + (sp[0]->s_n-1),
403 &x->x_value);
404}
405
406static void snapshot_tilde_bang(t_snapshot *x)
407{
408 outlet_float(x->x_obj.ob_outlet, x->x_value);
409}
410
411static void snapshot_tilde_set(t_snapshot *x, t_floatarg f)
412{
413 x->x_value = f;
414}
415
416static void snapshot_tilde_setup(void)
417{
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);
426}
427
428/* -------------------------- vsnapshot~ ------------------------------ */
429static t_class *vsnapshot_tilde_class;
430
431typedef struct _vsnapshot
432{
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;
441
442static void *vsnapshot_tilde_new(void)
443{
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);
451}
452
453static t_int *vsnapshot_tilde_perform(t_int *w)
454{
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);
464}
465
466static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp)
467{
468 int n = sp[0]->s_n;
469 if (n != x->x_n)
470 {
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;
476 }
477 x->x_sampspermsec = sp[0]->s_sr / 1000;
478 dsp_add(vsnapshot_tilde_perform, 2, sp[0]->s_vec, x);
479}
480
481static void vsnapshot_tilde_bang(t_vsnapshot *x)
482{
483 float val;
484 if (x->x_gotone)
485 {
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];
492 }
493 else val = 0;
494 outlet_float(x->x_obj.ob_outlet, val);
495}
496
497static void vsnapshot_tilde_ff(t_vsnapshot *x)
498{
499 if (x->x_vec)
500 t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
501}
502
503static void vsnapshot_tilde_setup(void)
504{
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);
511}
512
513
514/* ---------------- env~ - simple envelope follower. ----------------- */
515
516#define MAXOVERLAP 10
517#define MAXVSTAKEN 64
518
519typedef struct sigenv
520{
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;
533
534t_class *env_tilde_class;
535static void env_tilde_tick(t_sigenv *x);
536
537static void *env_tilde_new(t_floatarg fnpoints, t_floatarg fperiod)
538{
539 int npoints = fnpoints;
540 int period = fperiod;
541 t_sigenv *x;
542 float *buf;
543 int i;
544
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))))
550 {
551 error("env: couldn't allocate buffer");
552 return (0);
553 }
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);
567}
568
569static t_int *env_tilde_perform(t_int *w)
570{
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++)
579 {
580 float *hp = x->x_buf + count;
581 float *fp = in;
582 float sum = *sump;
583 int i;
584
585 for (i = 0; i < n; i++)
586 {
587 fp--;
588 sum += *hp++ * (*fp * *fp);
589 }
590 *sump = sum;
591 }
592 sump[0] = 0;
593 x->x_phase -= n;
594 if (x->x_phase < 0)
595 {
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);
603 }
604 return (w+4);
605}
606
607static void env_tilde_dsp(t_sigenv *x, t_signal **sp)
608{
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");
614}
615
616static void env_tilde_tick(t_sigenv *x) /* callback function for the clock */
617{
618 outlet_float(x->x_outlet, powtodb(x->x_result));
619}
620
621static void env_tilde_ff(t_sigenv *x) /* cleanup on free */
622{
623 clock_free(x->x_clock);
624 freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float));
625}
626
627
628void env_tilde_setup(void )
629{
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);
634}
635
636/* --------------------- threshold~ ----------------------------- */
637
638static t_class *threshold_tilde_class;
639
640typedef struct _threshold_tilde
641{
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;
655
656static void threshold_tilde_tick(t_threshold_tilde *x);
657static void threshold_tilde_set(t_threshold_tilde *x,
658 t_floatarg hithresh, t_floatarg hideadtime,
659 t_floatarg lothresh, t_floatarg lodeadtime);
660
661static t_threshold_tilde *threshold_tilde_new(t_floatarg hithresh,
662 t_floatarg hideadtime, t_floatarg lothresh, t_floatarg lodeadtime)
663{
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);
676}
677
678 /* "set" message to specify thresholds and dead times */
679static void threshold_tilde_set(t_threshold_tilde *x,
680 t_floatarg hithresh, t_floatarg hideadtime,
681 t_floatarg lothresh, t_floatarg lodeadtime)
682{
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;
689}
690
691 /* number in inlet sets state -- note incompatible with JMAX which used
692 "int" message for this, impossible here because of auto signal conversion */
693static void threshold_tilde_ft1(t_threshold_tilde *x, t_floatarg f)
694{
695 x->x_state = (f != 0);
696 x->x_deadwait = 0;
697}
698
699static void threshold_tilde_tick(t_threshold_tilde *x)
700{
701 if (x->x_state)
702 outlet_bang(x->x_outlet1);
703 else outlet_bang(x->x_outlet2);
704}
705
706static t_int *threshold_tilde_perform(t_int *w)
707{
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)
714 {
715 /* we're high; look for low sample */
716 for (; n--; in1++)
717 {
718 if (*in1 < x->x_lothresh)
719 {
720 clock_delay(x->x_clock, 0L);
721 x->x_state = 0;
722 x->x_deadwait = x->x_lodeadtime;
723 goto done;
724 }
725 }
726 }
727 else
728 {
729 /* we're low; look for high sample */
730 for (; n--; in1++)
731 {
732 if (*in1 >= x->x_hithresh)
733 {
734 clock_delay(x->x_clock, 0L);
735 x->x_state = 1;
736 x->x_deadwait = x->x_hideadtime;
737 goto done;
738 }
739 }
740 }
741done:
742 return (w+4);
743}
744
745void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp)
746{
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);
749}
750
751static void threshold_tilde_ff(t_threshold_tilde *x)
752{
753 clock_free(x->x_clock);
754}
755
756static void threshold_tilde_setup( void)
757{
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);
769}
770
771/* ------------------------ global setup routine ------------------------- */
772
773void d_ctl_setup(void)
774{
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();
782}
783
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. */
788
789/* sig~ and line~ control-to-signal converters;
790 snapshot~ signal-to-control converter.
791*/
792
793#include "m_pd.h"
794#include "math.h"
795
796/* -------------------------- sig~ ------------------------------ */
797static t_class *sig_tilde_class;
798
799typedef struct _sig
800{
801 t_object x_obj;
802 float x_f;
803} t_sig;
804
805static t_int *sig_tilde_perform(t_int *w)
806{
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);
813}
814
815static t_int *sig_tilde_perf8(t_int *w)
816{
817 t_float f = *(t_float *)(w[1]);
818 t_float *out = (t_float *)(w[2]);
819 int n = (int)(w[3]);
820
821 for (; n; n -= 8, out += 8)
822 {
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;
831 }
832 return (w+4);
833}
834
835void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n)
836{
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);
841}
842
843static void sig_tilde_float(t_sig *x, t_float f)
844{
845 x->x_f = f;
846}
847
848static void sig_tilde_dsp(t_sig *x, t_signal **sp)
849{
850 dsp_add(sig_tilde_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n);
851}
852
853static void *sig_tilde_new(t_floatarg f)
854{
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);
859}
860
861static void sig_tilde_setup(void)
862{
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);
867}
868
869
870#ifndef FIXEDPOINT
871
872/* -------------------------- line~ ------------------------------ */
873static t_class *line_tilde_class;
874
875typedef struct _line
876{
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;
889
890static t_int *line_tilde_perform(t_int *w)
891{
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;
896
897 if (PD_BIGORSMALL(f))
898 x->x_value = f = 0;
899 if (x->x_retarget)
900 {
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;
907 }
908 if (x->x_ticksleft)
909 {
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--;
914 }
915 else
916 {
917 x->x_value = x->x_target;
918 while (n--) *out++ = x->x_value;
919 }
920 return (w+4);
921}
922
923static void line_tilde_float(t_line *x, t_float f)
924{
925 if (x->x_inletvalue <= 0)
926 {
927 x->x_target = x->x_value = f;
928 x->x_ticksleft = x->x_retarget = 0;
929 }
930 else
931 {
932 x->x_target = f;
933 x->x_retarget = 1;
934 x->x_inletwas = x->x_inletvalue;
935 x->x_inletvalue = 0;
936 }
937}
938
939static void line_tilde_stop(t_line *x)
940{
941 x->x_target = x->x_value;
942 x->x_ticksleft = x->x_retarget = 0;
943}
944
945static void line_tilde_dsp(t_line *x, t_signal **sp)
946{
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);
950}
951
952static void *line_tilde_new(void)
953{
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);
960}
961
962static void line_tilde_setup(void)
963{
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);
971}
972
973/* -------------------------- vline~ ------------------------------ */
974static t_class *vline_tilde_class;
975
976typedef struct _vseg
977{
978 double s_targettime;
979 double s_starttime;
980 float s_target;
981 struct _vseg *s_next;
982} t_vseg;
983
984typedef struct _vline
985{
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;
998
999static t_int *vline_tilde_perform(t_int *w)
1000{
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++)
1011 {
1012 double timenext = timenow + msecpersamp;
1013 checknext:
1014 if (s)
1015 {
1016 /* has starttime elapsed? If so update value and increment */
1017 if (s->s_starttime < timenext)
1018 {
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)
1023 {
1024 f = s->s_target;
1025 inc = 0;
1026 }
1027 else
1028 {
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;
1033 }
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;
1041 }
1042 }
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;
1048 }
1049 x->x_value = f;
1050 return (w+4);
1051}
1052
1053static void vline_tilde_stop(t_vline *x)
1054{
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;
1063}
1064
1065static void vline_tilde_float(t_vline *x, t_float f)
1066{
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;
1074
1075 /* negative delay input means stop and jump immediately to new value */
1076 if (inlet2 < 0)
1077 {
1078 x->x_value = f;
1079 vline_tilde_stop(x);
1080 return;
1081 }
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)))
1090 {
1091 deletefrom = x->x_list;
1092 x->x_list = snew;
1093 }
1094 else
1095 {
1096 for (s1 = x->x_list; s2 = s1->s_next; s1 = s2)
1097 {
1098 if (s2->s_starttime > starttime ||
1099 (s2->s_starttime == starttime &&
1100 (s2->s_targettime > s2->s_starttime || inlet1 <= 0)))
1101 {
1102 deletefrom = s2;
1103 s1->s_next = snew;
1104 goto didit;
1105 }
1106 }
1107 s1->s_next = snew;
1108 deletefrom = 0;
1109 didit: ;
1110 }
1111 while (deletefrom)
1112 {
1113 s1 = deletefrom->s_next;
1114 t_freebytes(deletefrom, sizeof(*deletefrom));
1115 deletefrom = s1;
1116 }
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;
1122}
1123
1124static void vline_tilde_dsp(t_vline *x, t_signal **sp)
1125{
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;
1129}
1130
1131static void *vline_tilde_new(void)
1132{
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);
1144}
1145
1146static void vline_tilde_setup(void)
1147{
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);
1155}
1156
1157/* -------------------------- snapshot~ ------------------------------ */
1158static t_class *snapshot_tilde_class;
1159
1160typedef struct _snapshot
1161{
1162 t_object x_obj;
1163 t_sample x_value;
1164 float x_f;
1165} t_snapshot;
1166
1167static void *snapshot_tilde_new(void)
1168{
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);
1174}
1175
1176static t_int *snapshot_tilde_perform(t_int *w)
1177{
1178 t_float *in = (t_float *)(w[1]);
1179 t_float *out = (t_float *)(w[2]);
1180 *out = *in;
1181 return (w+3);
1182}
1183
1184static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp)
1185{
1186 dsp_add(snapshot_tilde_perform, 2, sp[0]->s_vec + (sp[0]->s_n-1),
1187 &x->x_value);
1188}
1189
1190static void snapshot_tilde_bang(t_snapshot *x)
1191{
1192 outlet_float(x->x_obj.ob_outlet, x->x_value);
1193}
1194
1195static void snapshot_tilde_set(t_snapshot *x, t_floatarg f)
1196{
1197 x->x_value = f;
1198}
1199
1200static void snapshot_tilde_setup(void)
1201{
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);
1210}
1211
1212/* -------------------------- vsnapshot~ ------------------------------ */
1213static t_class *vsnapshot_tilde_class;
1214
1215typedef struct _vsnapshot
1216{
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;
1225
1226static void *vsnapshot_tilde_new(void)
1227{
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);
1235}
1236
1237static t_int *vsnapshot_tilde_perform(t_int *w)
1238{
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);
1248}
1249
1250static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp)
1251{
1252 int n = sp[0]->s_n;
1253 if (n != x->x_n)
1254 {
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;
1260 }
1261 x->x_sampspermsec = sp[0]->s_sr / 1000;
1262 dsp_add(vsnapshot_tilde_perform, 2, sp[0]->s_vec, x);
1263}
1264
1265static void vsnapshot_tilde_bang(t_vsnapshot *x)
1266{
1267 float val;
1268 if (x->x_gotone)
1269 {
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];
1276 }
1277 else val = 0;
1278 outlet_float(x->x_obj.ob_outlet, val);
1279}
1280
1281static void vsnapshot_tilde_ff(t_vsnapshot *x)
1282{
1283 if (x->x_vec)
1284 t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
1285}
1286
1287static void vsnapshot_tilde_setup(void)
1288{
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);
1295}
1296
1297
1298/* ---------------- env~ - simple envelope follower. ----------------- */
1299
1300#define MAXOVERLAP 10
1301#define MAXVSTAKEN 64
1302
1303typedef struct sigenv
1304{
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;
1317
1318t_class *env_tilde_class;
1319static void env_tilde_tick(t_sigenv *x);
1320
1321static void *env_tilde_new(t_floatarg fnpoints, t_floatarg fperiod)
1322{
1323 int npoints = fnpoints;
1324 int period = fperiod;
1325 t_sigenv *x;
1326 float *buf;
1327 int i;
1328
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))))
1334 {
1335 error("env: couldn't allocate buffer");
1336 return (0);
1337 }
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);
1351}
1352
1353static t_int *env_tilde_perform(t_int *w)
1354{
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++)
1363 {
1364 float *hp = x->x_buf + count;
1365 float *fp = in;
1366 float sum = *sump;
1367 int i;
1368
1369 for (i = 0; i < n; i++)
1370 {
1371 fp--;
1372 sum += *hp++ * (*fp * *fp);
1373 }
1374 *sump = sum;
1375 }
1376 sump[0] = 0;
1377 x->x_phase -= n;
1378 if (x->x_phase < 0)
1379 {
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);
1387 }
1388 return (w+4);
1389}
1390
1391static void env_tilde_dsp(t_sigenv *x, t_signal **sp)
1392{
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");
1398}
1399
1400static void env_tilde_tick(t_sigenv *x) /* callback function for the clock */
1401{
1402 outlet_float(x->x_outlet, powtodb(x->x_result));
1403}
1404
1405static void env_tilde_ff(t_sigenv *x) /* cleanup on free */
1406{
1407 clock_free(x->x_clock);
1408 freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float));
1409}
1410
1411
1412void env_tilde_setup(void )
1413{
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);
1418}
1419
1420/* --------------------- threshold~ ----------------------------- */
1421
1422static t_class *threshold_tilde_class;
1423
1424typedef struct _threshold_tilde
1425{
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;
1439
1440static void threshold_tilde_tick(t_threshold_tilde *x);
1441static void threshold_tilde_set(t_threshold_tilde *x,
1442 t_floatarg hithresh, t_floatarg hideadtime,
1443 t_floatarg lothresh, t_floatarg lodeadtime);
1444
1445static t_threshold_tilde *threshold_tilde_new(t_floatarg hithresh,
1446 t_floatarg hideadtime, t_floatarg lothresh, t_floatarg lodeadtime)
1447{
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);
1460}
1461
1462 /* "set" message to specify thresholds and dead times */
1463static void threshold_tilde_set(t_threshold_tilde *x,
1464 t_floatarg hithresh, t_floatarg hideadtime,
1465 t_floatarg lothresh, t_floatarg lodeadtime)
1466{
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;
1473}
1474
1475 /* number in inlet sets state -- note incompatible with JMAX which used
1476 "int" message for this, impossible here because of auto signal conversion */
1477static void threshold_tilde_ft1(t_threshold_tilde *x, t_floatarg f)
1478{
1479 x->x_state = (f != 0);
1480 x->x_deadwait = 0;
1481}
1482
1483static void threshold_tilde_tick(t_threshold_tilde *x)
1484{
1485 if (x->x_state)
1486 outlet_bang(x->x_outlet1);
1487 else outlet_bang(x->x_outlet2);
1488}
1489
1490static t_int *threshold_tilde_perform(t_int *w)
1491{
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)
1498 {
1499 /* we're high; look for low sample */
1500 for (; n--; in1++)
1501 {
1502 if (*in1 < x->x_lothresh)
1503 {
1504 clock_delay(x->x_clock, 0L);
1505 x->x_state = 0;
1506 x->x_deadwait = x->x_lodeadtime;
1507 goto done;
1508 }
1509 }
1510 }
1511 else
1512 {
1513 /* we're low; look for high sample */
1514 for (; n--; in1++)
1515 {
1516 if (*in1 >= x->x_hithresh)
1517 {
1518 clock_delay(x->x_clock, 0L);
1519 x->x_state = 1;
1520 x->x_deadwait = x->x_hideadtime;
1521 goto done;
1522 }
1523 }
1524 }
1525done:
1526 return (w+4);
1527}
1528
1529void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp)
1530{
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);
1533}
1534
1535static void threshold_tilde_ff(t_threshold_tilde *x)
1536{
1537 clock_free(x->x_clock);
1538}
1539
1540static void threshold_tilde_setup( void)
1541{
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);
1553}
1554
1555/* ------------------------ global setup routine ------------------------- */
1556
1557void d_ctl_setup(void)
1558{
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();
1566}
1567
1568#endif