A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 788 lines 21 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/* sig~ and line~ control-to-signal converters; 6 snapshot~ signal-to-control converter. 7*/ 8 9#include "m_pd.h" 10#include "math.h" 11 12/* -------------------------- sig~ ------------------------------ */ 13static t_class *sig_tilde_class; 14 15typedef struct _sig 16{ 17 t_object x_obj; 18 float x_f; 19} t_sig; 20 21static t_int *sig_tilde_perform(t_int *w) 22{ 23 t_float f = *(t_float *)(w[1]); 24 t_float *out = (t_float *)(w[2]); 25 int n = (int)(w[3]); 26 while (n--) 27 *out++ = f; 28 return (w+4); 29} 30 31static t_int *sig_tilde_perf8(t_int *w) 32{ 33 t_float f = *(t_float *)(w[1]); 34 t_float *out = (t_float *)(w[2]); 35 int n = (int)(w[3]); 36 37 for (; n; n -= 8, out += 8) 38 { 39 out[0] = f; 40 out[1] = f; 41 out[2] = f; 42 out[3] = f; 43 out[4] = f; 44 out[5] = f; 45 out[6] = f; 46 out[7] = f; 47 } 48 return (w+4); 49} 50 51void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n) 52{ 53 if (n&7) 54 dsp_add(sig_tilde_perform, 3, in, out, n); 55 else 56 dsp_add(sig_tilde_perf8, 3, in, out, n); 57} 58 59static void sig_tilde_float(t_sig *x, t_float f) 60{ 61 x->x_f = f; 62} 63 64static void sig_tilde_dsp(t_sig *x, t_signal **sp) 65{ 66 dsp_add(sig_tilde_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n); 67} 68 69static void *sig_tilde_new(t_floatarg f) 70{ 71 t_sig *x = (t_sig *)pd_new(sig_tilde_class); 72 x->x_f = f; 73 outlet_new(&x->x_obj, gensym("signal")); 74 return (x); 75} 76 77#ifndef ROCKBOX 78static 79#endif 80void sig_tilde_setup(void) 81{ 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); 86} 87 88 89#ifndef FIXEDPOINT 90 91/* -------------------------- line~ ------------------------------ */ 92static t_class *line_tilde_class; 93 94typedef struct _line 95{ 96 t_object x_obj; 97 float x_target; 98 float x_value; 99 float x_biginc; 100 float x_inc; 101 float x_1overn; 102 float x_dspticktomsec; 103 float x_inletvalue; 104 float x_inletwas; 105 int x_ticksleft; 106 int x_retarget; 107} t_line; 108 109static t_int *line_tilde_perform(t_int *w) 110{ 111 t_line *x = (t_line *)(w[1]); 112 t_float *out = (t_float *)(w[2]); 113 int n = (int)(w[3]); 114 float f = x->x_value; 115 116 if (PD_BIGORSMALL(f)) 117 x->x_value = f = 0; 118 if (x->x_retarget) 119 { 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; 125 x->x_retarget = 0; 126 } 127 if (x->x_ticksleft) 128 { 129 float f = x->x_value; 130 while (n--) *out++ = f, f += x->x_inc; 131 x->x_value += x->x_biginc; 132 x->x_ticksleft--; 133 } 134 else 135 { 136 x->x_value = x->x_target; 137 while (n--) *out++ = x->x_value; 138 } 139 return (w+4); 140} 141 142static void line_tilde_float(t_line *x, t_float f) 143{ 144 if (x->x_inletvalue <= 0) 145 { 146 x->x_target = x->x_value = f; 147 x->x_ticksleft = x->x_retarget = 0; 148 } 149 else 150 { 151 x->x_target = f; 152 x->x_retarget = 1; 153 x->x_inletwas = x->x_inletvalue; 154 x->x_inletvalue = 0; 155 } 156} 157 158static void line_tilde_stop(t_line *x) 159{ 160 x->x_target = x->x_value; 161 x->x_ticksleft = x->x_retarget = 0; 162} 163 164static void line_tilde_dsp(t_line *x, t_signal **sp) 165{ 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); 169} 170 171static void *line_tilde_new(void) 172{ 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; 178 return (x); 179} 180 181static void line_tilde_setup(void) 182{ 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, 187 gensym("dsp"), 0); 188 class_addmethod(line_tilde_class, (t_method)line_tilde_stop, 189 gensym("stop"), 0); 190} 191 192/* -------------------------- vline~ ------------------------------ */ 193static t_class *vline_tilde_class; 194 195typedef struct _vseg 196{ 197 double s_targettime; 198 double s_starttime; 199 float s_target; 200 struct _vseg *s_next; 201} t_vseg; 202 203typedef struct _vline 204{ 205 t_object x_obj; 206 double x_value; 207 double x_inc; 208 double x_referencetime; 209 double x_samppermsec; 210 double x_msecpersamp; 211 double x_targettime; 212 float x_target; 213 float x_inlet1; 214 float x_inlet2; 215 t_vseg *x_list; 216} t_vline; 217 218static t_int *vline_tilde_perform(t_int *w) 219{ 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++) 230 { 231 double timenext = timenow + msecpersamp; 232 checknext: 233 if (s) 234 { 235 /* has starttime elapsed? If so update value and increment */ 236 if (s->s_starttime < timenext) 237 { 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) 242 { 243 f = s->s_target; 244 inc = 0; 245 } 246 else 247 { 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; 252 } 253 x->x_inc = inc; 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)); 258 s = x->x_list; 259 goto checknext; 260 } 261 } 262 if (x->x_targettime <= timenext) 263 f = x->x_target, inc = x->x_inc = 0, x->x_targettime = 1e20; 264 *out++ = f; 265 f = f + inc; 266 timenow = timenext; 267 } 268 x->x_value = f; 269 return (w+4); 270} 271 272static void vline_tilde_stop(t_vline *x) 273{ 274 t_vseg *s1, *s2; 275 for (s1 = x->x_list; s1; s1 = s2) 276 s2 = s1->s_next, t_freebytes(s1, sizeof(*s1)); 277 x->x_list = 0; 278 x->x_inc = 0; 279 x->x_inlet1 = x->x_inlet2 = 0; 280 x->x_target = x->x_value; 281 x->x_targettime = 1e20; 282} 283 284static void vline_tilde_float(t_vline *x, t_float f) 285{ 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)) 292 f = 0; 293 294 /* negative delay input means stop and jump immediately to new value */ 295 if (inlet2 < 0) 296 { 297 x->x_value = f; 298 vline_tilde_stop(x); 299 return; 300 } 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))) 309 { 310 deletefrom = x->x_list; 311 x->x_list = snew; 312 } 313 else 314 { 315 for (s1 = x->x_list; s2 = s1->s_next; s1 = s2) 316 { 317 if (s2->s_starttime > starttime || 318 (s2->s_starttime == starttime && 319 (s2->s_targettime > s2->s_starttime || inlet1 <= 0))) 320 { 321 deletefrom = s2; 322 s1->s_next = snew; 323 goto didit; 324 } 325 } 326 s1->s_next = snew; 327 deletefrom = 0; 328 didit: ; 329 } 330 while (deletefrom) 331 { 332 s1 = deletefrom->s_next; 333 t_freebytes(deletefrom, sizeof(*deletefrom)); 334 deletefrom = s1; 335 } 336 snew->s_next = 0; 337 snew->s_target = f; 338 snew->s_starttime = starttime; 339 snew->s_targettime = starttime + inlet1; 340 x->x_inlet1 = x->x_inlet2 = 0; 341} 342 343static void vline_tilde_dsp(t_vline *x, t_signal **sp) 344{ 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; 348} 349 350static void *vline_tilde_new(void) 351{ 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(); 359 x->x_list = 0; 360 x->x_samppermsec = 0; 361 x->x_targettime = 1e20; 362 return (x); 363} 364 365static void vline_tilde_setup(void) 366{ 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, 371 gensym("dsp"), 0); 372 class_addmethod(vline_tilde_class, (t_method)vline_tilde_stop, 373 gensym("stop"), 0); 374} 375 376/* -------------------------- snapshot~ ------------------------------ */ 377static t_class *snapshot_tilde_class; 378 379typedef struct _snapshot 380{ 381 t_object x_obj; 382 t_sample x_value; 383 float x_f; 384} t_snapshot; 385 386static void *snapshot_tilde_new(void) 387{ 388 t_snapshot *x = (t_snapshot *)pd_new(snapshot_tilde_class); 389 x->x_value = 0; 390 outlet_new(&x->x_obj, &s_float); 391 x->x_f = 0; 392 return (x); 393} 394 395static t_int *snapshot_tilde_perform(t_int *w) 396{ 397 t_float *in = (t_float *)(w[1]); 398 t_float *out = (t_float *)(w[2]); 399 *out = *in; 400 return (w+3); 401} 402 403static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp) 404{ 405 dsp_add(snapshot_tilde_perform, 2, sp[0]->s_vec + (sp[0]->s_n-1), 406 &x->x_value); 407} 408 409static void snapshot_tilde_bang(t_snapshot *x) 410{ 411 outlet_float(x->x_obj.ob_outlet, x->x_value); 412} 413 414static void snapshot_tilde_set(t_snapshot *x, t_floatarg f) 415{ 416 x->x_value = f; 417} 418 419static void snapshot_tilde_setup(void) 420{ 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, 425 gensym("dsp"), 0); 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); 429} 430 431/* -------------------------- vsnapshot~ ------------------------------ */ 432static t_class *vsnapshot_tilde_class; 433 434typedef struct _vsnapshot 435{ 436 t_object x_obj; 437 int x_n; 438 int x_gotone; 439 t_sample *x_vec; 440 float x_f; 441 float x_sampspermsec; 442 double x_time; 443} t_vsnapshot; 444 445static void *vsnapshot_tilde_new(void) 446{ 447 t_vsnapshot *x = (t_vsnapshot *)pd_new(vsnapshot_tilde_class); 448 outlet_new(&x->x_obj, &s_float); 449 x->x_f = 0; 450 x->x_n = 0; 451 x->x_vec = 0; 452 x->x_gotone = 0; 453 return (x); 454} 455 456static t_int *vsnapshot_tilde_perform(t_int *w) 457{ 458 t_float *in = (t_float *)(w[1]); 459 t_vsnapshot *x = (t_vsnapshot *)(w[2]); 460 t_float *out = x->x_vec; 461 int n = x->x_n, i; 462 for (i = 0; i < n; i++) 463 out[i] = in[i]; 464 x->x_time = clock_getlogicaltime(); 465 x->x_gotone = 1; 466 return (w+3); 467} 468 469static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp) 470{ 471 int n = sp[0]->s_n; 472 if (n != x->x_n) 473 { 474 if (x->x_vec) 475 t_freebytes(x->x_vec, x->x_n * sizeof(t_sample)); 476 x->x_vec = (t_sample *)getbytes(n * sizeof(t_sample)); 477 x->x_gotone = 0; 478 x->x_n = n; 479 } 480 x->x_sampspermsec = sp[0]->s_sr / 1000; 481 dsp_add(vsnapshot_tilde_perform, 2, sp[0]->s_vec, x); 482} 483 484static void vsnapshot_tilde_bang(t_vsnapshot *x) 485{ 486 float val; 487 if (x->x_gotone) 488 { 489 int indx = clock_gettimesince(x->x_time) * x->x_sampspermsec; 490 if (indx < 0) 491 indx = 0; 492 else if (indx >= x->x_n) 493 indx = x->x_n - 1; 494 val = x->x_vec[indx]; 495 } 496 else val = 0; 497 outlet_float(x->x_obj.ob_outlet, val); 498} 499 500static void vsnapshot_tilde_ff(t_vsnapshot *x) 501{ 502 if (x->x_vec) 503 t_freebytes(x->x_vec, x->x_n * sizeof(t_sample)); 504} 505 506static void vsnapshot_tilde_setup(void) 507{ 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); 514} 515 516 517/* ---------------- env~ - simple envelope follower. ----------------- */ 518 519#define MAXOVERLAP 10 520#define MAXVSTAKEN 64 521 522typedef struct sigenv 523{ 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 */ 534 float x_f; 535} t_sigenv; 536 537t_class *env_tilde_class; 538static void env_tilde_tick(t_sigenv *x); 539 540static void *env_tilde_new(t_floatarg fnpoints, t_floatarg fperiod) 541{ 542 int npoints = fnpoints; 543 int period = fperiod; 544 t_sigenv *x; 545 float *buf; 546 int i; 547 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)))) 553 { 554 error("env: couldn't allocate buffer"); 555 return (0); 556 } 557 x = (t_sigenv *)pd_new(env_tilde_class); 558 x->x_buf = buf; 559 x->x_npoints = npoints; 560 x->x_phase = 0; 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")); 568 x->x_f = 0; 569 return (x); 570} 571 572static t_int *env_tilde_perform(t_int *w) 573{ 574 t_sigenv *x = (t_sigenv *)(w[1]); 575 t_float *in = (t_float *)(w[2]); 576 int n = (int)(w[3]); 577 int count; 578 float *sump; 579 in += n; 580 for (count = x->x_phase, sump = x->x_sumbuf; 581 count < x->x_npoints; count += x->x_realperiod, sump++) 582 { 583 float *hp = x->x_buf + count; 584 float *fp = in; 585 float sum = *sump; 586 int i; 587 588 for (i = 0; i < n; i++) 589 { 590 fp--; 591 sum += *hp++ * (*fp * *fp); 592 } 593 *sump = sum; 594 } 595 sump[0] = 0; 596 x->x_phase -= n; 597 if (x->x_phase < 0) 598 { 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++) 602 sump[0] = sump[1]; 603 sump[0] = 0; 604 x->x_phase = x->x_realperiod - n; 605 clock_delay(x->x_clock, 0L); 606 } 607 return (w+4); 608} 609 610static void env_tilde_dsp(t_sigenv *x, t_signal **sp) 611{ 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"); 617} 618 619static void env_tilde_tick(t_sigenv *x) /* callback function for the clock */ 620{ 621 outlet_float(x->x_outlet, powtodb(x->x_result)); 622} 623 624static void env_tilde_ff(t_sigenv *x) /* cleanup on free */ 625{ 626 clock_free(x->x_clock); 627 freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float)); 628} 629 630 631void env_tilde_setup(void ) 632{ 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); 637} 638 639/* --------------------- threshold~ ----------------------------- */ 640 641static t_class *threshold_tilde_class; 642 643typedef struct _threshold_tilde 644{ 645 t_object x_obj; 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 */ 657} t_threshold_tilde; 658 659static void threshold_tilde_tick(t_threshold_tilde *x); 660static void threshold_tilde_set(t_threshold_tilde *x, 661 t_floatarg hithresh, t_floatarg hideadtime, 662 t_floatarg lothresh, t_floatarg lodeadtime); 663 664static t_threshold_tilde *threshold_tilde_new(t_floatarg hithresh, 665 t_floatarg hideadtime, t_floatarg lothresh, t_floatarg lodeadtime) 666{ 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.; 676 x->x_f = 0; 677 threshold_tilde_set(x, hithresh, hideadtime, lothresh, lodeadtime); 678 return (x); 679} 680 681 /* "set" message to specify thresholds and dead times */ 682static void threshold_tilde_set(t_threshold_tilde *x, 683 t_floatarg hithresh, t_floatarg hideadtime, 684 t_floatarg lothresh, t_floatarg lodeadtime) 685{ 686 if (lothresh > hithresh) 687 lothresh = hithresh; 688 x->x_hithresh = hithresh; 689 x->x_hideadtime = hideadtime; 690 x->x_lothresh = lothresh; 691 x->x_lodeadtime = lodeadtime; 692} 693 694 /* number in inlet sets state -- note incompatible with JMAX which used 695 "int" message for this, impossible here because of auto signal conversion */ 696static void threshold_tilde_ft1(t_threshold_tilde *x, t_floatarg f) 697{ 698 x->x_state = (f != 0); 699 x->x_deadwait = 0; 700} 701 702static void threshold_tilde_tick(t_threshold_tilde *x) 703{ 704 if (x->x_state) 705 outlet_bang(x->x_outlet1); 706 else outlet_bang(x->x_outlet2); 707} 708 709static t_int *threshold_tilde_perform(t_int *w) 710{ 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; 716 else if (x->x_state) 717 { 718 /* we're high; look for low sample */ 719 for (; n--; in1++) 720 { 721 if (*in1 < x->x_lothresh) 722 { 723 clock_delay(x->x_clock, 0L); 724 x->x_state = 0; 725 x->x_deadwait = x->x_lodeadtime; 726 goto done; 727 } 728 } 729 } 730 else 731 { 732 /* we're low; look for high sample */ 733 for (; n--; in1++) 734 { 735 if (*in1 >= x->x_hithresh) 736 { 737 clock_delay(x->x_clock, 0L); 738 x->x_state = 1; 739 x->x_deadwait = x->x_hideadtime; 740 goto done; 741 } 742 } 743 } 744done: 745 return (w+4); 746} 747 748void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp) 749{ 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); 752} 753 754static void threshold_tilde_ff(t_threshold_tilde *x) 755{ 756 clock_free(x->x_clock); 757} 758 759static void threshold_tilde_setup( void) 760{ 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, 771 gensym("dsp"), 0); 772} 773 774/* ------------------------ global setup routine ------------------------- */ 775 776void d_ctl_setup(void) 777{ 778 sig_tilde_setup(); 779 line_tilde_setup(); 780 vline_tilde_setup(); 781 snapshot_tilde_setup(); 782 vsnapshot_tilde_setup(); 783 env_tilde_setup(); 784 threshold_tilde_setup(); 785} 786 787#endif 788