diff --git a/pd/src/g_clone.c b/pd/src/g_clone.c index bb85141a4dd698c36e8d4c2d92628bb82db4d554..2529161e6de5da95ad0291e413b39d86a16018be 100644 --- a/pd/src/g_clone.c +++ b/pd/src/g_clone.c @@ -144,6 +144,14 @@ static void clone_in_vis(t_in *x, t_floatarg fn, t_floatarg vis) canvas_vis(x->i_owner->x_vec[n].c_gl, (vis != 0)); } +static void clone_in_fwd(t_in *x, t_symbol *s, int argc, t_atom *argv) +{ + if(s != gensym("fwd")) + typedmess(&x->i_pd, s, argc, argv); + else + pd_error(x->i_owner, "clone-inlet: no method for 'fwd'"); +} + static void clone_out_anything(t_out *x, t_symbol *s, int argc, t_atom *argv) { t_atom *outv; @@ -405,7 +413,8 @@ static void *clone_new(t_symbol *s, int argc, t_atom *argv) obj_issignalinlet(&x->x_vec[0].c_gl->gl_obj, i); x->x_invec[i].i_n = i; if (x->x_invec[i].i_signal) - signalinlet_new(&x->x_obj, 0); + inlet_new(&x->x_obj, &x->x_invec[i].i_pd, + &s_signal, &s_signal); else inlet_new(&x->x_obj, &x->x_invec[i].i_pd, 0, 0); } x->x_nout = obj_noutlets(&x->x_vec[0].c_gl->gl_obj); @@ -458,6 +467,8 @@ void clone_setup(void) A_GIMME, 0); class_addmethod(clone_in_class, (t_method)clone_in_vis, gensym("vis"), A_FLOAT, A_FLOAT, 0); + class_addmethod(clone_in_class, (t_method)clone_in_fwd, gensym("fwd"), + A_GIMME, 0); class_addlist(clone_in_class, (t_method)clone_in_list); clone_out_class = class_new(gensym("clone-outlet"), 0, 0, diff --git a/pd/src/g_io.c b/pd/src/g_io.c index c7330bf635d50c5c9f7c86743b3a0b8047b80653..eee1af66c3906f59210068faa3140745dab6cfa8 100644 --- a/pd/src/g_io.c +++ b/pd/src/g_io.c @@ -36,8 +36,8 @@ typedef struct _vinlet /* if not reblocking, the next slot communicates the parent's inlet signal from the prolog to the DSP routine: */ t_signal *x_directsignal; - - t_resample x_updown; + t_resample x_updown; + t_outlet *x_fwdout; /* optional outlet for forwarding messages to inlet~ */ } t_vinlet; static void *vinlet_new(t_symbol *s) @@ -116,6 +116,19 @@ t_int *vinlet_perform(t_int *w) return (w+4); } +static void vinlet_fwd(t_vinlet *x, t_symbol *s, int argc, t_atom *argv) +{ + if(x->x_fwdout) /* inlet~ fwd */ + outlet_anything(x->x_fwdout, s, argc, argv); + else if(x->x_buf == 0) /* inlet, need to forward message because we want + it to accept fwd selector */ + outlet_anything(x->x_obj.ob_outlet, s, argc, argv); + else /* inlet~ without fwd */ + pd_error(x->x_canvas, "inlet~: expected 'signal' but got '%s' " + "(Note: [inlet~] does not forward non-signal messages unless " + "argument 'fwd' is defined)", s->s_name); +} + static void vinlet_dsp(t_vinlet *x, t_signal **sp) { t_signal *outsig; @@ -251,8 +264,10 @@ static void *vinlet_newsig(t_symbol *s) x->x_endbuf = x->x_buf = (t_float *)getbytes(0); x->x_bufsize = 0; x->x_directsignal = 0; + x->x_fwdout = 0; outlet_new(&x->x_obj, &s_signal); - + /* this line was in pd vanilla but I don't think it is necessary + inlet_new(&x->x_obj, (t_pd *)x->x_inlet, 0, 0); */ resample_init(&x->x_updown); /* this should be thought over: @@ -265,6 +280,8 @@ static void *vinlet_newsig(t_symbol *s) else if (s == gensym("lin"))x->x_updown.method=2; /* up: linear interpolation */ else x->x_updown.method=0; /* up: zero-padding */ + if (s == gensym("fwd")) /* turn on forwarding */ + x->x_fwdout = outlet_new(&x->x_obj, 0); return (x); } @@ -279,6 +296,8 @@ static void vinlet_setup(void) class_addsymbol(vinlet_class, vinlet_symbol); class_addlist(vinlet_class, vinlet_list); class_addanything(vinlet_class, vinlet_anything); + class_addmethod(vinlet_class,(t_method)vinlet_fwd, gensym("fwd"), + A_GIMME, 0); class_addmethod(vinlet_class, (t_method)vinlet_dsp, gensym("dsp"), A_CANT, 0); class_sethelpsymbol(vinlet_class, gensym("pd")); diff --git a/pd/src/m_class.c b/pd/src/m_class.c index f59edbb309e92d40448bb10a099be22e96204175..a398ffb15351846dfaa22cc209dd452928a04c4a 100644 --- a/pd/src/m_class.c +++ b/pd/src/m_class.c @@ -1182,3 +1182,37 @@ t_gotfn zgetfn(t_pd *x, t_symbol *s) if (m->me_name == s) return(m->me_fun); return(0); } + +t_gotfn zcheckgetfn(t_pd *x, t_symbol *s, t_atomtype arg1, ...) +{ + t_class *c = *x; + t_methodentry *m; + int i, j; + + /* get arg types */ + va_list ap; + int nargs = 0; + t_atomtype args[MAXPDARG+1], curr = arg1; + va_start(ap, arg1); + while (curr != A_NULL && nargs < MAXPDARG) + { + args[nargs++] = curr; + curr = va_arg(ap, t_atomtype); + } + if (curr != A_NULL) error("zcheckgetfn: only 5 arguments are typecheckable"); + args[nargs] = A_NULL; + va_end(ap); + + for (i = c->c_nmethod, m = c->c_methods; i--; m++) + { + if (m->me_name == s) + { + j = 0; + /* both argtype lists are valid, dont need to check whether j < MAXDPARG */ + while(m->me_arg[j] != A_NULL && args[j] != A_NULL + && m->me_arg[j] == args[j]) j++; + if(m->me_arg[j] == A_NULL && args[j] == A_NULL) return(m->me_fun); + } + } + return(0); +} diff --git a/pd/src/m_obj.c b/pd/src/m_obj.c index ea1dd5dd2b73ddcaee60de608b2dbfe9072998e8..725ecf42514a51b4d7274165ecd502d0611070e1 100644 --- a/pd/src/m_obj.c +++ b/pd/src/m_obj.c @@ -80,6 +80,36 @@ static void inlet_wrong(t_inlet *x, t_symbol *s, int argc, t_atom *argv) x->i_symfrom->s_name, s->s_name, type_hint(s, argc, argv, 1)); } + /* forward a message to an inlet~ object */ +static int inlet_fwd(t_inlet *x, t_symbol *s, int argc, t_atom *argv) +{ + if(x->i_symfrom == &s_signal + && zcheckgetfn(x->i_dest, gensym("fwd"), A_GIMME, A_NULL)) + { + mess3(x->i_dest, gensym("fwd"), s, argc, argv); + return 1; + } + return 0; +} + +static int inlet_fwd_symbol(t_inlet *x, t_symbol *s) +{ + t_atom sym; SETSYMBOL(&sym, s); + return inlet_fwd(x, &s_symbol, 1, &sym); +} + +static int inlet_fwd_blob(t_inlet *x, t_blob *st) +{ + t_atom blob; SETBLOB(&blob, st); + return inlet_fwd(x, &s_blob, 1, &blob); +} + +static int inlet_fwd_pointer(t_inlet *x, t_gpointer *gp) +{ + t_atom ptr; SETPOINTER(&ptr, gp); + return inlet_fwd(x, &s_pointer, 1, &ptr); +} + static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv); /* LATER figure out how to make these efficient: */ @@ -90,7 +120,8 @@ static void inlet_bang(t_inlet *x) else if (!x->i_symfrom) pd_bang(x->i_dest); else if (x->i_symfrom == &s_list) inlet_list(x, &s_bang, 0, 0); - else inlet_wrong(x, &s_bang, 0, 0); + else if (!inlet_fwd(x, &s_bang, 0, 0)) + inlet_wrong(x, &s_bang, 0, 0); } static void inlet_pointer(t_inlet *x, t_gpointer *gp) @@ -104,7 +135,8 @@ static void inlet_pointer(t_inlet *x, t_gpointer *gp) SETPOINTER(&a, gp); inlet_list(x, &s_pointer, 1, &a); } - else inlet_wrong(x, &s_pointer, 0, 0); + else if (!inlet_fwd_pointer(x, gp)) + inlet_wrong(x, &s_pointer, 0, 0); } static void inlet_float(t_inlet *x, t_float f) @@ -129,7 +161,7 @@ static void inlet_symbol(t_inlet *x, t_symbol *s) if (x->i_symfrom == &s_symbol) pd_vmess(x->i_dest, x->i_symto, "s", s); else if (!x->i_symfrom) pd_symbol(x->i_dest, s); - else + else if (!inlet_fwd_symbol(x, s)) { t_atom a; SETSYMBOL(&a, s); @@ -153,7 +185,7 @@ static void inlet_blob(t_inlet *x, t_blob *st) /* MP20061226 blob type */ /*post("inlet_blob calling pd_blob");*/ pd_blob(x->i_dest, st); } - else + else if (!inlet_fwd_blob(x, st)) { /*post("inlet_blob calling inlet_wrong");*/ inlet_wrong(x, &s_blob, 0, 0); @@ -172,7 +204,8 @@ static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv) inlet_float(x, atom_getfloat(argv)); else if (argc==1 && argv->a_type == A_SYMBOL) inlet_symbol(x, atom_getsymbol(argv)); - else inlet_wrong(x, &s_list, 0, 0); + else if (!inlet_fwd(x, &s_list, argc, argv)) + inlet_wrong(x, &s_list, 0, 0); } static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv) @@ -181,7 +214,8 @@ static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv) typedmess(x->i_dest, x->i_symto, argc, argv); else if (!x->i_symfrom) typedmess(x->i_dest, s, argc, argv); - else inlet_wrong(x, s, 0, 0); + else if (!inlet_fwd(x, s, argc, argv)) + inlet_wrong(x, s, 0, 0); } void inlet_free(t_inlet *x) diff --git a/scripts/regression_tests.pd b/scripts/regression_tests.pd index cf661a67804247163d5fe7b551ff45a83d50a0c0..e8f29fc6eca1e8b1f09661edbd81c3bae5c9f5b8 100644 --- a/scripts/regression_tests.pd +++ b/scripts/regression_tests.pd @@ -1,7 +1,7 @@ -#N canvas 243 24 750 572 12; +#N canvas 244 48 750 572 12; #X obj 465 281 r \$0-result; -#X obj 212 239 bng 15 250 50 0 empty empty Run_all 17 7 0 10 #fcfcfc -#000000 #000000; +#X obj 212 239 bng 15 250 50 0 empty empty Run_all 17 7 0 10 -262144 +-1 -1; #X obj 56 25 r init; #X obj 345 191 route dollarzero; #X obj 198 281 rtest msg_dollarzero; @@ -25,7 +25,7 @@ is handy for some binbuf tests.; #X obj 198 659 rtest makefilename_double_percent; #X obj 198 710 rtest makefilename_code_coverage; #N canvas 461 242 450 323 (subpatch) 0; -#X restore 201 2415 pd; +#X restore 201 2555 pd; #X obj 198 761 rtest makefilename_default; #X obj 198 812 rtest makefilename_default_bang; #X obj 198 863 rtest makefilename_float; @@ -62,6 +62,8 @@ is handy for some binbuf tests.; #X obj 198 2196 rtest iemgui_color_symbolargs; #X obj 198 2251 rtest log_right_inlet; #X obj 198 2306 rtest log_base; +#X obj 198 2361 rtest inlet~_no_fwd; +#X obj 198 2416 rtest inlet~_fwd_large_message; #X connect 0 0 27 0; #X connect 1 0 4 0; #X connect 2 0 42 0; @@ -109,3 +111,5 @@ is handy for some binbuf tests.; #X connect 53 0 54 0; #X connect 54 0 55 0; #X connect 55 0 56 0; +#X connect 56 0 57 0; +#X connect 57 0 58 0; diff --git a/scripts/regression_tests/inlet~_fwd_large_message.pd b/scripts/regression_tests/inlet~_fwd_large_message.pd new file mode 100644 index 0000000000000000000000000000000000000000..e8b34272e24cfe8e500167083639d60f52234f55 --- /dev/null +++ b/scripts/regression_tests/inlet~_fwd_large_message.pd @@ -0,0 +1,23 @@ +#N canvas 240 193 835 453 12; +#X obj 57 22 inlet; +#X obj 57 260 outlet; +#X msg 57 51 bang; +#X obj 321 27 array define \$0-big; +#X obj 318 160 array size \$0-big; +#X msg 318 135 5e+06; +#X obj 132 138 array get \$0-big; +#N canvas 0 0 450 300 \$0-fwd-test~ 0; +#X obj 61 40 inlet~ fwd; +#X restore 132 176 pd \$0-fwd-test~; +#X obj 57 79 trigger bang bang bang; +#X obj 57 138 f 1; +#X obj 57 215 list append large messages to [inlet~ fwd] should not +blow the stack; +#X connect 0 0 2 0; +#X connect 2 0 8 0; +#X connect 5 0 4 0; +#X connect 8 0 9 0; +#X connect 8 1 6 0; +#X connect 8 2 5 0; +#X connect 9 0 10 0; +#X connect 10 0 1 0; diff --git a/scripts/regression_tests/inlet~_no_fwd.pd b/scripts/regression_tests/inlet~_no_fwd.pd new file mode 100644 index 0000000000000000000000000000000000000000..2ade5b6fffe6d30d76ea8b7737f2f431d7319cd1 --- /dev/null +++ b/scripts/regression_tests/inlet~_no_fwd.pd @@ -0,0 +1,23 @@ +#N canvas 239 169 507 299 12; +#X obj 57 22 inlet; +#X obj 57 230 outlet; +#N canvas 0 0 450 300 \$0-test~ 0; +#X obj 61 40 inlet~; +#X restore 171 146 pd \$0-test~; +#X obj 132 117 unpost; +#X obj 57 117 list; +#X obj 57 146 list length; +#X obj 57 185 list append non-signal message to inlet~ should trigger +an error; +#X msg 57 51 bang; +#X obj 57 79 trigger bang bang bang; +#X connect 0 0 7 0; +#X connect 3 0 4 1; +#X connect 3 1 2 0; +#X connect 4 0 5 0; +#X connect 5 0 6 0; +#X connect 6 0 1 0; +#X connect 7 0 8 0; +#X connect 8 0 4 0; +#X connect 8 1 3 0; +#X connect 8 2 4 1;