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.
12 /* -------------------------- sig~ ------------------------------ */
13 static t_class
*sig_tilde_class
;
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]);
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]);
37 for (; n
; n
-= 8, out
+= 8)
51 void dsp_add_scalarcopy(t_sample
*in
, t_sample
*out
, int n
)
54 dsp_add(sig_tilde_perform
, 3, in
, out
, n
);
56 dsp_add(sig_tilde_perf8
, 3, in
, out
, n
);
59 static void sig_tilde_float(t_sig
*x
, t_float 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
);
73 outlet_new(&x
->x_obj
, gensym("signal"));
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);
88 /* -------------------------- line~ ------------------------------ */
89 static t_class
*line_tilde_class
;
99 float x_dspticktomsec
;
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]);
111 float f
= x
->x_value
;
113 if (PD_BIGORSMALL(f
))
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
;
126 float f
= x
->x_value
;
127 while (n
--) *out
++ = f
, f
+= x
->x_inc
;
128 x
->x_value
+= x
->x_biginc
;
133 x
->x_value
= x
->x_target
;
134 while (n
--) *out
++ = x
->x_value
;
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;
150 x
->x_inletwas
= x
->x_inletvalue
;
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;
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
,
185 class_addmethod(line_tilde_class
, (t_method
)line_tilde_stop
,
189 /* -------------------------- vline~ ------------------------------ */
190 static t_class
*vline_tilde_class
;
197 struct _vseg
*s_next
;
200 typedef struct _vline
205 double x_referencetime
;
206 double x_samppermsec
;
207 double x_msecpersamp
;
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
;
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
)
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
;
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
));
259 if (x
->x_targettime
<= timenext
)
260 f
= x
->x_target
, inc
= x
->x_inc
= 0, x
->x_targettime
= 1e20
;
269 static void vline_tilde_stop(t_vline
*x
)
272 for (s1
= x
->x_list
; s1
; s1
= s2
)
273 s2
= s1
->s_next
, t_freebytes(s1
, sizeof(*s1
));
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
))
291 /* negative delay input means stop and jump immediately to new value */
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
;
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)))
329 s1
= deletefrom
->s_next
;
330 t_freebytes(deletefrom
, sizeof(*deletefrom
));
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();
357 x
->x_samppermsec
= 0;
358 x
->x_targettime
= 1e20
;
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
,
369 class_addmethod(vline_tilde_class
, (t_method
)vline_tilde_stop
,
373 /* -------------------------- snapshot~ ------------------------------ */
374 static t_class
*snapshot_tilde_class
;
376 typedef struct _snapshot
383 static void *snapshot_tilde_new(void)
385 t_snapshot
*x
= (t_snapshot
*)pd_new(snapshot_tilde_class
);
387 outlet_new(&x
->x_obj
, &s_float
);
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]);
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),
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
)
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
,
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
438 float x_sampspermsec
;
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
);
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
;
459 for (i
= 0; i
< n
; i
++)
461 x
->x_time
= clock_getlogicaltime();
466 static void vsnapshot_tilde_dsp(t_vsnapshot
*x
, t_signal
**sp
)
472 t_freebytes(x
->x_vec
, x
->x_n
* sizeof(t_sample
));
473 x
->x_vec
= (t_sample
*)getbytes(n
* sizeof(t_sample
));
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
)
486 int indx
= clock_gettimesince(x
->x_time
) * x
->x_sampspermsec
;
489 else if (indx
>= x
->x_n
)
491 val
= x
->x_vec
[indx
];
494 outlet_float(x
->x_obj
.ob_outlet
, val
);
497 static void vsnapshot_tilde_ff(t_vsnapshot
*x
)
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 */
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
;
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");
554 x
= (t_sigenv
*)pd_new(env_tilde_class
);
556 x
->x_npoints
= npoints
;
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"));
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]);
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
;
585 for (i
= 0; i
< n
; i
++)
588 sum
+= *hp
++ * (*fp
* *fp
);
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
++)
601 x
->x_phase
= x
->x_realperiod
- n
;
602 clock_delay(x
->x_clock
, 0L);
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
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 */
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.;
674 threshold_tilde_set(x
, hithresh
, hideadtime
, lothresh
, lodeadtime
);
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
)
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);
699 static void threshold_tilde_tick(t_threshold_tilde
*x
)
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
;
715 /* we're high; look for low sample */
718 if (*in1
< x
->x_lothresh
)
720 clock_delay(x
->x_clock
, 0L);
722 x
->x_deadwait
= x
->x_lodeadtime
;
729 /* we're low; look for high sample */
732 if (*in1
>= x
->x_hithresh
)
734 clock_delay(x
->x_clock
, 0L);
736 x
->x_deadwait
= x
->x_hideadtime
;
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
,
771 /* ------------------------ global setup routine ------------------------- */
773 void d_ctl_setup(void)
778 snapshot_tilde_setup();
779 vsnapshot_tilde_setup();
781 threshold_tilde_setup();
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.
796 /* -------------------------- sig~ ------------------------------ */
797 static t_class
*sig_tilde_class
;
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]);
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]);
821 for (; n
; n
-= 8, out
+= 8)
835 void dsp_add_scalarcopy(t_sample
*in
, t_sample
*out
, int n
)
838 dsp_add(sig_tilde_perform
, 3, in
, out
, n
);
840 dsp_add(sig_tilde_perf8
, 3, in
, out
, n
);
843 static void sig_tilde_float(t_sig
*x
, t_float 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
);
857 outlet_new(&x
->x_obj
, gensym("signal"));
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);
872 /* -------------------------- line~ ------------------------------ */
873 static t_class
*line_tilde_class
;
883 float x_dspticktomsec
;
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]);
895 float f
= x
->x_value
;
897 if (PD_BIGORSMALL(f
))
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
;
910 float f
= x
->x_value
;
911 while (n
--) *out
++ = f
, f
+= x
->x_inc
;
912 x
->x_value
+= x
->x_biginc
;
917 x
->x_value
= x
->x_target
;
918 while (n
--) *out
++ = x
->x_value
;
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;
934 x
->x_inletwas
= x
->x_inletvalue
;
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;
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
,
969 class_addmethod(line_tilde_class
, (t_method
)line_tilde_stop
,
973 /* -------------------------- vline~ ------------------------------ */
974 static t_class
*vline_tilde_class
;
981 struct _vseg
*s_next
;
984 typedef struct _vline
989 double x_referencetime
;
990 double x_samppermsec
;
991 double x_msecpersamp
;
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
;
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
)
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
;
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
));
1043 if (x
->x_targettime
<= timenext
)
1044 f
= x
->x_target
, inc
= x
->x_inc
= 0, x
->x_targettime
= 1e20
;
1053 static void vline_tilde_stop(t_vline
*x
)
1056 for (s1
= x
->x_list
; s1
; s1
= s2
)
1057 s2
= s1
->s_next
, t_freebytes(s1
, sizeof(*s1
));
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
))
1075 /* negative delay input means stop and jump immediately to new value */
1079 vline_tilde_stop(x
);
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
;
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)))
1113 s1
= deletefrom
->s_next
;
1114 t_freebytes(deletefrom
, sizeof(*deletefrom
));
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();
1141 x
->x_samppermsec
= 0;
1142 x
->x_targettime
= 1e20
;
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
,
1153 class_addmethod(vline_tilde_class
, (t_method
)vline_tilde_stop
,
1157 /* -------------------------- snapshot~ ------------------------------ */
1158 static t_class
*snapshot_tilde_class
;
1160 typedef struct _snapshot
1167 static void *snapshot_tilde_new(void)
1169 t_snapshot
*x
= (t_snapshot
*)pd_new(snapshot_tilde_class
);
1171 outlet_new(&x
->x_obj
, &s_float
);
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]);
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),
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
)
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
,
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
1222 float x_sampspermsec
;
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
);
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
;
1243 for (i
= 0; i
< n
; i
++)
1245 x
->x_time
= clock_getlogicaltime();
1250 static void vsnapshot_tilde_dsp(t_vsnapshot
*x
, t_signal
**sp
)
1256 t_freebytes(x
->x_vec
, x
->x_n
* sizeof(t_sample
));
1257 x
->x_vec
= (t_sample
*)getbytes(n
* sizeof(t_sample
));
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
)
1270 int indx
= clock_gettimesince(x
->x_time
) * x
->x_sampspermsec
;
1273 else if (indx
>= x
->x_n
)
1275 val
= x
->x_vec
[indx
];
1278 outlet_float(x
->x_obj
.ob_outlet
, val
);
1281 static void vsnapshot_tilde_ff(t_vsnapshot
*x
)
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 */
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
;
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");
1338 x
= (t_sigenv
*)pd_new(env_tilde_class
);
1340 x
->x_npoints
= npoints
;
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"));
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]);
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
;
1369 for (i
= 0; i
< n
; i
++)
1372 sum
+= *hp
++ * (*fp
* *fp
);
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
++)
1385 x
->x_phase
= x
->x_realperiod
- n
;
1386 clock_delay(x
->x_clock
, 0L);
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
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.;
1458 threshold_tilde_set(x
, hithresh
, hideadtime
, lothresh
, lodeadtime
);
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);
1483 static void threshold_tilde_tick(t_threshold_tilde
*x
)
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 */
1502 if (*in1
< x
->x_lothresh
)
1504 clock_delay(x
->x_clock
, 0L);
1506 x
->x_deadwait
= x
->x_lodeadtime
;
1513 /* we're low; look for high sample */
1516 if (*in1
>= x
->x_hithresh
)
1518 clock_delay(x
->x_clock
, 0L);
1520 x
->x_deadwait
= x
->x_hideadtime
;
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
,
1555 /* ------------------------ global setup routine ------------------------- */
1557 void d_ctl_setup(void)
1561 vline_tilde_setup();
1562 snapshot_tilde_setup();
1563 vsnapshot_tilde_setup();
1565 threshold_tilde_setup();