A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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 ------------------------------ */
10static t_class *delay_class;
11
12typedef struct _delay
13{
14 t_object x_obj;
15 t_clock *x_clock;
16 double x_deltime;
17} t_delay;
18
19static void delay_bang(t_delay *x)
20{
21 clock_delay(x->x_clock, x->x_deltime);
22}
23
24static void delay_stop(t_delay *x)
25{
26 clock_unset(x->x_clock);
27}
28
29static void delay_ft1(t_delay *x, t_floatarg g)
30{
31 if (g < 0) g = 0;
32 x->x_deltime = g;
33}
34
35static void delay_float(t_delay *x, t_float f)
36{
37 delay_ft1(x, f);
38 delay_bang(x);
39}
40
41static void delay_tick(t_delay *x)
42{
43 outlet_bang(x->x_obj.ob_outlet);
44}
45
46static void delay_free(t_delay *x)
47{
48 clock_free(x->x_clock);
49}
50
51static 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
61static 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 ------------------------------ */
74static t_class *metro_class;
75
76typedef 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
84static 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
91static 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
98static void metro_bang(t_metro *x)
99{
100 metro_float(x, 1);
101}
102
103static void metro_stop(t_metro *x)
104{
105 metro_float(x, 0);
106}
107
108static void metro_ft1(t_metro *x, t_floatarg g)
109{
110 if (g < 1) g = 1;
111 x->x_deltime = g;
112}
113
114static void metro_free(t_metro *x)
115{
116 clock_free(x->x_clock);
117}
118
119static 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
130static 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 ------------------------------ */
142static t_class *line_class;
143
144typedef 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
158static 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
176static 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
204static void line_ft1(t_line *x, t_floatarg g)
205{
206 x->x_in1val = g;
207 x->x_gotinlet = 1;
208}
209
210static void line_stop(t_line *x)
211{
212 x->x_targetval = x->x_setval;
213 clock_unset(x->x_clock);
214}
215
216static void line_free(t_line *x)
217{
218 clock_free(x->x_clock);
219}
220
221static 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
236static 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 ------------------------------ */
248static t_class *timer_class;
249
250typedef struct _timer
251{
252 t_object x_obj;
253 t_time x_settime;
254} t_timer;
255
256static void timer_bang(t_timer *x)
257{
258 x->x_settime = clock_getsystime();
259}
260
261static 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
267static void *timer_new(t_floatarg f)
268{
269#ifdef ROCKBOX
270 (void) f;
271#endif
272 t_timer *x = (t_timer *)pd_new(timer_class);
273 timer_bang(x);
274 outlet_new(&x->x_obj, gensym("float"));
275 inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2"));
276 return (x);
277}
278
279static void timer_setup(void)
280{
281 timer_class = class_new(gensym("timer"), (t_newmethod)timer_new, 0,
282 sizeof(t_timer), 0, A_DEFFLOAT, 0);
283 class_addbang(timer_class, timer_bang);
284 class_addmethod(timer_class, (t_method)timer_bang2, gensym("bang2"), 0);
285}
286
287
288/* -------------------------- pipe -------------------------- */
289
290static t_class *pipe_class;
291
292typedef struct _hang
293{
294 t_clock *h_clock;
295 struct _hang *h_next;
296 struct _pipe *h_owner;
297 t_gpointer *h_gp;
298 union word h_vec[1]; /* not the actual number. */
299} t_hang;
300
301typedef struct pipeout
302{
303 t_atom p_atom;
304 t_outlet *p_outlet;
305} t_pipeout;
306
307typedef struct _pipe
308{
309 t_object x_obj;
310 int x_n;
311 int x_nptr;
312 float x_deltime;
313 t_pipeout *x_vec;
314 t_gpointer *x_gp;
315 t_hang *x_hang;
316} t_pipe;
317
318static void *pipe_new(t_symbol *s, int argc, t_atom *argv)
319{
320#ifdef ROCKBOX
321 (void) s;
322#endif
323 t_pipe *x = (t_pipe *)pd_new(pipe_class);
324 t_atom defarg, *ap;
325 t_pipeout *vec, *vp;
326 t_gpointer *gp;
327 int nptr = 0;
328 int i;
329 float deltime;
330 if (argc)
331 {
332 if (argv[argc-1].a_type != A_FLOAT)
333 {
334 char stupid[80];
335 atom_string(&argv[argc-1], stupid, 79);
336 post("pipe: %s: bad time delay value", stupid);
337 deltime = 0;
338 }
339 else deltime = argv[argc-1].a_w.w_float;
340 argc--;
341 }
342 else deltime = 0;
343 if (!argc)
344 {
345 argv = &defarg;
346 argc = 1;
347 SETFLOAT(&defarg, 0);
348 }
349 x->x_n = argc;
350 vec = x->x_vec = (t_pipeout *)getbytes(argc * sizeof(*x->x_vec));
351
352 for (i = argc, ap = argv; i--; ap++)
353 if (ap->a_type == A_SYMBOL && *ap->a_w.w_symbol->s_name == 'p')
354 nptr++;
355
356 gp = x->x_gp = (t_gpointer *)t_getbytes(nptr * sizeof (*gp));
357 x->x_nptr = nptr;
358
359 for (i = 0, vp = vec, ap = argv; i < argc; i++, ap++, vp++)
360 {
361 if (ap->a_type == A_FLOAT)
362 {
363 vp->p_atom = *ap;
364 vp->p_outlet = outlet_new(&x->x_obj, &s_float);
365 if (i) floatinlet_new(&x->x_obj, &vp->p_atom.a_w.w_float);
366 }
367 else if (ap->a_type == A_SYMBOL)
368 {
369 char c = *ap->a_w.w_symbol->s_name;
370 if (c == 's')
371 {
372 SETSYMBOL(&vp->p_atom, &s_symbol);
373 vp->p_outlet = outlet_new(&x->x_obj, &s_symbol);
374 if (i) symbolinlet_new(&x->x_obj, &vp->p_atom.a_w.w_symbol);
375 }
376 else if (c == 'p')
377 {
378 vp->p_atom.a_type = A_POINTER;
379 vp->p_atom.a_w.w_gpointer = gp;
380 gpointer_init(gp);
381 vp->p_outlet = outlet_new(&x->x_obj, &s_pointer);
382 if (i) pointerinlet_new(&x->x_obj, gp);
383 gp++;
384 }
385 else
386 {
387 if (c != 'f') error("pack: %s: bad type",
388 ap->a_w.w_symbol->s_name);
389 SETFLOAT(&vp->p_atom, 0);
390 vp->p_outlet = outlet_new(&x->x_obj, &s_float);
391 if (i) floatinlet_new(&x->x_obj, &vp->p_atom.a_w.w_float);
392 }
393 }
394 }
395 floatinlet_new(&x->x_obj, &x->x_deltime);
396 x->x_hang = 0;
397 x->x_deltime = deltime;
398 return (x);
399}
400
401static void hang_free(t_hang *h)
402{
403 t_pipe *x = h->h_owner;
404 t_gpointer *gp;
405 int i;
406 for (gp = h->h_gp, i = x->x_nptr; i--; gp++)
407 gpointer_unset(gp);
408 freebytes(h->h_gp, x->x_nptr * sizeof(*h->h_gp));
409 clock_free(h->h_clock);
410 freebytes(h, sizeof(*h) + (x->x_n - 1) * sizeof(*h->h_vec));
411}
412
413static void hang_tick(t_hang *h)
414{
415 t_pipe *x = h->h_owner;
416 t_hang *h2, *h3;
417 t_pipeout *p;
418 int i;
419 union word *w;
420 if (x->x_hang == h) x->x_hang = h->h_next;
421 else for (h2 = x->x_hang; (h3 = h2->h_next); h2 = h3)
422 {
423 if (h3 == h)
424 {
425 h2->h_next = h3->h_next;
426 break;
427 }
428 }
429 for (i = x->x_n, p = x->x_vec + (x->x_n - 1), w = h->h_vec + (x->x_n - 1);
430 i--; p--, w--)
431 {
432 switch (p->p_atom.a_type)
433 {
434 case A_FLOAT: outlet_float(p->p_outlet, w->w_float); break;
435 case A_SYMBOL: outlet_symbol(p->p_outlet, w->w_symbol); break;
436 case A_POINTER:
437 if (gpointer_check(w->w_gpointer, 1))
438 outlet_pointer(p->p_outlet, w->w_gpointer);
439 else post("pipe: stale pointer");
440 break;
441#ifdef ROCKBOX
442 default: break;
443#endif
444 }
445 }
446 hang_free(h);
447}
448
449static void pipe_list(t_pipe *x, t_symbol *s, int ac, t_atom *av)
450{
451#ifdef ROCKBOX
452 (void) s;
453#endif
454 t_hang *h = (t_hang *)
455 getbytes(sizeof(*h) + (x->x_n - 1) * sizeof(*h->h_vec));
456 t_gpointer *gp, *gp2;
457 t_pipeout *p;
458 int i, n = x->x_n;
459 t_atom *ap;
460 t_word *w;
461 h->h_gp = (t_gpointer *)getbytes(x->x_nptr * sizeof(t_gpointer));
462 if (ac > n) ac = n;
463 for (i = 0, gp = x->x_gp, p = x->x_vec, ap = av; i < ac;
464 i++, p++, ap++)
465 {
466 switch (p->p_atom.a_type)
467 {
468 case A_FLOAT: p->p_atom.a_w.w_float = atom_getfloat(ap); break;
469 case A_SYMBOL: p->p_atom.a_w.w_symbol = atom_getsymbol(ap); break;
470 case A_POINTER:
471 gpointer_unset(gp);
472 if (ap->a_type != A_POINTER)
473 post("pipe: bad pointer");
474 else
475 {
476 *gp = *(ap->a_w.w_gpointer);
477 if (gp->gp_stub) gp->gp_stub->gs_refcount++;
478 }
479 gp++;
480#ifdef ROCKBOX
481 break;
482 default: break;
483#endif
484 }
485 }
486 for (i = 0, gp = x->x_gp, gp2 = h->h_gp, p = x->x_vec, w = h->h_vec;
487 i < n; i++, p++, w++)
488 {
489 if (p->p_atom.a_type == A_POINTER)
490 {
491 if (gp->gp_stub) gp->gp_stub->gs_refcount++;
492 w->w_gpointer = gp2;
493 *gp2++ = *gp++;
494 }
495 else *w = p->p_atom.a_w;
496 }
497 h->h_next = x->x_hang;
498 x->x_hang = h;
499 h->h_owner = x;
500 h->h_clock = clock_new(h, (t_method)hang_tick);
501 clock_delay(h->h_clock, (x->x_deltime >= 0 ? x->x_deltime : 0));
502}
503
504static void pipe_flush(t_pipe *x)
505{
506 while (x->x_hang) hang_tick(x->x_hang);
507}
508
509static void pipe_clear(t_pipe *x)
510{
511 t_hang *hang;
512 while ((hang = x->x_hang))
513 {
514 x->x_hang = hang->h_next;
515 hang_free(hang);
516 }
517}
518
519static void pipe_setup(void)
520{
521 pipe_class = class_new(gensym("pipe"),
522 (t_newmethod)pipe_new, (t_method)pipe_clear,
523 sizeof(t_pipe), 0, A_GIMME, 0);
524 class_addlist(pipe_class, pipe_list);
525 class_addmethod(pipe_class, (t_method)pipe_flush, gensym("flush"), 0);
526 class_addmethod(pipe_class, (t_method)pipe_clear, gensym("clear"), 0);
527}
528
529void x_time_setup(void)
530{
531 delay_setup();
532 metro_setup();
533 line_setup();
534 timer_setup();
535 pipe_setup();
536}
537