A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 537 lines 13 kB view raw
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