A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 865 lines 23 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#if 0 6//#ifdef ROCKBOX 7#include "plugin.h" 8#include "../../pdbox.h" 9#endif 10 11#define PD_CLASS_DEF 12#include "m_pd.h" 13#include "m_imp.h" 14#include "s_stuff.h" 15 16#ifdef ROCKBOX 17 18#include "plugin.h" 19#include "../../pdbox.h" 20 21#else /* ROCKBOX */ 22#include <stdlib.h> 23#ifdef UNIX 24#include <unistd.h> 25#endif 26#ifdef MSW 27#include <io.h> 28#endif 29 30#include <stdarg.h> 31#include <string.h> 32#endif /* ROCKBOX */ 33 34static t_symbol *class_loadsym; /* name under which an extern is invoked */ 35static void pd_defaultfloat(t_pd *x, t_float f); 36static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv); 37t_pd pd_objectmaker; /* factory for creating "object" boxes */ 38t_pd pd_canvasmaker; /* factory for creating canvases */ 39 40static t_symbol *class_extern_dir = &s_; 41 42static void pd_defaultanything(t_pd *x, t_symbol *s, int argc, t_atom *argv) 43{ 44#ifdef ROCKBOX 45 (void) argc; 46 (void) argv; 47#endif 48 pd_error(x, "%s: no method for '%s'", (*x)->c_name->s_name, s->s_name); 49} 50 51static void pd_defaultbang(t_pd *x) 52{ 53 if (*(*x)->c_listmethod != pd_defaultlist) 54 (*(*x)->c_listmethod)(x, 0, 0, 0); 55 else (*(*x)->c_anymethod)(x, &s_bang, 0, 0); 56} 57 58static void pd_defaultpointer(t_pd *x, t_gpointer *gp) 59{ 60 if (*(*x)->c_listmethod != pd_defaultlist) 61 { 62 t_atom at; 63 SETPOINTER(&at, gp); 64 (*(*x)->c_listmethod)(x, 0, 1, &at); 65 } 66 else 67 { 68 t_atom at; 69 SETPOINTER(&at, gp); 70 (*(*x)->c_anymethod)(x, &s_pointer, 1, &at); 71 } 72} 73 74static void pd_defaultfloat(t_pd *x, t_float f) 75{ 76 if (*(*x)->c_listmethod != pd_defaultlist) 77 { 78 t_atom at; 79 SETFLOAT(&at, f); 80 (*(*x)->c_listmethod)(x, 0, 1, &at); 81 } 82 else 83 { 84 t_atom at; 85 SETFLOAT(&at, f); 86 (*(*x)->c_anymethod)(x, &s_float, 1, &at); 87 } 88} 89 90static void pd_defaultsymbol(t_pd *x, t_symbol *s) 91{ 92 if (*(*x)->c_listmethod != pd_defaultlist) 93 { 94 t_atom at; 95 SETSYMBOL(&at, s); 96 (*(*x)->c_listmethod)(x, 0, 1, &at); 97 } 98 else 99 { 100 t_atom at; 101 SETSYMBOL(&at, s); 102 (*(*x)->c_anymethod)(x, &s_symbol, 1, &at); 103 } 104} 105 106void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv); 107static void class_nosavefn(t_gobj *z, t_binbuf *b); 108 109 /* handle "list" messages to Pds without explicit list methods defined. */ 110static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv) 111{ 112 /* a list with one element which is a number can be handled by a 113 "float" method if any is defined; same for "symbol", "pointer". */ 114 if (argc == 1) 115 { 116 if (argv->a_type == A_FLOAT && 117 *(*x)->c_floatmethod != pd_defaultfloat) 118 { 119 (*(*x)->c_floatmethod)(x, argv->a_w.w_float); 120 return; 121 } 122 else if (argv->a_type == A_SYMBOL && 123 *(*x)->c_symbolmethod != pd_defaultsymbol) 124 { 125 (*(*x)->c_symbolmethod)(x, argv->a_w.w_symbol); 126 return; 127 } 128 else if (argv->a_type == A_POINTER && 129 *(*x)->c_pointermethod != pd_defaultpointer) 130 { 131 (*(*x)->c_pointermethod)(x, argv->a_w.w_gpointer); 132 return; 133 } 134 } 135 /* Next try for an "anything" method */ 136 if ((*x)->c_anymethod != pd_defaultanything) 137 (*(*x)->c_anymethod)(x, &s_list, argc, argv); 138 139 /* if the object is patchable (i.e., can have proper inlets) 140 send it on to obj_list which will unpack the list into the inlets */ 141 else if ((*x)->c_patchable) 142 obj_list((t_object *)x, s, argc, argv); 143 /* otherwise gove up and complain. */ 144 else pd_defaultanything(x, &s_list, argc, argv); 145} 146 147 /* for now we assume that all "gobjs" are text unless explicitly 148 overridden later by calling class_setbehavior(). I'm not sure 149 how to deal with Pds that aren't gobjs; shouldn't there be a 150 way to check that at run time? Perhaps the presence of a "newmethod" 151 should be our cue, or perhaps the "tiny" flag. */ 152 153 /* another matter. This routine does two unrelated things: it creates 154 a Pd class, but also adds a "new" method to create an instance of it. 155 These are combined for historical reasons and for brevity in writing 156 objects. To avoid adding a "new" method send a null function pointer. 157 To add additional ones, use class_addcreator below. Some "classes", like 158 "select", are actually two classes of the same name, one for the single- 159 argument form, one for the multiple one; see select_setup() to find out 160 how this is handled. */ 161 162extern t_widgetbehavior text_widgetbehavior; 163extern void text_save(t_gobj *z, t_binbuf *b); 164 165t_class *class_new(t_symbol *s, t_newmethod newmethod, t_method freemethod, 166 size_t size, int flags, t_atomtype type1, ...) 167{ 168 va_list ap; 169 t_atomtype vec[MAXPDARG+1], *vp = vec; 170 int count = 0; 171 t_class *c; 172 int typeflag = flags & CLASS_TYPEMASK; 173 if (!typeflag) typeflag = CLASS_PATCHABLE; 174 *vp = type1; 175 176 va_start(ap, type1); 177 while (*vp) 178 { 179 if (count == MAXPDARG) 180 { 181 error("class %s: sorry: only %d creation args allowed", 182 s->s_name, MAXPDARG); 183 break; 184 } 185 vp++; 186 count++; 187 *vp = va_arg(ap, t_atomtype); 188 } 189 va_end(ap); 190 if (pd_objectmaker && newmethod) 191 { 192 /* add a "new" method by the name specified by the object */ 193 class_addmethod(pd_objectmaker, (t_method)newmethod, s, 194 vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]); 195 if (class_loadsym) 196 { 197 /* if we're loading an extern it might have been invoked by a 198 longer file name; in this case, make this an admissible name 199 too. */ 200 char *loadstring = class_loadsym->s_name, 201 l1 = strlen(s->s_name), l2 = strlen(loadstring); 202 if (l2 > l1 && !strcmp(s->s_name, loadstring + (l2 - l1))) 203 class_addmethod(pd_objectmaker, (t_method)newmethod, 204 class_loadsym, 205 vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]); 206 } 207 } 208 c = (t_class *)t_getbytes(sizeof(*c)); 209 c->c_name = c->c_helpname = s; 210 c->c_size = size; 211 c->c_methods = t_getbytes(0); 212 c->c_nmethod = 0; 213 c->c_freemethod = (t_method)freemethod; 214 c->c_bangmethod = pd_defaultbang; 215 c->c_pointermethod = pd_defaultpointer; 216 c->c_floatmethod = pd_defaultfloat; 217 c->c_symbolmethod = pd_defaultsymbol; 218 c->c_listmethod = pd_defaultlist; 219 c->c_anymethod = pd_defaultanything; 220 c->c_wb = (typeflag == CLASS_PATCHABLE ? &text_widgetbehavior : 0); 221 c->c_pwb = 0; 222 c->c_firstin = ((flags & CLASS_NOINLET) == 0); 223 c->c_patchable = (typeflag == CLASS_PATCHABLE); 224 c->c_gobj = (typeflag >= CLASS_GOBJ); 225 c->c_drawcommand = 0; 226 c->c_floatsignalin = 0; 227 c->c_externdir = class_extern_dir; 228 c->c_savefn = (typeflag == CLASS_PATCHABLE ? text_save : class_nosavefn); 229#if 0 230 post("class: %s", c->c_name->s_name); 231#endif 232 return (c); 233} 234 235 /* add a creation method, which is a function that returns a Pd object 236 suitable for putting in an object box. We presume you've got a class it 237 can belong to, but this won't be used until the newmethod is actually 238 called back (and the new method explicitly takes care of this.) */ 239 240void class_addcreator(t_newmethod newmethod, t_symbol *s, 241 t_atomtype type1, ...) 242{ 243 va_list ap; 244 t_atomtype vec[MAXPDARG+1], *vp = vec; 245 int count = 0; 246 *vp = type1; 247 248 va_start(ap, type1); 249 while (*vp) 250 { 251 if (count == MAXPDARG) 252 { 253 error("class %s: sorry: only %d creation args allowed", 254 s->s_name, MAXPDARG); 255 break; 256 } 257 vp++; 258 count++; 259 *vp = va_arg(ap, t_atomtype); 260 } 261 va_end(ap); 262 class_addmethod(pd_objectmaker, (t_method)newmethod, s, 263 vec[0], vec[1], vec[2], vec[3], vec[4], vec[5]); 264} 265 266void class_addmethod(t_class *c, t_method fn, t_symbol *sel, 267 t_atomtype arg1, ...) 268{ 269 va_list ap; 270 t_methodentry *m; 271 t_atomtype argtype = arg1; 272 int nargs; 273 274 va_start(ap, arg1); 275 /* "signal" method specifies that we take audio signals but 276 that we don't want automatic float to signal conversion. This 277 is obsolete; you should now use the CLASS_MAINSIGNALIN macro. */ 278 if (sel == &s_signal) 279 { 280 if (c->c_floatsignalin) 281 post("warning: signal method overrides class_mainsignalin"); 282 c->c_floatsignalin = -1; 283 } 284 /* check for special cases. "Pointer" is missing here so that 285 pd_objectmaker's pointer method can be typechecked differently. */ 286 if (sel == &s_bang) 287 { 288 if (argtype) goto phooey; 289 class_addbang(c, fn); 290 } 291 else if (sel == &s_float) 292 { 293 if (argtype != A_FLOAT || va_arg(ap, t_atomtype)) goto phooey; 294 class_doaddfloat(c, fn); 295 } 296 else if (sel == &s_symbol) 297 { 298 if (argtype != A_SYMBOL || va_arg(ap, t_atomtype)) goto phooey; 299 class_addsymbol(c, fn); 300 } 301 else if (sel == &s_list) 302 { 303 if (argtype != A_GIMME) goto phooey; 304 class_addlist(c, fn); 305 } 306 else if (sel == &s_anything) 307 { 308 if (argtype != A_GIMME) goto phooey; 309 class_addanything(c, fn); 310 } 311 else 312 { 313 c->c_methods = t_resizebytes(c->c_methods, 314 c->c_nmethod * sizeof(*c->c_methods), 315 (c->c_nmethod + 1) * sizeof(*c->c_methods)); 316 m = c->c_methods + c->c_nmethod; 317 c->c_nmethod++; 318 m->me_name = sel; 319 m->me_fun = (t_gotfn)fn; 320 nargs = 0; 321 while (argtype != A_NULL && nargs < MAXPDARG) 322 { 323 m->me_arg[nargs++] = argtype; 324 argtype = va_arg(ap, t_atomtype); 325 } 326 if (argtype != A_NULL) 327 error("%s_%s: only 5 arguments are typecheckable; use A_GIMME", 328 c->c_name->s_name, sel->s_name); 329 va_end(ap); 330 m->me_arg[nargs] = A_NULL; 331 } 332 return; 333phooey: 334 bug("class_addmethod: %s_%s: bad argument types\n", 335 c->c_name->s_name, sel->s_name); 336} 337 338 /* Instead of these, see the "class_addfloat", etc., macros in m_pd.h */ 339void class_addbang(t_class *c, t_method fn) 340{ 341 c->c_bangmethod = (t_bangmethod)fn; 342} 343 344void class_addpointer(t_class *c, t_method fn) 345{ 346 c->c_pointermethod = (t_pointermethod)fn; 347} 348 349void class_doaddfloat(t_class *c, t_method fn) 350{ 351 c->c_floatmethod = (t_floatmethod)fn; 352} 353 354void class_addsymbol(t_class *c, t_method fn) 355{ 356 c->c_symbolmethod = (t_symbolmethod)fn; 357} 358 359void class_addlist(t_class *c, t_method fn) 360{ 361 c->c_listmethod = (t_listmethod)fn; 362} 363 364void class_addanything(t_class *c, t_method fn) 365{ 366 c->c_anymethod = (t_anymethod)fn; 367} 368 369void class_setwidget(t_class *c, t_widgetbehavior *w) 370{ 371 c->c_wb = w; 372} 373 374void class_setparentwidget(t_class *c, t_parentwidgetbehavior *pw) 375{ 376 c->c_pwb = pw; 377} 378 379char *class_getname(t_class *c) 380{ 381 return (c->c_name->s_name); 382} 383 384char *class_gethelpname(t_class *c) 385{ 386 return (c->c_helpname->s_name); 387} 388 389void class_sethelpsymbol(t_class *c, t_symbol *s) 390{ 391 c->c_helpname = s; 392} 393 394t_parentwidgetbehavior *pd_getparentwidget(t_pd *x) 395{ 396 return ((*x)->c_pwb); 397} 398 399void class_setdrawcommand(t_class *c) 400{ 401 c->c_drawcommand = 1; 402} 403 404int class_isdrawcommand(t_class *c) 405{ 406 return (c->c_drawcommand); 407} 408 409static void pd_floatforsignal(t_pd *x, t_float f) 410{ 411 int offset = (*x)->c_floatsignalin; 412 if (offset > 0) 413 *(t_sample *)(((char *)x) + offset) = ftofix(f); 414 else 415 pd_error(x, "%s: float unexpected for signal input", 416 (*x)->c_name->s_name); 417} 418 419void class_domainsignalin(t_class *c, int onset) 420{ 421 if (onset <= 0) onset = -1; 422 else 423 { 424 if (c->c_floatmethod != pd_defaultfloat) 425 post("warning: %s: float method overwritten", c->c_name->s_name); 426 c->c_floatmethod = (t_floatmethod)pd_floatforsignal; 427 } 428 c->c_floatsignalin = onset; 429} 430 431void class_set_extern_dir(t_symbol *s) 432{ 433 class_extern_dir = s; 434} 435 436char *class_gethelpdir(t_class *c) 437{ 438 return (c->c_externdir->s_name); 439} 440 441static void class_nosavefn(t_gobj *z, t_binbuf *b) 442{ 443#ifdef ROCKBOX 444 (void) z; 445 (void) b; 446#endif 447 bug("save function called but not defined"); 448} 449 450void class_setsavefn(t_class *c, t_savefn f) 451{ 452 c->c_savefn = f; 453} 454 455t_savefn class_getsavefn(t_class *c) 456{ 457 return (c->c_savefn); 458} 459 460void class_setpropertiesfn(t_class *c, t_propertiesfn f) 461{ 462 c->c_propertiesfn = f; 463} 464 465t_propertiesfn class_getpropertiesfn(t_class *c) 466{ 467 return (c->c_propertiesfn); 468} 469 470/* ---------------- the symbol table ------------------------ */ 471 472#define HASHSIZE 1024 473 474static t_symbol *symhash[HASHSIZE]; 475 476t_symbol *dogensym(char *s, t_symbol *oldsym) 477{ 478 t_symbol **sym1, *sym2; 479 unsigned int hash1 = 0, hash2 = 0; 480 int length = 0; 481 char *s2 = s; 482 while (*s2) 483 { 484 hash1 += *s2; 485 hash2 += hash1; 486 length++; 487 s2++; 488 } 489 sym1 = symhash + (hash2 & (HASHSIZE-1)); 490 while ((sym2 = *sym1)) 491 { 492 if (!strcmp(sym2->s_name, s)) return(sym2); 493 sym1 = &sym2->s_next; 494 } 495 if (oldsym) sym2 = oldsym; 496 else 497 { 498 sym2 = (t_symbol *)t_getbytes(sizeof(*sym2)); 499 sym2->s_name = t_getbytes(length+1); 500 sym2->s_next = 0; 501 sym2->s_thing = 0; 502 strcpy(sym2->s_name, s); 503 } 504 *sym1 = sym2; 505 return (sym2); 506} 507 508t_symbol *gensym(char *s) 509{ 510// printf("gensym: %s\n", s); 511#ifdef ROCKBOX 512 if(s == NULL) 513 return dogensym("/", 0); 514 else 515#endif 516 return(dogensym(s, 0)); 517} 518 519#ifndef ROCKBOX 520static 521#endif 522t_symbol *addfileextent(t_symbol *s) 523{ 524 char namebuf[MAXPDSTRING], *str = s->s_name; 525 int ln = strlen(str); 526 if (!strcmp(str + ln - 3, ".pd")) return (s); 527 strcpy(namebuf, str); 528 strcpy(namebuf+ln, ".pd"); 529 return (gensym(namebuf)); 530} 531 532static int tryingalready; 533 534void canvas_popabstraction(t_canvas *x); 535extern t_pd *newest; 536 537t_symbol* pathsearch(t_symbol *s,char* ext); 538int pd_setloadingabstraction(t_symbol *sym); 539 540 /* this routine is called when a new "object" is requested whose class Pd 541 doesn't know. Pd tries to load it as an extern, then as an abstraction. */ 542void new_anything(void *dummy, t_symbol *s, int argc, t_atom *argv) 543{ 544 t_pd *current; 545 t_symbol *dir = canvas_getcurrentdir(); 546 int fd; 547 char dirbuf[MAXPDSTRING], *nameptr; 548 if (tryingalready) return; 549 newest = 0; 550 class_loadsym = s; 551 if (sys_load_lib(dir->s_name, s->s_name)) 552 { 553 tryingalready = 1; 554 typedmess(dummy, s, argc, argv); 555 tryingalready = 0; 556 return; 557 } 558 class_loadsym = 0; 559 current = s__X.s_thing; 560 if ((fd = open_via_path(dir->s_name, s->s_name, ".pd", 561 dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0 || 562 (fd = open_via_path(dir->s_name, s->s_name, ".pat", 563 dirbuf, &nameptr, MAXPDSTRING, 0)) >= 0) 564 { 565 close (fd); 566 if (!pd_setloadingabstraction(s)) 567 { 568 canvas_setargs(argc, argv); /* bug fix by Krzysztof Czaja */ 569 binbuf_evalfile(gensym(nameptr), gensym(dirbuf)); 570 if (s__X.s_thing != current) 571 canvas_popabstraction((t_canvas *)(s__X.s_thing)); 572 canvas_setargs(0, 0); 573 } 574 else error("%s: can't load abstraction within itself\n", s->s_name); 575 } 576 else newest = 0; 577} 578 579t_symbol s_pointer = {"pointer", 0, 0}; 580t_symbol s_float = {"float", 0, 0}; 581t_symbol s_symbol = {"symbol", 0, 0}; 582t_symbol s_bang = {"bang", 0, 0}; 583t_symbol s_list = {"list", 0, 0}; 584t_symbol s_anything = {"anything", 0, 0}; 585t_symbol s_signal = {"signal", 0, 0}; 586t_symbol s__N = {"#N", 0, 0}; 587t_symbol s__X = {"#X", 0, 0}; 588t_symbol s_x = {"x", 0, 0}; 589t_symbol s_y = {"y", 0, 0}; 590t_symbol s_ = {"", 0, 0}; 591 592static t_symbol *symlist[] = { &s_pointer, &s_float, &s_symbol, &s_bang, 593 &s_list, &s_anything, &s_signal, &s__N, &s__X, &s_x, &s_y, &s_}; 594 595void mess_init(void) 596{ 597 t_symbol **sp; 598 int i; 599 600 if (pd_objectmaker) return; 601 for (i = sizeof(symlist)/sizeof(*symlist), sp = symlist; i--; sp++) 602 (void) dogensym((*sp)->s_name, *sp); 603 pd_objectmaker = class_new(gensym("objectmaker"), 0, 0, sizeof(t_pd), 604 CLASS_DEFAULT, A_NULL); 605 pd_canvasmaker = class_new(gensym("classmaker"), 0, 0, sizeof(t_pd), 606 CLASS_DEFAULT, A_NULL); 607 pd_bind(&pd_canvasmaker, &s__N); 608 class_addanything(pd_objectmaker, (t_method)new_anything); 609} 610 611t_pd *newest; 612 613/* This is externally available, but note that it might later disappear; the 614whole "newest" thing is a hack which needs to be redesigned. */ 615t_pd *pd_newest(void) 616{ 617 return (newest); 618} 619 620 /* horribly, we need prototypes for each of the artificial function 621 calls in typedmess(), to keep the compiler quiet. */ 622typedef t_pd *(*t_newgimme)(t_symbol *s, int argc, t_atom *argv); 623typedef void(*t_messgimme)(t_pd *x, t_symbol *s, int argc, t_atom *argv); 624 625typedef t_pd *(*t_fun0)( 626 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5); 627typedef t_pd *(*t_fun1)(t_int i1, 628 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5); 629typedef t_pd *(*t_fun2)(t_int i1, t_int i2, 630 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5); 631typedef t_pd *(*t_fun3)(t_int i1, t_int i2, t_int i3, 632 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5); 633typedef t_pd *(*t_fun4)(t_int i1, t_int i2, t_int i3, t_int i4, 634 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5); 635typedef t_pd *(*t_fun5)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5, 636 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5); 637typedef t_pd *(*t_fun6)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5, t_int i6, 638 t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5); 639 640void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv) 641{ 642#ifndef ROCKBOX 643 t_method *f; 644#endif 645 t_class *c = *x; 646 t_methodentry *m; 647 t_atomtype *wp, wanttype; 648 int i; 649 t_int ai[MAXPDARG+1], *ap = ai; 650 t_floatarg ad[MAXPDARG+1], *dp = ad; 651 int narg = 0; 652 t_pd *bonzo; 653 654 /* check for messages that are handled by fixed slots in the class 655 structure. We don't catch "pointer" though so that sending "pointer" 656 to pd_objectmaker doesn't require that we supply a pointer value. */ 657 if (s == &s_float) 658 { 659 if (!argc) (*c->c_floatmethod)(x, 0.); 660 else if (argv->a_type == A_FLOAT) 661 (*c->c_floatmethod)(x, argv->a_w.w_float); 662 else goto badarg; 663 return; 664 } 665 if (s == &s_bang) 666 { 667 (*c->c_bangmethod)(x); 668 return; 669 } 670 if (s == &s_list) 671 { 672 (*c->c_listmethod)(x, s, argc, argv); 673 return; 674 } 675 if (s == &s_symbol) 676 { 677 if (argc && argv->a_type == A_SYMBOL) 678 (*c->c_symbolmethod)(x, argv->a_w.w_symbol); 679 else 680 (*c->c_symbolmethod)(x, &s_); 681 return; 682 } 683 for (i = c->c_nmethod, m = c->c_methods; i--; m++) 684 if (m->me_name == s) 685 { 686 wp = m->me_arg; 687 if (*wp == A_GIMME) 688 { 689 if (x == &pd_objectmaker) 690 newest = (*((t_newgimme)(m->me_fun)))(s, argc, argv); 691 else (*((t_messgimme)(m->me_fun)))(x, s, argc, argv); 692 return; 693 } 694 695 if (argc > MAXPDARG) argc = MAXPDARG; 696 if (x != &pd_objectmaker) *(ap++) = (t_int)x, narg++; 697 while((wanttype = *wp++)) 698 { 699 switch (wanttype) 700 { 701 case A_POINTER: 702 if (!argc) goto badarg; 703 else 704 { 705 if (argv->a_type == A_POINTER) 706 *ap = (t_int)(argv->a_w.w_gpointer); 707 else goto badarg; 708 argc--; 709 argv++; 710 } 711 narg++; 712 ap++; 713 break; 714 case A_FLOAT: 715 if (!argc) goto badarg; 716 /* Intentional fallthrough */ 717 case A_DEFFLOAT: 718 if (!argc) *dp = 0; 719 else 720 { 721 if (argv->a_type == A_FLOAT) 722 *dp = argv->a_w.w_float; 723 else goto badarg; 724 argc--; 725 argv++; 726 } 727 dp++; 728 break; 729 case A_SYMBOL: 730 if (!argc) goto badarg; 731 /* Intentional fallthrough */ 732 case A_DEFSYM: 733 if (!argc) *ap = (t_int)(&s_); 734 else 735 { 736 if (argv->a_type == A_SYMBOL) 737 *ap = (t_int)(argv->a_w.w_symbol); 738 /* if it's an unfilled "dollar" argument it appears 739 as zero here; cheat and bash it to the null 740 symbol. Unfortunately, this lets real zeros 741 pass as symbols too, which seems wrong... */ 742 else if (x == &pd_objectmaker && argv->a_type == A_FLOAT 743 && argv->a_w.w_float == 0) 744 *ap = (t_int)(&s_); 745 else goto badarg; 746 argc--; 747 argv++; 748 } 749 narg++; 750 ap++; 751#ifdef ROCKBOX 752 break; 753 default: 754 break; 755#endif 756 } 757 } 758 switch (narg) 759 { 760 case 0 : bonzo = (*(t_fun0)(m->me_fun)) 761 (ad[0], ad[1], ad[2], ad[3], ad[4]); break; 762 case 1 : bonzo = (*(t_fun1)(m->me_fun)) 763 (ai[0], ad[0], ad[1], ad[2], ad[3], ad[4]); break; 764 case 2 : bonzo = (*(t_fun2)(m->me_fun)) 765 (ai[0], ai[1], ad[0], ad[1], ad[2], ad[3], ad[4]); break; 766 case 3 : bonzo = (*(t_fun3)(m->me_fun)) 767 (ai[0], ai[1], ai[2], ad[0], ad[1], ad[2], ad[3], ad[4]); break; 768 case 4 : bonzo = (*(t_fun4)(m->me_fun)) 769 (ai[0], ai[1], ai[2], ai[3], 770 ad[0], ad[1], ad[2], ad[3], ad[4]); break; 771 case 5 : bonzo = (*(t_fun5)(m->me_fun)) 772 (ai[0], ai[1], ai[2], ai[3], ai[4], 773 ad[0], ad[1], ad[2], ad[3], ad[4]); break; 774 case 6 : bonzo = (*(t_fun6)(m->me_fun)) 775 (ai[0], ai[1], ai[2], ai[3], ai[4], ai[5], 776 ad[0], ad[1], ad[2], ad[3], ad[4]); break; 777 default: bonzo = 0; 778 } 779 if (x == &pd_objectmaker) 780 newest = bonzo; 781 return; 782 } 783 (*c->c_anymethod)(x, s, argc, argv); 784 return; 785badarg: 786 pd_error(x, "Bad arguments for message '%s' to object '%s'", 787 s->s_name, c->c_name->s_name); 788} 789 790void pd_vmess(t_pd *x, t_symbol *sel, char *fmt, ...) 791{ 792 va_list ap; 793 t_atom arg[MAXPDARG], *at =arg; 794 int nargs = 0; 795 char *fp = fmt; 796 797 va_start(ap, fmt); 798 while (1) 799 { 800 if (nargs > MAXPDARG) 801 { 802 pd_error(x, "pd_vmess: only %d allowed", MAXPDARG); 803 break; 804 } 805 switch(*fp++) 806 { 807 case 'f': SETFLOAT(at, va_arg(ap, double)); break; 808 case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break; 809 case 'i': SETFLOAT(at, va_arg(ap, t_int)); break; 810 case 'p': SETPOINTER(at, va_arg(ap, t_gpointer *)); break; 811 default: goto done; 812 } 813 at++; 814 nargs++; 815 } 816done: 817 va_end(ap); 818 typedmess(x, sel, nargs, arg); 819} 820 821void pd_forwardmess(t_pd *x, int argc, t_atom *argv) 822{ 823 if (argc) 824 { 825 t_atomtype t = argv->a_type; 826 if (t == A_SYMBOL) pd_typedmess(x, argv->a_w.w_symbol, argc-1, argv+1); 827 else if (t == A_POINTER) 828 { 829 if (argc == 1) pd_pointer(x, argv->a_w.w_gpointer); 830 else pd_list(x, &s_list, argc, argv); 831 } 832 else if (t == A_FLOAT) 833 { 834 if (argc == 1) pd_float(x, argv->a_w.w_float); 835 else pd_list(x, &s_list, argc, argv); 836 } 837 else bug("pd_forwardmess"); 838 } 839 840} 841 842void nullfn(void) {} 843 844t_gotfn getfn(t_pd *x, t_symbol *s) 845{ 846 t_class *c = *x; 847 t_methodentry *m; 848 int i; 849 850 for (i = c->c_nmethod, m = c->c_methods; i--; m++) 851 if (m->me_name == s) return(m->me_fun); 852 pd_error(x, "%s: no method for message '%s'", c->c_name->s_name, s->s_name); 853 return((t_gotfn)nullfn); 854} 855 856t_gotfn zgetfn(t_pd *x, t_symbol *s) 857{ 858 t_class *c = *x; 859 t_methodentry *m; 860 int i; 861 862 for (i = c->c_nmethod, m = c->c_methods; i--; m++) 863 if (m->me_name == s) return(m->me_fun); 864 return(0); 865}