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"));
80 void sig_tilde_setup(void)
82 sig_tilde_class
= class_new(gensym("sig~"), (t_newmethod
)sig_tilde_new
, 0,
83 sizeof(t_sig
), 0, A_DEFFLOAT
, 0);
84 class_addfloat(sig_tilde_class
, (t_method
)sig_tilde_float
);
85 class_addmethod(sig_tilde_class
, (t_method
)sig_tilde_dsp
, gensym("dsp"), 0);
91 /* -------------------------- line~ ------------------------------ */
92 static t_class
*line_tilde_class
;
102 float x_dspticktomsec
;
109 static t_int
*line_tilde_perform(t_int
*w
)
111 t_line
*x
= (t_line
*)(w
[1]);
112 t_float
*out
= (t_float
*)(w
[2]);
114 float f
= x
->x_value
;
116 if (PD_BIGORSMALL(f
))
120 int nticks
= x
->x_inletwas
* x
->x_dspticktomsec
;
121 if (!nticks
) nticks
= 1;
122 x
->x_ticksleft
= nticks
;
123 x
->x_biginc
= (x
->x_target
- x
->x_value
)/(float)nticks
;
124 x
->x_inc
= x
->x_1overn
* x
->x_biginc
;
129 float f
= x
->x_value
;
130 while (n
--) *out
++ = f
, f
+= x
->x_inc
;
131 x
->x_value
+= x
->x_biginc
;
136 x
->x_value
= x
->x_target
;
137 while (n
--) *out
++ = x
->x_value
;
142 static void line_tilde_float(t_line
*x
, t_float f
)
144 if (x
->x_inletvalue
<= 0)
146 x
->x_target
= x
->x_value
= f
;
147 x
->x_ticksleft
= x
->x_retarget
= 0;
153 x
->x_inletwas
= x
->x_inletvalue
;
158 static void line_tilde_stop(t_line
*x
)
160 x
->x_target
= x
->x_value
;
161 x
->x_ticksleft
= x
->x_retarget
= 0;
164 static void line_tilde_dsp(t_line
*x
, t_signal
**sp
)
166 dsp_add(line_tilde_perform
, 3, x
, sp
[0]->s_vec
, sp
[0]->s_n
);
167 x
->x_1overn
= 1./sp
[0]->s_n
;
168 x
->x_dspticktomsec
= sp
[0]->s_sr
/ (1000 * sp
[0]->s_n
);
171 static void *line_tilde_new(void)
173 t_line
*x
= (t_line
*)pd_new(line_tilde_class
);
174 outlet_new(&x
->x_obj
, gensym("signal"));
175 floatinlet_new(&x
->x_obj
, &x
->x_inletvalue
);
176 x
->x_ticksleft
= x
->x_retarget
= 0;
177 x
->x_value
= x
->x_target
= x
->x_inletvalue
= x
->x_inletwas
= 0;
181 static void line_tilde_setup(void)
183 line_tilde_class
= class_new(gensym("line~"), line_tilde_new
, 0,
184 sizeof(t_line
), 0, 0);
185 class_addfloat(line_tilde_class
, (t_method
)line_tilde_float
);
186 class_addmethod(line_tilde_class
, (t_method
)line_tilde_dsp
,
188 class_addmethod(line_tilde_class
, (t_method
)line_tilde_stop
,
192 /* -------------------------- vline~ ------------------------------ */
193 static t_class
*vline_tilde_class
;
200 struct _vseg
*s_next
;
203 typedef struct _vline
208 double x_referencetime
;
209 double x_samppermsec
;
210 double x_msecpersamp
;
218 static t_int
*vline_tilde_perform(t_int
*w
)
220 t_vline
*x
= (t_vline
*)(w
[1]);
221 t_float
*out
= (t_float
*)(w
[2]);
222 int n
= (int)(w
[3]), i
;
223 double f
= x
->x_value
;
224 double inc
= x
->x_inc
;
225 double msecpersamp
= x
->x_msecpersamp
;
226 double samppermsec
= x
->x_samppermsec
;
227 double timenow
= clock_gettimesince(x
->x_referencetime
) - n
* msecpersamp
;
228 t_vseg
*s
= x
->x_list
;
229 for (i
= 0; i
< n
; i
++)
231 double timenext
= timenow
+ msecpersamp
;
235 /* has starttime elapsed? If so update value and increment */
236 if (s
->s_starttime
< timenext
)
238 if (x
->x_targettime
<= timenext
)
239 f
= x
->x_target
, inc
= 0;
240 /* if zero-length segment bash output value */
241 if (s
->s_targettime
<= s
->s_starttime
)
248 double incpermsec
= (s
->s_target
- f
)/
249 (s
->s_targettime
- s
->s_starttime
);
250 f
= f
+ incpermsec
* (timenext
- s
->s_starttime
);
251 inc
= incpermsec
* msecpersamp
;
254 x
->x_target
= s
->s_target
;
255 x
->x_targettime
= s
->s_targettime
;
256 x
->x_list
= s
->s_next
;
257 t_freebytes(s
, sizeof(*s
));
262 if (x
->x_targettime
<= timenext
)
263 f
= x
->x_target
, inc
= x
->x_inc
= 0, x
->x_targettime
= 1e20
;
272 static void vline_tilde_stop(t_vline
*x
)
275 for (s1
= x
->x_list
; s1
; s1
= s2
)
276 s2
= s1
->s_next
, t_freebytes(s1
, sizeof(*s1
));
279 x
->x_inlet1
= x
->x_inlet2
= 0;
280 x
->x_target
= x
->x_value
;
281 x
->x_targettime
= 1e20
;
284 static void vline_tilde_float(t_vline
*x
, t_float f
)
286 double timenow
= clock_gettimesince(x
->x_referencetime
);
287 float inlet1
= (x
->x_inlet1
< 0 ? 0 : x
->x_inlet1
);
288 float inlet2
= x
->x_inlet2
;
289 double starttime
= timenow
+ inlet2
;
290 t_vseg
*s1
, *s2
, *deletefrom
= 0, *snew
;
291 if (PD_BIGORSMALL(f
))
294 /* negative delay input means stop and jump immediately to new value */
301 snew
= (t_vseg
*)t_getbytes(sizeof(*snew
));
302 /* check if we supplant the first item in the list. We supplant
303 an item by having an earlier starttime, or an equal starttime unless
304 the equal one was instantaneous and the new one isn't (in which case
305 we'll do a jump-and-slide starting at that time.) */
306 if (!x
->x_list
|| x
->x_list
->s_starttime
> starttime
||
307 (x
->x_list
->s_starttime
== starttime
&&
308 (x
->x_list
->s_targettime
> x
->x_list
->s_starttime
|| inlet1
<= 0)))
310 deletefrom
= x
->x_list
;
315 for (s1
= x
->x_list
; s2
= s1
->s_next
; s1
= s2
)
317 if (s2
->s_starttime
> starttime
||
318 (s2
->s_starttime
== starttime
&&
319 (s2
->s_targettime
> s2
->s_starttime
|| inlet1
<= 0)))
332 s1
= deletefrom
->s_next
;
333 t_freebytes(deletefrom
, sizeof(*deletefrom
));
338 snew
->s_starttime
= starttime
;
339 snew
->s_targettime
= starttime
+ inlet1
;
340 x
->x_inlet1
= x
->x_inlet2
= 0;
343 static void vline_tilde_dsp(t_vline
*x
, t_signal
**sp
)
345 dsp_add(vline_tilde_perform
, 3, x
, sp
[0]->s_vec
, sp
[0]->s_n
);
346 x
->x_samppermsec
= ((double)(sp
[0]->s_sr
)) / 1000;
347 x
->x_msecpersamp
= ((double)1000) / sp
[0]->s_sr
;
350 static void *vline_tilde_new(void)
352 t_vline
*x
= (t_vline
*)pd_new(vline_tilde_class
);
353 outlet_new(&x
->x_obj
, gensym("signal"));
354 floatinlet_new(&x
->x_obj
, &x
->x_inlet1
);
355 floatinlet_new(&x
->x_obj
, &x
->x_inlet2
);
356 x
->x_inlet1
= x
->x_inlet2
= 0;
357 x
->x_value
= x
->x_inc
= 0;
358 x
->x_referencetime
= clock_getlogicaltime();
360 x
->x_samppermsec
= 0;
361 x
->x_targettime
= 1e20
;
365 static void vline_tilde_setup(void)
367 vline_tilde_class
= class_new(gensym("vline~"), vline_tilde_new
,
368 (t_method
)vline_tilde_stop
, sizeof(t_vline
), 0, 0);
369 class_addfloat(vline_tilde_class
, (t_method
)vline_tilde_float
);
370 class_addmethod(vline_tilde_class
, (t_method
)vline_tilde_dsp
,
372 class_addmethod(vline_tilde_class
, (t_method
)vline_tilde_stop
,
376 /* -------------------------- snapshot~ ------------------------------ */
377 static t_class
*snapshot_tilde_class
;
379 typedef struct _snapshot
386 static void *snapshot_tilde_new(void)
388 t_snapshot
*x
= (t_snapshot
*)pd_new(snapshot_tilde_class
);
390 outlet_new(&x
->x_obj
, &s_float
);
395 static t_int
*snapshot_tilde_perform(t_int
*w
)
397 t_float
*in
= (t_float
*)(w
[1]);
398 t_float
*out
= (t_float
*)(w
[2]);
403 static void snapshot_tilde_dsp(t_snapshot
*x
, t_signal
**sp
)
405 dsp_add(snapshot_tilde_perform
, 2, sp
[0]->s_vec
+ (sp
[0]->s_n
-1),
409 static void snapshot_tilde_bang(t_snapshot
*x
)
411 outlet_float(x
->x_obj
.ob_outlet
, x
->x_value
);
414 static void snapshot_tilde_set(t_snapshot
*x
, t_floatarg f
)
419 static void snapshot_tilde_setup(void)
421 snapshot_tilde_class
= class_new(gensym("snapshot~"), snapshot_tilde_new
, 0,
422 sizeof(t_snapshot
), 0, 0);
423 CLASS_MAINSIGNALIN(snapshot_tilde_class
, t_snapshot
, x_f
);
424 class_addmethod(snapshot_tilde_class
, (t_method
)snapshot_tilde_dsp
,
426 class_addmethod(snapshot_tilde_class
, (t_method
)snapshot_tilde_set
,
427 gensym("set"), A_DEFFLOAT
, 0);
428 class_addbang(snapshot_tilde_class
, snapshot_tilde_bang
);
431 /* -------------------------- vsnapshot~ ------------------------------ */
432 static t_class
*vsnapshot_tilde_class
;
434 typedef struct _vsnapshot
441 float x_sampspermsec
;
445 static void *vsnapshot_tilde_new(void)
447 t_vsnapshot
*x
= (t_vsnapshot
*)pd_new(vsnapshot_tilde_class
);
448 outlet_new(&x
->x_obj
, &s_float
);
456 static t_int
*vsnapshot_tilde_perform(t_int
*w
)
458 t_float
*in
= (t_float
*)(w
[1]);
459 t_vsnapshot
*x
= (t_vsnapshot
*)(w
[2]);
460 t_float
*out
= x
->x_vec
;
462 for (i
= 0; i
< n
; i
++)
464 x
->x_time
= clock_getlogicaltime();
469 static void vsnapshot_tilde_dsp(t_vsnapshot
*x
, t_signal
**sp
)
475 t_freebytes(x
->x_vec
, x
->x_n
* sizeof(t_sample
));
476 x
->x_vec
= (t_sample
*)getbytes(n
* sizeof(t_sample
));
480 x
->x_sampspermsec
= sp
[0]->s_sr
/ 1000;
481 dsp_add(vsnapshot_tilde_perform
, 2, sp
[0]->s_vec
, x
);
484 static void vsnapshot_tilde_bang(t_vsnapshot
*x
)
489 int indx
= clock_gettimesince(x
->x_time
) * x
->x_sampspermsec
;
492 else if (indx
>= x
->x_n
)
494 val
= x
->x_vec
[indx
];
497 outlet_float(x
->x_obj
.ob_outlet
, val
);
500 static void vsnapshot_tilde_ff(t_vsnapshot
*x
)
503 t_freebytes(x
->x_vec
, x
->x_n
* sizeof(t_sample
));
506 static void vsnapshot_tilde_setup(void)
508 vsnapshot_tilde_class
= class_new(gensym("vsnapshot~"),
509 vsnapshot_tilde_new
, (t_method
)vsnapshot_tilde_ff
,
510 sizeof(t_vsnapshot
), 0, 0);
511 CLASS_MAINSIGNALIN(vsnapshot_tilde_class
, t_vsnapshot
, x_f
);
512 class_addmethod(vsnapshot_tilde_class
, (t_method
)vsnapshot_tilde_dsp
, gensym("dsp"), 0);
513 class_addbang(vsnapshot_tilde_class
, vsnapshot_tilde_bang
);
517 /* ---------------- env~ - simple envelope follower. ----------------- */
519 #define MAXOVERLAP 10
520 #define MAXVSTAKEN 64
522 typedef struct sigenv
524 t_object x_obj
; /* header */
525 void *x_outlet
; /* a "float" outlet */
526 void *x_clock
; /* a "clock" object */
527 float *x_buf
; /* a Hanning window */
528 int x_phase
; /* number of points since last output */
529 int x_period
; /* requested period of output */
530 int x_realperiod
; /* period rounded up to vecsize multiple */
531 int x_npoints
; /* analysis window size in samples */
532 float x_result
; /* result to output */
533 float x_sumbuf
[MAXOVERLAP
]; /* summing buffer */
537 t_class
*env_tilde_class
;
538 static void env_tilde_tick(t_sigenv
*x
);
540 static void *env_tilde_new(t_floatarg fnpoints
, t_floatarg fperiod
)
542 int npoints
= fnpoints
;
543 int period
= fperiod
;
548 if (npoints
< 1) npoints
= 1024;
549 if (period
< 1) period
= npoints
/2;
550 if (period
< npoints
/ MAXOVERLAP
+ 1)
551 period
= npoints
/ MAXOVERLAP
+ 1;
552 if (!(buf
= getbytes(sizeof(float) * (npoints
+ MAXVSTAKEN
))))
554 error("env: couldn't allocate buffer");
557 x
= (t_sigenv
*)pd_new(env_tilde_class
);
559 x
->x_npoints
= npoints
;
561 x
->x_period
= period
;
562 for (i
= 0; i
< MAXOVERLAP
; i
++) x
->x_sumbuf
[i
] = 0;
563 for (i
= 0; i
< npoints
; i
++)
564 buf
[i
] = (1. - cos((2 * 3.14159 * i
) / npoints
))/npoints
;
565 for (; i
< npoints
+MAXVSTAKEN
; i
++) buf
[i
] = 0;
566 x
->x_clock
= clock_new(x
, (t_method
)env_tilde_tick
);
567 x
->x_outlet
= outlet_new(&x
->x_obj
, gensym("float"));
572 static t_int
*env_tilde_perform(t_int
*w
)
574 t_sigenv
*x
= (t_sigenv
*)(w
[1]);
575 t_float
*in
= (t_float
*)(w
[2]);
580 for (count
= x
->x_phase
, sump
= x
->x_sumbuf
;
581 count
< x
->x_npoints
; count
+= x
->x_realperiod
, sump
++)
583 float *hp
= x
->x_buf
+ count
;
588 for (i
= 0; i
< n
; i
++)
591 sum
+= *hp
++ * (*fp
* *fp
);
599 x
->x_result
= x
->x_sumbuf
[0];
600 for (count
= x
->x_realperiod
, sump
= x
->x_sumbuf
;
601 count
< x
->x_npoints
; count
+= x
->x_realperiod
, sump
++)
604 x
->x_phase
= x
->x_realperiod
- n
;
605 clock_delay(x
->x_clock
, 0L);
610 static void env_tilde_dsp(t_sigenv
*x
, t_signal
**sp
)
612 if (x
->x_period
% sp
[0]->s_n
) x
->x_realperiod
=
613 x
->x_period
+ sp
[0]->s_n
- (x
->x_period
% sp
[0]->s_n
);
614 else x
->x_realperiod
= x
->x_period
;
615 dsp_add(env_tilde_perform
, 3, x
, sp
[0]->s_vec
, sp
[0]->s_n
);
616 if (sp
[0]->s_n
> MAXVSTAKEN
) bug("env_tilde_dsp");
619 static void env_tilde_tick(t_sigenv
*x
) /* callback function for the clock */
621 outlet_float(x
->x_outlet
, powtodb(x
->x_result
));
624 static void env_tilde_ff(t_sigenv
*x
) /* cleanup on free */
626 clock_free(x
->x_clock
);
627 freebytes(x
->x_buf
, (x
->x_npoints
+ MAXVSTAKEN
) * sizeof(float));
631 void env_tilde_setup(void )
633 env_tilde_class
= class_new(gensym("env~"), (t_newmethod
)env_tilde_new
,
634 (t_method
)env_tilde_ff
, sizeof(t_sigenv
), 0, A_DEFFLOAT
, A_DEFFLOAT
, 0);
635 CLASS_MAINSIGNALIN(env_tilde_class
, t_sigenv
, x_f
);
636 class_addmethod(env_tilde_class
, (t_method
)env_tilde_dsp
, gensym("dsp"), 0);
639 /* --------------------- threshold~ ----------------------------- */
641 static t_class
*threshold_tilde_class
;
643 typedef struct _threshold_tilde
646 t_outlet
*x_outlet1
; /* bang out for high thresh */
647 t_outlet
*x_outlet2
; /* bang out for low thresh */
648 t_clock
*x_clock
; /* wakeup for message output */
649 float x_f
; /* scalar inlet */
650 int x_state
; /* 1 = high, 0 = low */
651 float x_hithresh
; /* value of high threshold */
652 float x_lothresh
; /* value of low threshold */
653 float x_deadwait
; /* msec remaining in dead period */
654 float x_msecpertick
; /* msec per DSP tick */
655 float x_hideadtime
; /* hi dead time in msec */
656 float x_lodeadtime
; /* lo dead time in msec */
659 static void threshold_tilde_tick(t_threshold_tilde
*x
);
660 static void threshold_tilde_set(t_threshold_tilde
*x
,
661 t_floatarg hithresh
, t_floatarg hideadtime
,
662 t_floatarg lothresh
, t_floatarg lodeadtime
);
664 static t_threshold_tilde
*threshold_tilde_new(t_floatarg hithresh
,
665 t_floatarg hideadtime
, t_floatarg lothresh
, t_floatarg lodeadtime
)
667 t_threshold_tilde
*x
= (t_threshold_tilde
*)
668 pd_new(threshold_tilde_class
);
669 x
->x_state
= 0; /* low state */
670 x
->x_deadwait
= 0; /* no dead time */
671 x
->x_clock
= clock_new(x
, (t_method
)threshold_tilde_tick
);
672 x
->x_outlet1
= outlet_new(&x
->x_obj
, &s_bang
);
673 x
->x_outlet2
= outlet_new(&x
->x_obj
, &s_bang
);
674 inlet_new(&x
->x_obj
, &x
->x_obj
.ob_pd
, &s_float
, gensym("ft1"));
675 x
->x_msecpertick
= 0.;
677 threshold_tilde_set(x
, hithresh
, hideadtime
, lothresh
, lodeadtime
);
681 /* "set" message to specify thresholds and dead times */
682 static void threshold_tilde_set(t_threshold_tilde
*x
,
683 t_floatarg hithresh
, t_floatarg hideadtime
,
684 t_floatarg lothresh
, t_floatarg lodeadtime
)
686 if (lothresh
> hithresh
)
688 x
->x_hithresh
= hithresh
;
689 x
->x_hideadtime
= hideadtime
;
690 x
->x_lothresh
= lothresh
;
691 x
->x_lodeadtime
= lodeadtime
;
694 /* number in inlet sets state -- note incompatible with JMAX which used
695 "int" message for this, impossible here because of auto signal conversion */
696 static void threshold_tilde_ft1(t_threshold_tilde
*x
, t_floatarg f
)
698 x
->x_state
= (f
!= 0);
702 static void threshold_tilde_tick(t_threshold_tilde
*x
)
705 outlet_bang(x
->x_outlet1
);
706 else outlet_bang(x
->x_outlet2
);
709 static t_int
*threshold_tilde_perform(t_int
*w
)
711 float *in1
= (float *)(w
[1]);
712 t_threshold_tilde
*x
= (t_threshold_tilde
*)(w
[2]);
713 int n
= (t_int
)(w
[3]);
714 if (x
->x_deadwait
> 0)
715 x
->x_deadwait
-= x
->x_msecpertick
;
718 /* we're high; look for low sample */
721 if (*in1
< x
->x_lothresh
)
723 clock_delay(x
->x_clock
, 0L);
725 x
->x_deadwait
= x
->x_lodeadtime
;
732 /* we're low; look for high sample */
735 if (*in1
>= x
->x_hithresh
)
737 clock_delay(x
->x_clock
, 0L);
739 x
->x_deadwait
= x
->x_hideadtime
;
748 void threshold_tilde_dsp(t_threshold_tilde
*x
, t_signal
**sp
)
750 x
->x_msecpertick
= 1000. * sp
[0]->s_n
/ sp
[0]->s_sr
;
751 dsp_add(threshold_tilde_perform
, 3, sp
[0]->s_vec
, x
, sp
[0]->s_n
);
754 static void threshold_tilde_ff(t_threshold_tilde
*x
)
756 clock_free(x
->x_clock
);
759 static void threshold_tilde_setup( void)
761 threshold_tilde_class
= class_new(gensym("threshold~"),
762 (t_newmethod
)threshold_tilde_new
, (t_method
)threshold_tilde_ff
,
763 sizeof(t_threshold_tilde
), 0,
764 A_DEFFLOAT
, A_DEFFLOAT
, A_DEFFLOAT
, A_DEFFLOAT
, 0);
765 CLASS_MAINSIGNALIN(threshold_tilde_class
, t_threshold_tilde
, x_f
);
766 class_addmethod(threshold_tilde_class
, (t_method
)threshold_tilde_set
,
767 gensym("set"), A_FLOAT
, A_FLOAT
, A_FLOAT
, A_FLOAT
, 0);
768 class_addmethod(threshold_tilde_class
, (t_method
)threshold_tilde_ft1
,
769 gensym("ft1"), A_FLOAT
, 0);
770 class_addmethod(threshold_tilde_class
, (t_method
)threshold_tilde_dsp
,
774 /* ------------------------ global setup routine ------------------------- */
776 void d_ctl_setup(void)
781 snapshot_tilde_setup();
782 vsnapshot_tilde_setup();
784 threshold_tilde_setup();