From ddef561c60dac4e9f268e8c43336184fc91ecc27 Mon Sep 17 00:00:00 2001 From: Martin Peach Date: Mon, 17 Jan 2011 20:30:55 +0000 Subject: [routeOSC] can now route addresses deeper than 1 (like /testing/one/two/three). Added a [verbosity( message to print some debug info. Added a [paths( message to print out the currently active addresses to Pd console. Updated the help patch to match. svn path=/trunk/externals/mrpeach/; revision=14748 --- osc/routeOSC-help.pd | 120 +++++++++++++++++++++++++----------------- osc/routeOSC.c | 146 +++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 196 insertions(+), 70 deletions(-) diff --git a/osc/routeOSC-help.pd b/osc/routeOSC-help.pd index 934c667..a1dc13f 100644 --- a/osc/routeOSC-help.pd +++ b/osc/routeOSC-help.pd @@ -1,49 +1,71 @@ -#N canvas 482 458 615 420 12; -#X obj -39 219 cnv 15 200 40 empty empty empty 20 12 0 14 -4034 -66577 -0; -#X obj -96 64 udpreceive 9997; -#X obj 271 84 unpack 0 0 0 0; -#X floatatom 271 115 3 0 0 0 - - -; -#X floatatom 302 115 3 0 0 0 - - -; -#X floatatom 334 115 3 0 0 0 - - -; -#X floatatom 366 115 3 0 0 0 - - -; -#X text 231 114 from; -#X obj -96 94 unpackOSC; -#X obj -8 229 routeOSC /test /west; -#X obj -8 264 print a; -#X obj 60 264 print b; -#X obj 129 264 print c; -#X msg -24 193 set /left; -#X msg -47 170 set /left /right; -#X text -108 16 routeOSC; -#X text -108 34 accepts lists of floats that are interpreted as OSC -packets; -#X text 84 176 set message reassigns outputs; -#X text -106 303 see also:; -#X obj -27 303 packOSC; -#X floatatom -12 114 10 0 0 1 millisecond_delay - -; -#X obj -96 121 pipelist; -#X text 163 228 arguments are OSC addresses to be routed; -#X text 269 294 2008/09/17 Martin Peach; -#X text -108 347 see:; -#X text 39 348 for a way to send OSC over TCP or serial connections. -; -#X obj -73 348 unpackOSCstream; -#X text 104 196 (but new outlets can't be created); -#X obj -130 148 print unpacked; -#X connect 1 0 8 0; -#X connect 1 1 2 0; -#X connect 2 0 3 0; -#X connect 2 1 4 0; -#X connect 2 2 5 0; -#X connect 2 3 6 0; -#X connect 8 0 21 0; -#X connect 8 0 28 0; -#X connect 8 1 20 0; -#X connect 8 1 21 1; -#X connect 9 0 10 0; -#X connect 9 1 11 0; -#X connect 9 2 12 0; -#X connect 13 0 9 0; -#X connect 14 0 9 0; -#X connect 21 0 9 0; +#N canvas 334 350 923 562 12; +#X obj 81 389 cnv 15 200 40 empty empty empty 20 12 0 14 -4034 -66577 +0; +#X obj -76 40 udpreceive 9997; +#X floatatom 91 111 3 0 0 0 - - -; +#X floatatom 118 111 3 0 0 0 - - -; +#X floatatom 145 111 3 0 0 0 - - -; +#X floatatom 172 111 3 0 0 0 - - -; +#X text 51 110 from; +#X obj -76 164 unpackOSC; +#X obj 112 399 routeOSC /test /west; +#X msg 76 343 set /left; +#X msg 53 320 set /left /right; +#X text 324 108 see also:; +#X obj 396 109 packOSC; +#X floatatom 483 184 10 0 0 1 millisecond_delay - -; +#X obj -76 191 pipelist; +#X text 283 398 arguments are OSC addresses to be routed; +#X text -117 517 see:; +#X text 30 518 for a way to send OSC over TCP or serial connections. +; +#X obj -82 518 unpackOSCstream; +#X text 231 341 (but new outlets can't be created); +#X obj -110 218 print unpacked; +#X text 503 476 2011/01/17 Martin Peach; +#X obj 91 87 unpack 0 0 0 0 0; +#X floatatom 200 111 8 0 0 0 - - -; +#X obj 26 64 route received from; +#X floatatom 26 132 5 0 0 0 - - -; +#X text 66 132 bytes; +#X msg 99 366 set /test/one/two/three; +#X msg 27 294 paths; +#X msg 4 271 verbosity \$1; +#X obj 4 253 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1 +; +#X text 22 249 set to 1 for debugging; +#X text 275 365 routeOSC will match deep paths; +#X text 245 40 [routeOSC] parses lists of floats (only integers on +[0..255]) as OSC packets.; +#X text 246 77 Open [packOSC-help] to send packets to this patch.; +#X text -6 186 If the OSC packet has a timetag \, [pipelist] will delay +it until the time occurs; +#X obj 112 480 print match_1; +#X obj 180 457 print match_2; +#X obj 249 434 print no_match; +#X text 177 319 [set( reassigns outputs from left to right; +#X text 81 294 [paths( will print the current OSC addresses to Pd console +; +#X connect 1 0 7 0; +#X connect 1 1 24 0; +#X connect 7 0 14 0; +#X connect 7 0 20 0; +#X connect 7 1 13 0; +#X connect 7 1 14 1; +#X connect 8 0 36 0; +#X connect 8 1 37 0; +#X connect 8 2 38 0; +#X connect 9 0 8 0; +#X connect 10 0 8 0; +#X connect 14 0 8 0; +#X connect 22 0 2 0; +#X connect 22 1 3 0; +#X connect 22 2 4 0; +#X connect 22 3 5 0; +#X connect 22 4 23 0; +#X connect 24 0 25 0; +#X connect 24 1 22 0; +#X connect 27 0 8 0; +#X connect 28 0 8 0; +#X connect 29 0 8 0; +#X connect 30 0 29 0; diff --git a/osc/routeOSC.c b/osc/routeOSC.c index 5f48e4f..7dea8f6 100644 --- a/osc/routeOSC.c +++ b/osc/routeOSC.c @@ -87,22 +87,33 @@ The OpenSound Control WWW page is typedef struct _routeOSC { - t_object x_obj; // required header - t_int x_num; // Number of prefixes we store - char *x_prefixes[MAX_NUM]; - void *x_outlets[MAX_NUM+1]; // one for each prefix plus one for everything else + t_object x_obj; /* required header */ + t_int x_num; /* Number of prefixes we store */ + t_int x_verbosity; /* level of debug output required */ +// char *x_prefixes[MAX_NUM]; /* the OSC addresses to be matched */ +// int x_prefix_depth[MAX_NUM]; /* the number of slashes in each prefix */ +// void *x_outlets[MAX_NUM+1]; /* one for each prefix plus one for everything else */ + char **x_prefixes; /* the OSC addresses to be matched */ + int *x_prefix_depth; /* the number of slashes in each prefix */ + void **x_outlets; /* one for each prefix plus one for everything else */ } t_routeOSC; /* prototypes */ void routeOSC_setup(void); +static void routeOSC_free(t_routeOSC *x); static int MyPatternMatch (const char *pattern, const char *test); static void routeOSC_doanything(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv); static void routeOSC_list(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv); static void *routeOSC_new(t_symbol *s, int argc, t_atom *argv); static void routeOSC_set(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv); +static void routeOSC_paths(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv); +static void routeOSC_verbosity(t_routeOSC *x, t_floatarg v); +static int routeOSC_count_slashes(char *prefix); static char *NextSlashOrNull(char *p); +static char *NthSlashOrNull(char *p, int n); static void StrCopyUntilSlash(char *target, const char *source); +static void StrCopyUntilNthSlash(char *target, const char *source, int n); /* from OSC-pattern-match.c @@ -127,6 +138,9 @@ static int MyPatternMatch (const char *pattern, const char *test) static void routeOSC_free(t_routeOSC *x) { + freebytes(x->x_prefixes, x->x_num*sizeof(char)); /* the OSC addresses to be matched */ + freebytes(x->x_prefix_depth, x->x_num*sizeof(int)); /* the number of slashes in each prefix */ + freebytes(x->x_outlets, x->x_num*sizeof(void *)); /* one for each prefix plus one for everything else */ } /* initialization routine */ @@ -134,10 +148,12 @@ static void routeOSC_free(t_routeOSC *x) void routeOSC_setup(void) { routeOSC_class = class_new(gensym("routeOSC"), (t_newmethod)routeOSC_new, - (t_method)routeOSC_free,sizeof(t_routeOSC), 0, A_GIMME, 0); + (t_method)routeOSC_free, sizeof(t_routeOSC), 0, A_GIMME, 0); class_addlist(routeOSC_class, routeOSC_list); class_addanything(routeOSC_class, routeOSC_doanything); class_addmethod(routeOSC_class, (t_method)routeOSC_set, gensym("set"), A_GIMME, 0); + class_addmethod(routeOSC_class, (t_method)routeOSC_paths, gensym("paths"), A_GIMME, 0); + class_addmethod(routeOSC_class, (t_method)routeOSC_verbosity, gensym("verbosity"), A_DEFFLOAT, 0); ps_emptySymbol = gensym(""); @@ -158,6 +174,11 @@ static void *routeOSC_new(t_symbol *s, int argc, t_atom *argv) return 0; } x->x_num = 0; + + x->x_prefixes = (char **)getzbytes(argc*sizeof(char)); /* the OSC addresses to be matched */ + x->x_prefix_depth = (int *)getzbytes(argc*sizeof(int)); /* the number of slashes in each prefix */ + x->x_outlets = (void **)getzbytes(argc*sizeof(void *)); /* one for each prefix plus one for everything else */ + for (i = 0; i < argc; ++i) { if (argv[i].a_type == A_SYMBOL) @@ -165,6 +186,7 @@ static void *routeOSC_new(t_symbol *s, int argc, t_atom *argv) if (argv[i].a_w.w_symbol->s_name[0] == '/') { /* Now that's a nice prefix */ x->x_prefixes[i] = argv[i].a_w.w_symbol->s_name; + x->x_prefix_depth[i] = routeOSC_count_slashes(x->x_prefixes[i]); ++(x->x_num); } } @@ -185,6 +207,7 @@ static void *routeOSC_new(t_symbol *s, int argc, t_atom *argv) { x->x_outlets[i] = outlet_new(&x->x_obj, &s_list); } + x->x_verbosity = 0; /* quiet by default */ return (x); } @@ -215,16 +238,39 @@ static void routeOSC_set(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv) if (argv[i].a_w.w_symbol->s_name[0] == '/') { /* Now that's a nice prefix */ x->x_prefixes[i] = argv[i].a_w.w_symbol->s_name; + x->x_prefix_depth[i] = routeOSC_count_slashes(x->x_prefixes[i]); } } } +static void routeOSC_paths(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv) +{ /* print out the paths we are matching */ + int i; + + for (i = 0; i < x->x_num; ++i) post("path[%d]: %s (depth %d)", i, x->x_prefixes[i], x->x_prefix_depth[i]); +} + +static void routeOSC_verbosity(t_routeOSC *x, t_floatarg v) +{ + x->x_verbosity = (v == 0)? 0: 1; + if (x->x_verbosity) post("routeOSC_verbosity is %d", x->x_verbosity); +} + +static int routeOSC_count_slashes(char *prefix) +{ /* find the path depth of the prefix by counting the numberof slashes */ + int i = 0; + char *p = prefix; + + while (*p != '\0') if (*p++ == '/') i++; + return i; +} + static void routeOSC_list(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv) { if(argc < 1) { - pd_error(x, "* routeOSC: ignoring empty list..."); - return; + pd_error(x, "* routeOSC: ignoring empty list..."); + return; } if (argv[0].a_type == A_SYMBOL) { @@ -237,39 +283,44 @@ static void routeOSC_list(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv) // output on unmatched outlet jdl 20020908 if (argv[0].a_type == A_FLOAT) { - outlet_float(x->x_outlets[x->x_num], atom_getfloat(argv)); + outlet_float(x->x_outlets[x->x_num], atom_getfloat(argv)); } else { - pd_error(x, "* routeOSC: unrecognized atom type!"); + pd_error(x, "* routeOSC: unrecognized atom type!"); } } } static void routeOSC_doanything(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv) { - char *pattern, *nextSlash; - int i; - int matchedAnything; + char *pattern, *nextSlash; + int i, pattern_depth = 0, matchedAnything = 0; // post("*** routeOSC_anything(s %s, argc %ld)", s->s_name, (long) argc); pattern = s->s_name; + if (x->x_verbosity) post("routeOSC_doanything: pattern is %s", pattern); if (pattern[0] != '/') { pd_error(x, "* routeOSC: invalid message pattern %s does not begin with /", s->s_name); outlet_anything(x->x_outlets[x->x_num], s, argc, argv); return; } - matchedAnything = 0; + pattern_depth = routeOSC_count_slashes(pattern); + if (x->x_verbosity) post("routeOSC_doanything: pattern_depth is %i", pattern_depth); nextSlash = NextSlashOrNull(pattern+1); if (*nextSlash == '\0') - { + { /* pattern_depth == 1 */ /* last level of the address, so we'll output the argument list */ for (i = 0; i < x->x_num; ++i) { - if (MyPatternMatch(pattern+1, x->x_prefixes[i]+1)) + if + ( + (x->x_prefix_depth[i] <= pattern_depth) + && (MyPatternMatch(pattern+1, x->x_prefixes[i]+1)) + ) { ++matchedAnything; // I hate stupid Max lists with a special first element @@ -312,16 +363,27 @@ static void routeOSC_doanything(t_routeOSC *x, t_symbol *s, int argc, t_atom *ar t_symbol *restOfPattern = 0; /* avoid the gensym unless we have to output */ char patternBegin[1000]; - /* Get the first level of the incoming pattern to match against all our prefixes */ - StrCopyUntilSlash(patternBegin, pattern+1); + /* Get the incoming pattern to match against all our prefixes */ for (i = 0; i < x->x_num; ++i) { - if (MyPatternMatch(patternBegin, x->x_prefixes[i]+1)) + restOfPattern = 0; + if (x->x_prefix_depth[i] <= pattern_depth) { - ++matchedAnything; - if (restOfPattern == 0) restOfPattern = gensym(nextSlash); - outlet_anything(x->x_outlets[i], restOfPattern, argc, argv); + StrCopyUntilNthSlash(patternBegin, pattern+1, x->x_prefix_depth[i]); + if (x->x_verbosity) + post("routeOSC_doanything: (%d) patternBegin is %s", i, patternBegin); + if (MyPatternMatch(patternBegin, x->x_prefixes[i]+1)) + { + if (x->x_verbosity) + post("routeOSC_doanything: (%d) matched %s depth %d", i, x->x_prefixes[i], x->x_prefix_depth[i]); + ++matchedAnything; + nextSlash = NthSlashOrNull(pattern+1, x->x_prefix_depth[i]); + if (x->x_verbosity) + post("routeOSC_doanything: (%d) nextSlash %s", i, nextSlash); + if (restOfPattern == 0) restOfPattern = gensym(nextSlash); + outlet_anything(x->x_outlets[i], restOfPattern, argc, argv); + } } } } @@ -339,6 +401,22 @@ static char *NextSlashOrNull(char *p) return p; } +static char *NthSlashOrNull(char *p, int n) +{ + int i; + for (i = 0; i < n; ++i) + { + while (*p != '/') + { + if (*p == '\0') return p; + p++; + } + if (i < n-1) p++; /* skip the slash unless it's the nth slash */ + } + return p; +} + + static void StrCopyUntilSlash(char *target, const char *source) { while (*source != '/' && *source != '\0') @@ -350,6 +428,32 @@ static void StrCopyUntilSlash(char *target, const char *source) *target = 0; } +static void StrCopyUntilNthSlash(char *target, const char *source, int n) +{ /* copy the path up but not including the nth slash */ + int i = n; + + while (i > 0) + { + while (*source != '/') + { + *target = *source; + if (*source == '\0') return; + ++target; + ++source; + } + i--; + /* got a slash. If it's the nth, don't include it */ + if (i == 0) + { + *target = 0; + return; + } + *target = *source; + ++source; + ++target; + } +} + /* from OSC-pattern-match.c Matt Wright, 3/16/98 -- cgit v1.2.1