diff options
Diffstat (limited to 'apps/plugins/pdbox/PDa/src/x_time.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/src/x_time.c | 1040 |
1 files changed, 1040 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/src/x_time.c b/apps/plugins/pdbox/PDa/src/x_time.c new file mode 100644 index 0000000000..580a30b36d --- /dev/null +++ b/apps/plugins/pdbox/PDa/src/x_time.c | |||
@@ -0,0 +1,1040 @@ | |||
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 | /* clock objects */ | ||
6 | |||
7 | #include "m_pd.h" | ||
8 | #include <stdio.h> | ||
9 | /* -------------------------- delay ------------------------------ */ | ||
10 | static t_class *delay_class; | ||
11 | |||
12 | typedef struct _delay | ||
13 | { | ||
14 | t_object x_obj; | ||
15 | t_clock *x_clock; | ||
16 | double x_deltime; | ||
17 | } t_delay; | ||
18 | |||
19 | static void delay_bang(t_delay *x) | ||
20 | { | ||
21 | clock_delay(x->x_clock, x->x_deltime); | ||
22 | } | ||
23 | |||
24 | static void delay_stop(t_delay *x) | ||
25 | { | ||
26 | clock_unset(x->x_clock); | ||
27 | } | ||
28 | |||
29 | static void delay_ft1(t_delay *x, t_floatarg g) | ||
30 | { | ||
31 | if (g < 0) g = 0; | ||
32 | x->x_deltime = g; | ||
33 | } | ||
34 | |||
35 | static void delay_float(t_delay *x, t_float f) | ||
36 | { | ||
37 | delay_ft1(x, f); | ||
38 | delay_bang(x); | ||
39 | } | ||
40 | |||
41 | static void delay_tick(t_delay *x) | ||
42 | { | ||
43 | outlet_bang(x->x_obj.ob_outlet); | ||
44 | } | ||
45 | |||
46 | static void delay_free(t_delay *x) | ||
47 | { | ||
48 | clock_free(x->x_clock); | ||
49 | } | ||
50 | |||
51 | static void *delay_new(t_floatarg f) | ||
52 | { | ||
53 | t_delay *x = (t_delay *)pd_new(delay_class); | ||
54 | delay_ft1(x, f); | ||
55 | x->x_clock = clock_new(x, (t_method)delay_tick); | ||
56 | outlet_new(&x->x_obj, gensym("bang")); | ||
57 | inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1")); | ||
58 | return (x); | ||
59 | } | ||
60 | |||
61 | static void delay_setup(void) | ||
62 | { | ||
63 | delay_class = class_new(gensym("delay"), (t_newmethod)delay_new, | ||
64 | (t_method)delay_free, sizeof(t_delay), 0, A_DEFFLOAT, 0); | ||
65 | class_addcreator((t_newmethod)delay_new, gensym("del"), A_DEFFLOAT, 0); | ||
66 | class_addbang(delay_class, delay_bang); | ||
67 | class_addmethod(delay_class, (t_method)delay_stop, gensym("stop"), 0); | ||
68 | class_addmethod(delay_class, (t_method)delay_ft1, | ||
69 | gensym("ft1"), A_FLOAT, 0); | ||
70 | class_addfloat(delay_class, (t_method)delay_float); | ||
71 | } | ||
72 | |||
73 | /* -------------------------- metro ------------------------------ */ | ||
74 | static t_class *metro_class; | ||
75 | |||
76 | typedef struct _metro | ||
77 | { | ||
78 | t_object x_obj; | ||
79 | t_clock *x_clock; | ||
80 | double x_deltime; | ||
81 | int x_hit; | ||
82 | } t_metro; | ||
83 | |||
84 | static void metro_tick(t_metro *x) | ||
85 | { | ||
86 | x->x_hit = 0; | ||
87 | outlet_bang(x->x_obj.ob_outlet); | ||
88 | if (!x->x_hit) clock_delay(x->x_clock, x->x_deltime); | ||
89 | } | ||
90 | |||
91 | static void metro_float(t_metro *x, t_float f) | ||
92 | { | ||
93 | if (f != 0) metro_tick(x); | ||
94 | else clock_unset(x->x_clock); | ||
95 | x->x_hit = 1; | ||
96 | } | ||
97 | |||
98 | static void metro_bang(t_metro *x) | ||
99 | { | ||
100 | metro_float(x, 1); | ||
101 | } | ||
102 | |||
103 | static void metro_stop(t_metro *x) | ||
104 | { | ||
105 | metro_float(x, 0); | ||
106 | } | ||
107 | |||
108 | static void metro_ft1(t_metro *x, t_floatarg g) | ||
109 | { | ||
110 | if (g < 1) g = 1; | ||
111 | x->x_deltime = g; | ||
112 | } | ||
113 | |||
114 | static void metro_free(t_metro *x) | ||
115 | { | ||
116 | clock_free(x->x_clock); | ||
117 | } | ||
118 | |||
119 | static void *metro_new(t_floatarg f) | ||
120 | { | ||
121 | t_metro *x = (t_metro *)pd_new(metro_class); | ||
122 | metro_ft1(x, f); | ||
123 | x->x_hit = 0; | ||
124 | x->x_clock = clock_new(x, (t_method)metro_tick); | ||
125 | outlet_new(&x->x_obj, gensym("bang")); | ||
126 | inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1")); | ||
127 | return (x); | ||
128 | } | ||
129 | |||
130 | static void metro_setup(void) | ||
131 | { | ||
132 | metro_class = class_new(gensym("metro"), (t_newmethod)metro_new, | ||
133 | (t_method)metro_free, sizeof(t_metro), 0, A_DEFFLOAT, 0); | ||
134 | class_addbang(metro_class, metro_bang); | ||
135 | class_addmethod(metro_class, (t_method)metro_stop, gensym("stop"), 0); | ||
136 | class_addmethod(metro_class, (t_method)metro_ft1, gensym("ft1"), | ||
137 | A_FLOAT, 0); | ||
138 | class_addfloat(metro_class, (t_method)metro_float); | ||
139 | } | ||
140 | |||
141 | /* -------------------------- line ------------------------------ */ | ||
142 | static t_class *line_class; | ||
143 | |||
144 | typedef struct _line | ||
145 | { | ||
146 | t_object x_obj; | ||
147 | t_clock *x_clock; | ||
148 | double x_targettime; | ||
149 | t_float x_targetval; | ||
150 | double x_prevtime; | ||
151 | t_float x_setval; | ||
152 | int x_gotinlet; | ||
153 | t_float x_grain; | ||
154 | double x_1overtimediff; | ||
155 | double x_in1val; | ||
156 | } t_line; | ||
157 | |||
158 | static void line_tick(t_line *x) | ||
159 | { | ||
160 | double timenow = clock_getsystime(); | ||
161 | double msectogo = - clock_gettimesince(x->x_targettime); | ||
162 | if (msectogo < 1E-9) | ||
163 | { | ||
164 | outlet_float(x->x_obj.ob_outlet, x->x_targetval); | ||
165 | } | ||
166 | else | ||
167 | { | ||
168 | outlet_float(x->x_obj.ob_outlet, | ||
169 | x->x_setval + x->x_1overtimediff * (timenow - x->x_prevtime) | ||
170 | * (x->x_targetval - x->x_setval)); | ||
171 | clock_delay(x->x_clock, | ||
172 | (x->x_grain > msectogo ? msectogo : x->x_grain)); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | static void line_float(t_line *x, t_float f) | ||
177 | { | ||
178 | double timenow = clock_getsystime(); | ||
179 | if (x->x_gotinlet && x->x_in1val > 0) | ||
180 | { | ||
181 | if (timenow > x->x_targettime) x->x_setval = x->x_targetval; | ||
182 | else x->x_setval = x->x_setval + x->x_1overtimediff * | ||
183 | (timenow - x->x_prevtime) | ||
184 | * (x->x_targetval - x->x_setval); | ||
185 | x->x_prevtime = timenow; | ||
186 | x->x_targettime = clock_getsystimeafter(x->x_in1val); | ||
187 | x->x_targetval = f; | ||
188 | line_tick(x); | ||
189 | x->x_gotinlet = 0; | ||
190 | x->x_1overtimediff = 1./ (x->x_targettime - timenow); | ||
191 | clock_delay(x->x_clock, | ||
192 | (x->x_grain > x->x_in1val ? x->x_in1val : x->x_grain)); | ||
193 | |||
194 | } | ||
195 | else | ||
196 | { | ||
197 | clock_unset(x->x_clock); | ||
198 | x->x_targetval = x->x_setval = f; | ||
199 | outlet_float(x->x_obj.ob_outlet, f); | ||
200 | } | ||
201 | x->x_gotinlet = 0; | ||
202 | } | ||
203 | |||
204 | static void line_ft1(t_line *x, t_floatarg g) | ||
205 | { | ||
206 | x->x_in1val = g; | ||
207 | x->x_gotinlet = 1; | ||
208 | } | ||
209 | |||
210 | static void line_stop(t_line *x) | ||
211 | { | ||
212 | x->x_targetval = x->x_setval; | ||
213 | clock_unset(x->x_clock); | ||
214 | } | ||
215 | |||
216 | static void line_free(t_line *x) | ||
217 | { | ||
218 | clock_free(x->x_clock); | ||
219 | } | ||
220 | |||
221 | static void *line_new(t_floatarg f, t_floatarg grain) | ||
222 | { | ||
223 | t_line *x = (t_line *)pd_new(line_class); | ||
224 | x->x_targetval = x->x_setval = f; | ||
225 | x->x_gotinlet = 0; | ||
226 | x->x_1overtimediff = 1; | ||
227 | x->x_clock = clock_new(x, (t_method)line_tick); | ||
228 | x->x_targettime = x->x_prevtime = clock_getsystime(); | ||
229 | if (grain <= 0) grain = 20; | ||
230 | x->x_grain = grain; | ||
231 | outlet_new(&x->x_obj, gensym("float")); | ||
232 | inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1")); | ||
233 | return (x); | ||
234 | } | ||
235 | |||
236 | static void line_setup(void) | ||
237 | { | ||
238 | line_class = class_new(gensym("line"), (t_newmethod)line_new, | ||
239 | (t_method)line_free, sizeof(t_line), 0, A_DEFFLOAT, A_DEFFLOAT, 0); | ||
240 | class_addmethod(line_class, (t_method)line_ft1, | ||
241 | gensym("ft1"), A_FLOAT, 0); | ||
242 | class_addmethod(line_class, (t_method)line_stop, | ||
243 | gensym("stop"), 0); | ||
244 | class_addfloat(line_class, (t_method)line_float); | ||
245 | } | ||
246 | |||
247 | /* -------------------------- timer ------------------------------ */ | ||
248 | static t_class *timer_class; | ||
249 | |||
250 | typedef struct _timer | ||
251 | { | ||
252 | t_object x_obj; | ||
253 | t_time x_settime; | ||
254 | } t_timer; | ||
255 | |||
256 | static void timer_bang(t_timer *x) | ||
257 | { | ||
258 | x->x_settime = clock_getsystime(); | ||
259 | } | ||
260 | |||
261 | static void timer_bang2(t_timer *x) | ||
262 | { | ||
263 | t_time diff = clock_gettimesince(x->x_settime); | ||
264 | outlet_float(x->x_obj.ob_outlet, diff); | ||
265 | } | ||
266 | |||
267 | static void *timer_new(t_floatarg f) | ||
268 | { | ||
269 | t_timer *x = (t_timer *)pd_new(timer_class); | ||
270 | timer_bang(x); | ||
271 | outlet_new(&x->x_obj, gensym("float")); | ||
272 | inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2")); | ||
273 | return (x); | ||
274 | } | ||
275 | |||
276 | static void timer_setup(void) | ||
277 | { | ||
278 | timer_class = class_new(gensym("timer"), (t_newmethod)timer_new, 0, | ||
279 | sizeof(t_timer), 0, A_DEFFLOAT, 0); | ||
280 | class_addbang(timer_class, timer_bang); | ||
281 | class_addmethod(timer_class, (t_method)timer_bang2, gensym("bang2"), 0); | ||
282 | } | ||
283 | |||
284 | |||
285 | /* -------------------------- pipe -------------------------- */ | ||
286 | |||
287 | static t_class *pipe_class; | ||
288 | |||
289 | typedef struct _hang | ||
290 | { | ||
291 | t_clock *h_clock; | ||
292 | struct _hang *h_next; | ||
293 | struct _pipe *h_owner; | ||
294 | t_gpointer *h_gp; | ||
295 | union word h_vec[1]; /* not the actual number. */ | ||
296 | } t_hang; | ||
297 | |||
298 | typedef struct pipeout | ||
299 | { | ||
300 | t_atom p_atom; | ||
301 | t_outlet *p_outlet; | ||
302 | } t_pipeout; | ||
303 | |||
304 | typedef struct _pipe | ||
305 | { | ||
306 | t_object x_obj; | ||
307 | int x_n; | ||
308 | int x_nptr; | ||
309 | float x_deltime; | ||
310 | t_pipeout *x_vec; | ||
311 | t_gpointer *x_gp; | ||
312 | t_hang *x_hang; | ||
313 | } t_pipe; | ||
314 | |||
315 | static void *pipe_new(t_symbol *s, int argc, t_atom *argv) | ||
316 | { | ||
317 | t_pipe *x = (t_pipe *)pd_new(pipe_class); | ||
318 | t_atom defarg, *ap; | ||
319 | t_pipeout *vec, *vp; | ||
320 | t_gpointer *gp; | ||
321 | int nptr = 0; | ||
322 | int i; | ||
323 | float deltime; | ||
324 | if (argc) | ||
325 | { | ||
326 | if (argv[argc-1].a_type != A_FLOAT) | ||
327 | { | ||
328 | char stupid[80]; | ||
329 | atom_string(&argv[argc-1], stupid, 79); | ||
330 | post("pipe: %s: bad time delay value", stupid); | ||
331 | deltime = 0; | ||
332 | } | ||
333 | else deltime = argv[argc-1].a_w.w_float; | ||
334 | argc--; | ||
335 | } | ||
336 | else deltime = 0; | ||
337 | if (!argc) | ||
338 | { | ||
339 | argv = &defarg; | ||
340 | argc = 1; | ||
341 | SETFLOAT(&defarg, 0); | ||
342 | } | ||
343 | x->x_n = argc; | ||
344 | vec = x->x_vec = (t_pipeout *)getbytes(argc * sizeof(*x->x_vec)); | ||
345 | |||
346 | for (i = argc, ap = argv; i--; ap++) | ||
347 | if (ap->a_type == A_SYMBOL && *ap->a_w.w_symbol->s_name == 'p') | ||
348 | nptr++; | ||
349 | |||
350 | gp = x->x_gp = (t_gpointer *)t_getbytes(nptr * sizeof (*gp)); | ||
351 | x->x_nptr = nptr; | ||
352 | |||
353 | for (i = 0, vp = vec, ap = argv; i < argc; i++, ap++, vp++) | ||
354 | { | ||
355 | if (ap->a_type == A_FLOAT) | ||
356 | { | ||
357 | vp->p_atom = *ap; | ||
358 | vp->p_outlet = outlet_new(&x->x_obj, &s_float); | ||
359 | if (i) floatinlet_new(&x->x_obj, &vp->p_atom.a_w.w_float); | ||
360 | } | ||
361 | else if (ap->a_type == A_SYMBOL) | ||
362 | { | ||
363 | char c = *ap->a_w.w_symbol->s_name; | ||
364 | if (c == 's') | ||
365 | { | ||
366 | SETSYMBOL(&vp->p_atom, &s_symbol); | ||
367 | vp->p_outlet = outlet_new(&x->x_obj, &s_symbol); | ||
368 | if (i) symbolinlet_new(&x->x_obj, &vp->p_atom.a_w.w_symbol); | ||
369 | } | ||
370 | else if (c == 'p') | ||
371 | { | ||
372 | vp->p_atom.a_type = A_POINTER; | ||
373 | vp->p_atom.a_w.w_gpointer = gp; | ||
374 | gpointer_init(gp); | ||
375 | vp->p_outlet = outlet_new(&x->x_obj, &s_pointer); | ||
376 | if (i) pointerinlet_new(&x->x_obj, gp); | ||
377 | gp++; | ||
378 | } | ||
379 | else | ||
380 | { | ||
381 | if (c != 'f') error("pack: %s: bad type", | ||
382 | ap->a_w.w_symbol->s_name); | ||
383 | SETFLOAT(&vp->p_atom, 0); | ||
384 | vp->p_outlet = outlet_new(&x->x_obj, &s_float); | ||
385 | if (i) floatinlet_new(&x->x_obj, &vp->p_atom.a_w.w_float); | ||
386 | } | ||
387 | } | ||
388 | } | ||
389 | floatinlet_new(&x->x_obj, &x->x_deltime); | ||
390 | x->x_hang = 0; | ||
391 | x->x_deltime = deltime; | ||
392 | return (x); | ||
393 | } | ||
394 | |||
395 | static void hang_free(t_hang *h) | ||
396 | { | ||
397 | t_pipe *x = h->h_owner; | ||
398 | t_gpointer *gp; | ||
399 | int i; | ||
400 | for (gp = h->h_gp, i = x->x_nptr; i--; gp++) | ||
401 | gpointer_unset(gp); | ||
402 | freebytes(h->h_gp, x->x_nptr * sizeof(*h->h_gp)); | ||
403 | clock_free(h->h_clock); | ||
404 | freebytes(h, sizeof(*h) + (x->x_n - 1) * sizeof(*h->h_vec)); | ||
405 | } | ||
406 | |||
407 | static void hang_tick(t_hang *h) | ||
408 | { | ||
409 | t_pipe *x = h->h_owner; | ||
410 | t_hang *h2, *h3; | ||
411 | t_pipeout *p; | ||
412 | int i; | ||
413 | union word *w; | ||
414 | if (x->x_hang == h) x->x_hang = h->h_next; | ||
415 | else for (h2 = x->x_hang; h3 = h2->h_next; h2 = h3) | ||
416 | { | ||
417 | if (h3 == h) | ||
418 | { | ||
419 | h2->h_next = h3->h_next; | ||
420 | break; | ||
421 | } | ||
422 | } | ||
423 | for (i = x->x_n, p = x->x_vec + (x->x_n - 1), w = h->h_vec + (x->x_n - 1); | ||
424 | i--; p--, w--) | ||
425 | { | ||
426 | switch (p->p_atom.a_type) | ||
427 | { | ||
428 | case A_FLOAT: outlet_float(p->p_outlet, w->w_float); break; | ||
429 | case A_SYMBOL: outlet_symbol(p->p_outlet, w->w_symbol); break; | ||
430 | case A_POINTER: | ||
431 | if (gpointer_check(w->w_gpointer, 1)) | ||
432 | outlet_pointer(p->p_outlet, w->w_gpointer); | ||
433 | else post("pipe: stale pointer"); | ||
434 | break; | ||
435 | } | ||
436 | } | ||
437 | hang_free(h); | ||
438 | } | ||
439 | |||
440 | static void pipe_list(t_pipe *x, t_symbol *s, int ac, t_atom *av) | ||
441 | { | ||
442 | t_hang *h = (t_hang *) | ||
443 | getbytes(sizeof(*h) + (x->x_n - 1) * sizeof(*h->h_vec)); | ||
444 | t_gpointer *gp, *gp2; | ||
445 | t_pipeout *p; | ||
446 | int i, n = x->x_n; | ||
447 | t_atom *ap; | ||
448 | t_word *w; | ||
449 | h->h_gp = (t_gpointer *)getbytes(x->x_nptr * sizeof(t_gpointer)); | ||
450 | if (ac > n) ac = n; | ||
451 | for (i = 0, gp = x->x_gp, p = x->x_vec, ap = av; i < ac; | ||
452 | i++, p++, ap++) | ||
453 | { | ||
454 | switch (p->p_atom.a_type) | ||
455 | { | ||
456 | case A_FLOAT: p->p_atom.a_w.w_float = atom_getfloat(ap); break; | ||
457 | case A_SYMBOL: p->p_atom.a_w.w_symbol = atom_getsymbol(ap); break; | ||
458 | case A_POINTER: | ||
459 | gpointer_unset(gp); | ||
460 | if (ap->a_type != A_POINTER) | ||
461 | post("pipe: bad pointer"); | ||
462 | else | ||
463 | { | ||
464 | *gp = *(ap->a_w.w_gpointer); | ||
465 | if (gp->gp_stub) gp->gp_stub->gs_refcount++; | ||
466 | } | ||
467 | gp++; | ||
468 | } | ||
469 | } | ||
470 | for (i = 0, gp = x->x_gp, gp2 = h->h_gp, p = x->x_vec, w = h->h_vec; | ||
471 | i < n; i++, p++, w++) | ||
472 | { | ||
473 | if (p->p_atom.a_type == A_POINTER) | ||
474 | { | ||
475 | if (gp->gp_stub) gp->gp_stub->gs_refcount++; | ||
476 | w->w_gpointer = gp2; | ||
477 | *gp2++ = *gp++; | ||
478 | } | ||
479 | else *w = p->p_atom.a_w; | ||
480 | } | ||
481 | h->h_next = x->x_hang; | ||
482 | x->x_hang = h; | ||
483 | h->h_owner = x; | ||
484 | h->h_clock = clock_new(h, (t_method)hang_tick); | ||
485 | clock_delay(h->h_clock, (x->x_deltime >= 0 ? x->x_deltime : 0)); | ||
486 | } | ||
487 | |||
488 | static void pipe_flush(t_pipe *x) | ||
489 | { | ||
490 | while (x->x_hang) hang_tick(x->x_hang); | ||
491 | } | ||
492 | |||
493 | static void pipe_clear(t_pipe *x) | ||
494 | { | ||
495 | t_hang *hang; | ||
496 | while (hang = x->x_hang) | ||
497 | { | ||
498 | x->x_hang = hang->h_next; | ||
499 | hang_free(hang); | ||
500 | } | ||
501 | } | ||
502 | |||
503 | static void pipe_setup(void) | ||
504 | { | ||
505 | pipe_class = class_new(gensym("pipe"), | ||
506 | (t_newmethod)pipe_new, (t_method)pipe_clear, | ||
507 | sizeof(t_pipe), 0, A_GIMME, 0); | ||
508 | class_addlist(pipe_class, pipe_list); | ||
509 | class_addmethod(pipe_class, (t_method)pipe_flush, gensym("flush"), 0); | ||
510 | class_addmethod(pipe_class, (t_method)pipe_clear, gensym("clear"), 0); | ||
511 | } | ||
512 | |||
513 | void x_time_setup(void) | ||
514 | { | ||
515 | delay_setup(); | ||
516 | metro_setup(); | ||
517 | line_setup(); | ||
518 | timer_setup(); | ||
519 | pipe_setup(); | ||
520 | } | ||
521 | /* Copyright (c) 1997-1999 Miller Puckette. | ||
522 | * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
523 | * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
524 | |||
525 | /* clock objects */ | ||
526 | |||
527 | #include "m_pd.h" | ||
528 | #include <stdio.h> | ||
529 | /* -------------------------- delay ------------------------------ */ | ||
530 | static t_class *delay_class; | ||
531 | |||
532 | typedef struct _delay | ||
533 | { | ||
534 | t_object x_obj; | ||
535 | t_clock *x_clock; | ||
536 | double x_deltime; | ||
537 | } t_delay; | ||
538 | |||
539 | static void delay_bang(t_delay *x) | ||
540 | { | ||
541 | clock_delay(x->x_clock, x->x_deltime); | ||
542 | } | ||
543 | |||
544 | static void delay_stop(t_delay *x) | ||
545 | { | ||
546 | clock_unset(x->x_clock); | ||
547 | } | ||
548 | |||
549 | static void delay_ft1(t_delay *x, t_floatarg g) | ||
550 | { | ||
551 | if (g < 0) g = 0; | ||
552 | x->x_deltime = g; | ||
553 | } | ||
554 | |||
555 | static void delay_float(t_delay *x, t_float f) | ||
556 | { | ||
557 | delay_ft1(x, f); | ||
558 | delay_bang(x); | ||
559 | } | ||
560 | |||
561 | static void delay_tick(t_delay *x) | ||
562 | { | ||
563 | outlet_bang(x->x_obj.ob_outlet); | ||
564 | } | ||
565 | |||
566 | static void delay_free(t_delay *x) | ||
567 | { | ||
568 | clock_free(x->x_clock); | ||
569 | } | ||
570 | |||
571 | static void *delay_new(t_floatarg f) | ||
572 | { | ||
573 | t_delay *x = (t_delay *)pd_new(delay_class); | ||
574 | delay_ft1(x, f); | ||
575 | x->x_clock = clock_new(x, (t_method)delay_tick); | ||
576 | outlet_new(&x->x_obj, gensym("bang")); | ||
577 | inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1")); | ||
578 | return (x); | ||
579 | } | ||
580 | |||
581 | static void delay_setup(void) | ||
582 | { | ||
583 | delay_class = class_new(gensym("delay"), (t_newmethod)delay_new, | ||
584 | (t_method)delay_free, sizeof(t_delay), 0, A_DEFFLOAT, 0); | ||
585 | class_addcreator((t_newmethod)delay_new, gensym("del"), A_DEFFLOAT, 0); | ||
586 | class_addbang(delay_class, delay_bang); | ||
587 | class_addmethod(delay_class, (t_method)delay_stop, gensym("stop"), 0); | ||
588 | class_addmethod(delay_class, (t_method)delay_ft1, | ||
589 | gensym("ft1"), A_FLOAT, 0); | ||
590 | class_addfloat(delay_class, (t_method)delay_float); | ||
591 | } | ||
592 | |||
593 | /* -------------------------- metro ------------------------------ */ | ||
594 | static t_class *metro_class; | ||
595 | |||
596 | typedef struct _metro | ||
597 | { | ||
598 | t_object x_obj; | ||
599 | t_clock *x_clock; | ||
600 | double x_deltime; | ||
601 | int x_hit; | ||
602 | } t_metro; | ||
603 | |||
604 | static void metro_tick(t_metro *x) | ||
605 | { | ||
606 | x->x_hit = 0; | ||
607 | outlet_bang(x->x_obj.ob_outlet); | ||
608 | if (!x->x_hit) clock_delay(x->x_clock, x->x_deltime); | ||
609 | } | ||
610 | |||
611 | static void metro_float(t_metro *x, t_float f) | ||
612 | { | ||
613 | if (f != 0) metro_tick(x); | ||
614 | else clock_unset(x->x_clock); | ||
615 | x->x_hit = 1; | ||
616 | } | ||
617 | |||
618 | static void metro_bang(t_metro *x) | ||
619 | { | ||
620 | metro_float(x, 1); | ||
621 | } | ||
622 | |||
623 | static void metro_stop(t_metro *x) | ||
624 | { | ||
625 | metro_float(x, 0); | ||
626 | } | ||
627 | |||
628 | static void metro_ft1(t_metro *x, t_floatarg g) | ||
629 | { | ||
630 | if (g < 1) g = 1; | ||
631 | x->x_deltime = g; | ||
632 | } | ||
633 | |||
634 | static void metro_free(t_metro *x) | ||
635 | { | ||
636 | clock_free(x->x_clock); | ||
637 | } | ||
638 | |||
639 | static void *metro_new(t_floatarg f) | ||
640 | { | ||
641 | t_metro *x = (t_metro *)pd_new(metro_class); | ||
642 | metro_ft1(x, f); | ||
643 | x->x_hit = 0; | ||
644 | x->x_clock = clock_new(x, (t_method)metro_tick); | ||
645 | outlet_new(&x->x_obj, gensym("bang")); | ||
646 | inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1")); | ||
647 | return (x); | ||
648 | } | ||
649 | |||
650 | static void metro_setup(void) | ||
651 | { | ||
652 | metro_class = class_new(gensym("metro"), (t_newmethod)metro_new, | ||
653 | (t_method)metro_free, sizeof(t_metro), 0, A_DEFFLOAT, 0); | ||
654 | class_addbang(metro_class, metro_bang); | ||
655 | class_addmethod(metro_class, (t_method)metro_stop, gensym("stop"), 0); | ||
656 | class_addmethod(metro_class, (t_method)metro_ft1, gensym("ft1"), | ||
657 | A_FLOAT, 0); | ||
658 | class_addfloat(metro_class, (t_method)metro_float); | ||
659 | } | ||
660 | |||
661 | /* -------------------------- line ------------------------------ */ | ||
662 | static t_class *line_class; | ||
663 | |||
664 | typedef struct _line | ||
665 | { | ||
666 | t_object x_obj; | ||
667 | t_clock *x_clock; | ||
668 | double x_targettime; | ||
669 | t_float x_targetval; | ||
670 | double x_prevtime; | ||
671 | t_float x_setval; | ||
672 | int x_gotinlet; | ||
673 | t_float x_grain; | ||
674 | double x_1overtimediff; | ||
675 | double x_in1val; | ||
676 | } t_line; | ||
677 | |||
678 | static void line_tick(t_line *x) | ||
679 | { | ||
680 | double timenow = clock_getsystime(); | ||
681 | double msectogo = - clock_gettimesince(x->x_targettime); | ||
682 | if (msectogo < 1E-9) | ||
683 | { | ||
684 | outlet_float(x->x_obj.ob_outlet, x->x_targetval); | ||
685 | } | ||
686 | else | ||
687 | { | ||
688 | outlet_float(x->x_obj.ob_outlet, | ||
689 | x->x_setval + x->x_1overtimediff * (timenow - x->x_prevtime) | ||
690 | * (x->x_targetval - x->x_setval)); | ||
691 | clock_delay(x->x_clock, | ||
692 | (x->x_grain > msectogo ? msectogo : x->x_grain)); | ||
693 | } | ||
694 | } | ||
695 | |||
696 | static void line_float(t_line *x, t_float f) | ||
697 | { | ||
698 | double timenow = clock_getsystime(); | ||
699 | if (x->x_gotinlet && x->x_in1val > 0) | ||
700 | { | ||
701 | if (timenow > x->x_targettime) x->x_setval = x->x_targetval; | ||
702 | else x->x_setval = x->x_setval + x->x_1overtimediff * | ||
703 | (timenow - x->x_prevtime) | ||
704 | * (x->x_targetval - x->x_setval); | ||
705 | x->x_prevtime = timenow; | ||
706 | x->x_targettime = clock_getsystimeafter(x->x_in1val); | ||
707 | x->x_targetval = f; | ||
708 | line_tick(x); | ||
709 | x->x_gotinlet = 0; | ||
710 | x->x_1overtimediff = 1./ (x->x_targettime - timenow); | ||
711 | clock_delay(x->x_clock, | ||
712 | (x->x_grain > x->x_in1val ? x->x_in1val : x->x_grain)); | ||
713 | |||
714 | } | ||
715 | else | ||
716 | { | ||
717 | clock_unset(x->x_clock); | ||
718 | x->x_targetval = x->x_setval = f; | ||
719 | outlet_float(x->x_obj.ob_outlet, f); | ||
720 | } | ||
721 | x->x_gotinlet = 0; | ||
722 | } | ||
723 | |||
724 | static void line_ft1(t_line *x, t_floatarg g) | ||
725 | { | ||
726 | x->x_in1val = g; | ||
727 | x->x_gotinlet = 1; | ||
728 | } | ||
729 | |||
730 | static void line_stop(t_line *x) | ||
731 | { | ||
732 | x->x_targetval = x->x_setval; | ||
733 | clock_unset(x->x_clock); | ||
734 | } | ||
735 | |||
736 | static void line_free(t_line *x) | ||
737 | { | ||
738 | clock_free(x->x_clock); | ||
739 | } | ||
740 | |||
741 | static void *line_new(t_floatarg f, t_floatarg grain) | ||
742 | { | ||
743 | t_line *x = (t_line *)pd_new(line_class); | ||
744 | x->x_targetval = x->x_setval = f; | ||
745 | x->x_gotinlet = 0; | ||
746 | x->x_1overtimediff = 1; | ||
747 | x->x_clock = clock_new(x, (t_method)line_tick); | ||
748 | x->x_targettime = x->x_prevtime = clock_getsystime(); | ||
749 | if (grain <= 0) grain = 20; | ||
750 | x->x_grain = grain; | ||
751 | outlet_new(&x->x_obj, gensym("float")); | ||
752 | inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("ft1")); | ||
753 | return (x); | ||
754 | } | ||
755 | |||
756 | static void line_setup(void) | ||
757 | { | ||
758 | line_class = class_new(gensym("line"), (t_newmethod)line_new, | ||
759 | (t_method)line_free, sizeof(t_line), 0, A_DEFFLOAT, A_DEFFLOAT, 0); | ||
760 | class_addmethod(line_class, (t_method)line_ft1, | ||
761 | gensym("ft1"), A_FLOAT, 0); | ||
762 | class_addmethod(line_class, (t_method)line_stop, | ||
763 | gensym("stop"), 0); | ||
764 | class_addfloat(line_class, (t_method)line_float); | ||
765 | } | ||
766 | |||
767 | /* -------------------------- timer ------------------------------ */ | ||
768 | static t_class *timer_class; | ||
769 | |||
770 | typedef struct _timer | ||
771 | { | ||
772 | t_object x_obj; | ||
773 | t_time x_settime; | ||
774 | } t_timer; | ||
775 | |||
776 | static void timer_bang(t_timer *x) | ||
777 | { | ||
778 | x->x_settime = clock_getsystime(); | ||
779 | } | ||
780 | |||
781 | static void timer_bang2(t_timer *x) | ||
782 | { | ||
783 | t_time diff = clock_gettimesince(x->x_settime); | ||
784 | outlet_float(x->x_obj.ob_outlet, diff); | ||
785 | } | ||
786 | |||
787 | static void *timer_new(t_floatarg f) | ||
788 | { | ||
789 | t_timer *x = (t_timer *)pd_new(timer_class); | ||
790 | timer_bang(x); | ||
791 | outlet_new(&x->x_obj, gensym("float")); | ||
792 | inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2")); | ||
793 | return (x); | ||
794 | } | ||
795 | |||
796 | static void timer_setup(void) | ||
797 | { | ||
798 | timer_class = class_new(gensym("timer"), (t_newmethod)timer_new, 0, | ||
799 | sizeof(t_timer), 0, A_DEFFLOAT, 0); | ||
800 | class_addbang(timer_class, timer_bang); | ||
801 | class_addmethod(timer_class, (t_method)timer_bang2, gensym("bang2"), 0); | ||
802 | } | ||
803 | |||
804 | |||
805 | /* -------------------------- pipe -------------------------- */ | ||
806 | |||
807 | static t_class *pipe_class; | ||
808 | |||
809 | typedef struct _hang | ||
810 | { | ||
811 | t_clock *h_clock; | ||
812 | struct _hang *h_next; | ||
813 | struct _pipe *h_owner; | ||
814 | t_gpointer *h_gp; | ||
815 | union word h_vec[1]; /* not the actual number. */ | ||
816 | } t_hang; | ||
817 | |||
818 | typedef struct pipeout | ||
819 | { | ||
820 | t_atom p_atom; | ||
821 | t_outlet *p_outlet; | ||
822 | } t_pipeout; | ||
823 | |||
824 | typedef struct _pipe | ||
825 | { | ||
826 | t_object x_obj; | ||
827 | int x_n; | ||
828 | int x_nptr; | ||
829 | float x_deltime; | ||
830 | t_pipeout *x_vec; | ||
831 | t_gpointer *x_gp; | ||
832 | t_hang *x_hang; | ||
833 | } t_pipe; | ||
834 | |||
835 | static void *pipe_new(t_symbol *s, int argc, t_atom *argv) | ||
836 | { | ||
837 | t_pipe *x = (t_pipe *)pd_new(pipe_class); | ||
838 | t_atom defarg, *ap; | ||
839 | t_pipeout *vec, *vp; | ||
840 | t_gpointer *gp; | ||
841 | int nptr = 0; | ||
842 | int i; | ||
843 | float deltime; | ||
844 | if (argc) | ||
845 | { | ||
846 | if (argv[argc-1].a_type != A_FLOAT) | ||
847 | { | ||
848 | char stupid[80]; | ||
849 | atom_string(&argv[argc-1], stupid, 79); | ||
850 | post("pipe: %s: bad time delay value", stupid); | ||
851 | deltime = 0; | ||
852 | } | ||
853 | else deltime = argv[argc-1].a_w.w_float; | ||
854 | argc--; | ||
855 | } | ||
856 | else deltime = 0; | ||
857 | if (!argc) | ||
858 | { | ||
859 | argv = &defarg; | ||
860 | argc = 1; | ||
861 | SETFLOAT(&defarg, 0); | ||
862 | } | ||
863 | x->x_n = argc; | ||
864 | vec = x->x_vec = (t_pipeout *)getbytes(argc * sizeof(*x->x_vec)); | ||
865 | |||
866 | for (i = argc, ap = argv; i--; ap++) | ||
867 | if (ap->a_type == A_SYMBOL && *ap->a_w.w_symbol->s_name == 'p') | ||
868 | nptr++; | ||
869 | |||
870 | gp = x->x_gp = (t_gpointer *)t_getbytes(nptr * sizeof (*gp)); | ||
871 | x->x_nptr = nptr; | ||
872 | |||
873 | for (i = 0, vp = vec, ap = argv; i < argc; i++, ap++, vp++) | ||
874 | { | ||
875 | if (ap->a_type == A_FLOAT) | ||
876 | { | ||
877 | vp->p_atom = *ap; | ||
878 | vp->p_outlet = outlet_new(&x->x_obj, &s_float); | ||
879 | if (i) floatinlet_new(&x->x_obj, &vp->p_atom.a_w.w_float); | ||
880 | } | ||
881 | else if (ap->a_type == A_SYMBOL) | ||
882 | { | ||
883 | char c = *ap->a_w.w_symbol->s_name; | ||
884 | if (c == 's') | ||
885 | { | ||
886 | SETSYMBOL(&vp->p_atom, &s_symbol); | ||
887 | vp->p_outlet = outlet_new(&x->x_obj, &s_symbol); | ||
888 | if (i) symbolinlet_new(&x->x_obj, &vp->p_atom.a_w.w_symbol); | ||
889 | } | ||
890 | else if (c == 'p') | ||
891 | { | ||
892 | vp->p_atom.a_type = A_POINTER; | ||
893 | vp->p_atom.a_w.w_gpointer = gp; | ||
894 | gpointer_init(gp); | ||
895 | vp->p_outlet = outlet_new(&x->x_obj, &s_pointer); | ||
896 | if (i) pointerinlet_new(&x->x_obj, gp); | ||
897 | gp++; | ||
898 | } | ||
899 | else | ||
900 | { | ||
901 | if (c != 'f') error("pack: %s: bad type", | ||
902 | ap->a_w.w_symbol->s_name); | ||
903 | SETFLOAT(&vp->p_atom, 0); | ||
904 | vp->p_outlet = outlet_new(&x->x_obj, &s_float); | ||
905 | if (i) floatinlet_new(&x->x_obj, &vp->p_atom.a_w.w_float); | ||
906 | } | ||
907 | } | ||
908 | } | ||
909 | floatinlet_new(&x->x_obj, &x->x_deltime); | ||
910 | x->x_hang = 0; | ||
911 | x->x_deltime = deltime; | ||
912 | return (x); | ||
913 | } | ||
914 | |||
915 | static void hang_free(t_hang *h) | ||
916 | { | ||
917 | t_pipe *x = h->h_owner; | ||
918 | t_gpointer *gp; | ||
919 | int i; | ||
920 | for (gp = h->h_gp, i = x->x_nptr; i--; gp++) | ||
921 | gpointer_unset(gp); | ||
922 | freebytes(h->h_gp, x->x_nptr * sizeof(*h->h_gp)); | ||
923 | clock_free(h->h_clock); | ||
924 | freebytes(h, sizeof(*h) + (x->x_n - 1) * sizeof(*h->h_vec)); | ||
925 | } | ||
926 | |||
927 | static void hang_tick(t_hang *h) | ||
928 | { | ||
929 | t_pipe *x = h->h_owner; | ||
930 | t_hang *h2, *h3; | ||
931 | t_pipeout *p; | ||
932 | int i; | ||
933 | union word *w; | ||
934 | if (x->x_hang == h) x->x_hang = h->h_next; | ||
935 | else for (h2 = x->x_hang; h3 = h2->h_next; h2 = h3) | ||
936 | { | ||
937 | if (h3 == h) | ||
938 | { | ||
939 | h2->h_next = h3->h_next; | ||
940 | break; | ||
941 | } | ||
942 | } | ||
943 | for (i = x->x_n, p = x->x_vec + (x->x_n - 1), w = h->h_vec + (x->x_n - 1); | ||
944 | i--; p--, w--) | ||
945 | { | ||
946 | switch (p->p_atom.a_type) | ||
947 | { | ||
948 | case A_FLOAT: outlet_float(p->p_outlet, w->w_float); break; | ||
949 | case A_SYMBOL: outlet_symbol(p->p_outlet, w->w_symbol); break; | ||
950 | case A_POINTER: | ||
951 | if (gpointer_check(w->w_gpointer, 1)) | ||
952 | outlet_pointer(p->p_outlet, w->w_gpointer); | ||
953 | else post("pipe: stale pointer"); | ||
954 | break; | ||
955 | } | ||
956 | } | ||
957 | hang_free(h); | ||
958 | } | ||
959 | |||
960 | static void pipe_list(t_pipe *x, t_symbol *s, int ac, t_atom *av) | ||
961 | { | ||
962 | t_hang *h = (t_hang *) | ||
963 | getbytes(sizeof(*h) + (x->x_n - 1) * sizeof(*h->h_vec)); | ||
964 | t_gpointer *gp, *gp2; | ||
965 | t_pipeout *p; | ||
966 | int i, n = x->x_n; | ||
967 | t_atom *ap; | ||
968 | t_word *w; | ||
969 | h->h_gp = (t_gpointer *)getbytes(x->x_nptr * sizeof(t_gpointer)); | ||
970 | if (ac > n) ac = n; | ||
971 | for (i = 0, gp = x->x_gp, p = x->x_vec, ap = av; i < ac; | ||
972 | i++, p++, ap++) | ||
973 | { | ||
974 | switch (p->p_atom.a_type) | ||
975 | { | ||
976 | case A_FLOAT: p->p_atom.a_w.w_float = atom_getfloat(ap); break; | ||
977 | case A_SYMBOL: p->p_atom.a_w.w_symbol = atom_getsymbol(ap); break; | ||
978 | case A_POINTER: | ||
979 | gpointer_unset(gp); | ||
980 | if (ap->a_type != A_POINTER) | ||
981 | post("pipe: bad pointer"); | ||
982 | else | ||
983 | { | ||
984 | *gp = *(ap->a_w.w_gpointer); | ||
985 | if (gp->gp_stub) gp->gp_stub->gs_refcount++; | ||
986 | } | ||
987 | gp++; | ||
988 | } | ||
989 | } | ||
990 | for (i = 0, gp = x->x_gp, gp2 = h->h_gp, p = x->x_vec, w = h->h_vec; | ||
991 | i < n; i++, p++, w++) | ||
992 | { | ||
993 | if (p->p_atom.a_type == A_POINTER) | ||
994 | { | ||
995 | if (gp->gp_stub) gp->gp_stub->gs_refcount++; | ||
996 | w->w_gpointer = gp2; | ||
997 | *gp2++ = *gp++; | ||
998 | } | ||
999 | else *w = p->p_atom.a_w; | ||
1000 | } | ||
1001 | h->h_next = x->x_hang; | ||
1002 | x->x_hang = h; | ||
1003 | h->h_owner = x; | ||
1004 | h->h_clock = clock_new(h, (t_method)hang_tick); | ||
1005 | clock_delay(h->h_clock, (x->x_deltime >= 0 ? x->x_deltime : 0)); | ||
1006 | } | ||
1007 | |||
1008 | static void pipe_flush(t_pipe *x) | ||
1009 | { | ||
1010 | while (x->x_hang) hang_tick(x->x_hang); | ||
1011 | } | ||
1012 | |||
1013 | static void pipe_clear(t_pipe *x) | ||
1014 | { | ||
1015 | t_hang *hang; | ||
1016 | while (hang = x->x_hang) | ||
1017 | { | ||
1018 | x->x_hang = hang->h_next; | ||
1019 | hang_free(hang); | ||
1020 | } | ||
1021 | } | ||
1022 | |||
1023 | static void pipe_setup(void) | ||
1024 | { | ||
1025 | pipe_class = class_new(gensym("pipe"), | ||
1026 | (t_newmethod)pipe_new, (t_method)pipe_clear, | ||
1027 | sizeof(t_pipe), 0, A_GIMME, 0); | ||
1028 | class_addlist(pipe_class, pipe_list); | ||
1029 | class_addmethod(pipe_class, (t_method)pipe_flush, gensym("flush"), 0); | ||
1030 | class_addmethod(pipe_class, (t_method)pipe_clear, gensym("clear"), 0); | ||
1031 | } | ||
1032 | |||
1033 | void x_time_setup(void) | ||
1034 | { | ||
1035 | delay_setup(); | ||
1036 | metro_setup(); | ||
1037 | line_setup(); | ||
1038 | timer_setup(); | ||
1039 | pipe_setup(); | ||
1040 | } | ||