From f29e5ba61aebdda221b201e35bb47a4a9c885735 Mon Sep 17 00:00:00 2001 From: Martin Peach Date: Wed, 16 Aug 2006 20:22:22 +0000 Subject: Added the net, osc and sqosc~ directories svn path=/trunk/externals/mrpeach/; revision=5629 --- osc/routeOSC.c | 510 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 510 insertions(+) create mode 100755 osc/routeOSC.c (limited to 'osc/routeOSC.c') diff --git a/osc/routeOSC.c b/osc/routeOSC.c new file mode 100755 index 0000000..50c7872 --- /dev/null +++ b/osc/routeOSC.c @@ -0,0 +1,510 @@ +/* routeOSC.c 20060424 by Martin Peach, based on OSCroute and OSC-pattern-match.c. */ +/* 20060425 cleaned up some more */ +/* OSCroute.c header follows: */ +/* +Written by Adrian Freed, The Center for New Music and Audio Technologies, +University of California, Berkeley. Copyright (c) 1992,93,94,95,96,97,98,99,2000,01,02,03,04 +The Regents of the University of California (Regents). + +Permission to use, copy, modify, distribute, and distribute modified versions +of this software and its documentation without fee and without a signed +licensing agreement, is hereby granted, provided that the above copyright +notice, this paragraph and the following two paragraphs appear in all copies, +modifications, and distributions. + +IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING +OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED +HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + + +The OSC webpage is http://cnmat.cnmat.berkeley.edu/OpenSoundControl +*/ + +/* OSC-route.c + Max object for OSC-style dispatching + + To-do: + + Match a pattern against a pattern? + [Done: Only Slash-Star is allowed, see MyPatternMatch.] + Declare outlet types / distinguish leaf nodes from other children + More sophisticated (2-pass?) allmessages scheme + set message? + + + pd + ------------- + -- tweaks for Win32 www.zeggz.com/raf 13-April-2002 + +*/ +/* OSC-pattern-match.c header follows: */ +/* +Copyright © 1998. The Regents of the University of California (Regents). +All Rights Reserved. + +Written by Matt Wright, The Center for New Music and Audio Technologies, +University of California, Berkeley. + +Permission to use, copy, modify, distribute, and distribute modified versions +of this software and its documentation without fee and without a signed +licensing agreement, is hereby granted, provided that the above copyright +notice, this paragraph and the following two paragraphs appear in all copies, +modifications, and distributions. + +IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING +OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED +HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +The OpenSound Control WWW page is + http://www.cnmat.berkeley.edu/OpenSoundControl +*/ + + + +/* + OSC-pattern-match.c + Matt Wright, 3/16/98 + Adapted from oscpattern.c, by Matt Wright and Amar Chaudhury +*/ + +#if HAVE_CONFIG_H +#include +#endif + +/* the required include files */ +#include "m_pd.h" + +#define MAX_NUM 128 // maximum number of paths (prefixes) we can route + +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_routeOSC; + +/* prototypes */ + +#ifdef MSW +__declspec(dllexport) +#endif +void routeOSC_setup(void); +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 char *NextSlashOrNull(char *p); +static void StrCopyUntilSlash(char *target, const char *source); + +/* from + OSC-pattern-match.c +*/ +static const char *theWholePattern; /* Just for warning messages */ +static int MatchBrackets (const char *pattern, const char *test); +static int MatchList (const char *pattern, const char *test); +static int PatternMatch (const char * pattern, const char * test); + +static t_class *routeOSC_class; +t_symbol *ps_list, *ps_complain, *ps_emptySymbol; + +static int MyPatternMatch (const char *pattern, const char *test) +{ + // This allows the special case of "routeOSC /* " to be an outlet that + // matches anything; i.e., it always outputs the input with the first level + // of the address stripped off. + + if (test[0] == '*' && test[1] == '\0') return 1; + else return PatternMatch(pattern, test); +} + +static void routeOSC_free(t_routeOSC *x) +{ +} + +/* initialization routine */ +// setup +#ifdef MSW +__declspec(dllexport) +#endif +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); + 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_sethelpsymbol(routeOSC_class, gensym("routeOSC-help.pd")); + + ps_emptySymbol = gensym(""); + + post("routeOSC object version 1.0 by Martin Peach, based on OSCroute by Matt Wright. pd: jdl Win32 raf."); + post("OSCroute Copyright © 1999 Regents of the Univ. of California. All Rights Reserved."); +} + +/* instance creation routine */ +static void *routeOSC_new(t_symbol *s, int argc, t_atom *argv) +{ + + t_routeOSC *x = (t_routeOSC *)pd_new(routeOSC_class); // get memory for a new object & initialize + int i; + + if (argc > MAX_NUM) + { + post("* routeOSC: too many arguments: %ld (max %ld)", argc, MAX_NUM); + return 0; + } + x->x_num = 0; + for (i = 0; i < argc; ++i) + { + if (argv[i].a_type == A_SYMBOL) + { + 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_num); + } +#if 0 +/* this doesn't make sense to me MP20060425 */ + else if (argv[i].a_w.w_symbol->s_name[0] == '#' && + argv[i].a_w.w_symbol->s_name[1] >= '1' && + argv[i].a_w.w_symbol->s_name[1] <= '9') + { + /* The Max programmer is trying to make a patch that will be + a subpatch with arguments. We have to make an outlet for this + argument. */ + x->x_prefixes[i] = "dummy"; + ++(x->x_num); + } +#endif /* 0 */ + } + else if (argv[i].a_type == A_FLOAT) + { + post("* routeOSC: float arguments are not OK."); + return 0; + } + else + { + post("* routeOSC: unrecognized argument type!"); + return 0; + } + } + /* Have to create the outlets in reverse order */ + /* well, not in pd ? */ + for (i = 0; i <= x->x_num; i++) + { + x->x_outlets[i] = outlet_new(&x->x_obj, &s_list); + } + return (x); +} + +static void routeOSC_set(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv) +{ + int i; + + if (argc > x->x_num) + { + post ("routeOSC: too many paths"); + return; + } + for (i = 0; i < argc; ++i) + { + if (argv[i].a_type != A_SYMBOL) + { + post ("routeOSC: path %d not a symbol", i); + return; + } + if (argv[i].a_w.w_symbol->s_name[0] != '/') + { + post ("routeOSC: path %d doesn't start with /", i); + return; + } + } + for (i = 0; i < argc; ++i) + { + 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; + } + } +} + +static void routeOSC_list(t_routeOSC *x, t_symbol *s, int argc, t_atom *argv) +{ + if (argc > 0 && argv[0].a_type == A_SYMBOL) + { + /* Ignore the fact that this is a "list" */ + routeOSC_doanything(x, argv[0].a_w.w_symbol, argc-1, argv+1); + } + else + { + // post("* OSC-route: invalid list beginning with a number"); + // output on unmatched outlet jdl 20020908 + if (argv[0].a_type == A_FLOAT) + { + outlet_float(x->x_outlets[x->x_num], argv[0].a_w.w_float); + } + else + { + post("* 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; + // post("*** routeOSC_anything(s %s, argc %ld)", s->s_name, (long) argc); + + pattern = s->s_name; + if (pattern[0] != '/') + { + post("* 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; + + nextSlash = NextSlashOrNull(pattern+1); + if (*nextSlash == '\0') + { + /* 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)) + { + ++matchedAnything; + // I hate stupid Max lists with a special first element + if (argc == 0) + { + outlet_bang(x->x_outlets[i]); + } + else if (argv[0].a_type == A_SYMBOL) + { + // Promote the symbol that was argv[0] to the special symbol + outlet_anything(x->x_outlets[i], argv[0].a_w.w_symbol, argc-1, argv+1); + } + else if (argc > 1) + { + // Multiple arguments starting with a number, so naturally we have + // to use a special function to output this "list", since it's what + // Max originally meant by "list". + outlet_list(x->x_outlets[i], 0L, argc, argv); + } + else + { + // There was only one argument, and it was a number, so we output it + // not as a list + if (argv[0].a_type == A_FLOAT) + { + outlet_float(x->x_outlets[i], argv[0].a_w.w_float); + } + else + { + post("* routeOSC: unrecognized atom type!"); + } + } + } + } + } + else + { + /* There's more address after this part, so our output list will begin with + the next slash. */ + 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); + + for (i = 0; i < x->x_num; ++i) + { + if (MyPatternMatch(patternBegin, x->x_prefixes[i]+1)) + { + ++matchedAnything; + if (restOfPattern == 0) restOfPattern = gensym(nextSlash); + outlet_anything(x->x_outlets[i], restOfPattern, argc, argv); + } + } + } + + if (!matchedAnything) + { + // output unmatched data on rightmost outlet a la normal 'route' object, jdl 20020908 + outlet_anything(x->x_outlets[x->x_num], s, argc, argv); + } +} + +static char *NextSlashOrNull(char *p) +{ + while (*p != '/' && *p != '\0') p++; + return p; +} + +static void StrCopyUntilSlash(char *target, const char *source) +{ + while (*source != '/' && *source != '\0') + { + *target = *source; + ++target; + ++source; + } + *target = 0; +} + +/* from + OSC-pattern-match.c + Matt Wright, 3/16/98 + Adapted from oscpattern.c, by Matt Wright and Amar Chaudhury +*/ + +static int PatternMatch (const char * pattern, const char * test) +{ + theWholePattern = pattern; + + if (pattern == 0 || pattern[0] == 0) return test[0] == 0; + + if (test[0] == 0) + { + if (pattern[0] == '*') return PatternMatch (pattern+1, test); + return 0; + } + + switch (pattern[0]) + { + case 0: + return test[0] == 0; + case '?': + return PatternMatch (pattern+1, test+1); + case '*': + if (PatternMatch (pattern+1, test)) return 1; + return PatternMatch (pattern, test+1); + case ']': + case '}': + post("routeOSC: Spurious %c in pattern \".../%s/...\"",pattern[0], theWholePattern); + return 0; + case '[': + return MatchBrackets (pattern,test); + case '{': + return MatchList (pattern,test); + case '\\': + if (pattern[1] == 0) return test[0] == 0; + if (pattern[1] == test[0]) return PatternMatch (pattern+2,test+1); + return 0; + default: + if (pattern[0] == test[0]) return PatternMatch (pattern+1,test+1); + return 0; + } +} + +/* we know that pattern[0] == '[' and test[0] != 0 */ + +static int MatchBrackets (const char *pattern, const char *test) +{ + int result; + int negated = 0; + const char *p = pattern; + + if (pattern[1] == 0) + { + post("routeOSC: Unterminated [ in pattern \".../%s/...\"", theWholePattern); + return 0; + } + if (pattern[1] == '!') + { + negated = 1; + p++; + } + while (*p != ']') + { + if (*p == 0) + { + post("Unterminated [ in pattern \".../%s/...\"", theWholePattern); + return 0; + } + if (p[1] == '-' && p[2] != 0) + { + if (test[0] >= p[0] && test[0] <= p[2]) + { + result = !negated; + goto advance; + } + } + if (p[0] == test[0]) + { + result = !negated; + goto advance; + } + p++; + } + result = negated; +advance: + if (!result) return 0; + while (*p != ']') + { + if (*p == 0) + { + post("Unterminated [ in pattern \".../%s/...\"", theWholePattern); + return 0; + } + p++; + } + return PatternMatch (p+1,test+1); +} + +static int MatchList (const char *pattern, const char *test) +{ + const char *restOfPattern, *tp = test; + + for(restOfPattern = pattern; *restOfPattern != '}'; restOfPattern++) + { + if (*restOfPattern == 0) + { + post("Unterminated { in pattern \".../%s/...\"", theWholePattern); + return 0; + } + } + restOfPattern++; /* skip close curly brace */ + pattern++; /* skip open curly brace */ + while (1) + { + if (*pattern == ',') + { + if (PatternMatch (restOfPattern, tp)) return 1; + tp = test; + ++pattern; + } + else if (*pattern == '}') return PatternMatch (restOfPattern, tp); + else if (*pattern == *tp) + { + ++pattern; + ++tp; + } + else + { + tp = test; + while (*pattern != ',' && *pattern != '}') pattern++; + if (*pattern == ',') pattern++; + } + } +} + +/* end of routeOSC.c */ -- cgit v1.2.1