From 189c0787586602185fea7dcbc3ef37665b75ba45 Mon Sep 17 00:00:00 2001 From: jdl Date: Tue, 6 Aug 2002 12:13:57 +0000 Subject: This commit was generated by cvs2svn to compensate for changes in r75, which included commits to RCS files with non-trunk default branches. svn path=/trunk/externals/OSCx/; revision=76 --- OSC/routeOSC.c | 417 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 417 insertions(+) create mode 100644 OSC/routeOSC.c (limited to 'OSC/routeOSC.c') diff --git a/OSC/routeOSC.c b/OSC/routeOSC.c new file mode 100644 index 0000000..4ff38cb --- /dev/null +++ b/OSC/routeOSC.c @@ -0,0 +1,417 @@ +/* +Copyright (c) 1999, 2000, 20010 The Regents of the University of +California (Regents). +All Rights Reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for educational, research, and not-for-profit purposes, 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. Contact The Office of +Technology Licensing, UC Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley, +CA 94720-1620, (510) 643-7201, for commercial licensing opportunities. + +Written by Matt Wright, The Center for New Music and Audio Technologies, +University of California, Berkeley. + + 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-route.c + Max object for OSC-style dispatching + + To-do: + + Match a pattern against a pattern? + 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 + + + */ + + + +/* the required include files */ +#include "m_pd.h" +#include "OSC-common.h" +#include "OSC-pattern-match.h" + +#ifdef WIN32 + #include + #include +#endif + + +/* structure definition of your object */ +#define MAX_NUM 20 +#define OSC_ROUTE_VERSION "1.05" +/* Version 1.04: Allows #1 thru #9 as typed-in arguments + Version 1.05: Allows "list" messages as well as "message" messages. +*/ + +static t_class *OSCroute_class; + +typedef struct _OSCroute +{ + t_object x_obj; // required header + t_int x_num; // Number of address prefixes we store + t_int x_complainmode; // Do we print a message if no match? + char *x_prefixes[MAX_NUM]; + void *x_outlets[MAX_NUM]; +} t_OSCroute; + +t_symbol *ps_list, *ps_complain, *ps_emptySymbol; + +/* prototypes */ + +void OSCroute_doanything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv); +void OSCroute_anything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv); +void OSCroute_list(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv); +/* //void *OSCroute_new(t_symbol *s, int argc, atom *argv); */ +void *OSCroute_new(t_symbol *s, int argc, t_atom *argv); +void OSCroute_version (t_OSCroute *x); +/* void OSCroute_assist (OSCroute *x, void *box, long msg, long arg, */ +/* char *dstString); */ +void OSCroute_allmessages(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv); + +static char *NextSlashOrNull(char *p); +static void StrCopyUntilSlash(char *target, const char *source); + + +// free +static void OSCroute_free(t_OSCroute *x) +{ + // freebytes(x->x_vec, x->x_nelement * sizeof(*x->x_vec)); +} + +/* initialization routine */ + +// setup +#ifdef WIN32 + OSC_API void OSCroute_setup(void) { +#else + void OSCroute_setup(void) { +#endif + OSCroute_class = class_new(gensym("OSCroute"), (t_newmethod)OSCroute_new, + (t_method)OSCroute_free,sizeof(t_OSCroute), 0, A_GIMME, 0); + class_addlist(OSCroute_class, OSCroute_list); + class_addanything(OSCroute_class, OSCroute_anything); + class_addmethod(OSCroute_class, (t_method)OSCroute_version, gensym("version"), A_NULL, 0, 0); + class_sethelpsymbol(OSCroute_class, gensym("OSC/OSCroute-help.pd")); + + /* + class_addmethod(OSCroute_class, (t_method)OSCroute_connect, + gensym("connect"), A_SYMBOL, A_FLOAT, 0); + class_addmethod(OSCroute_class, (t_method)OSCroute_disconnect, + gensym("disconnect"), 0); + class_addmethod(OSCroute_class, (t_method)OSCroute_send, gensym("send"), + A_GIMME, 0); + */ +/* ps_list = gensym("list"); */ +/* ps_complain = gensym("complain"); */ + ps_emptySymbol = gensym(""); + + post("OSCroute object version " OSC_ROUTE_VERSION " by Matt Wright. pd-fication cxc. Win32 raf."); + post("OSCroute Copyright © 1999 Regents of the University of California. All Rights Reserved."); +} + + + +/* instance creation routine */ + +void *OSCroute_new(t_symbol *s, int argc, t_atom *argv) +{ + //OSCroute *x; + t_OSCroute *x = (t_OSCroute *)pd_new(OSCroute_class); // get memory for a new object & initialize + + //int i, n; + int i; //{{raf}} n not used + + // EnterCallback(); + + if (argc > MAX_NUM) { + post("* OSC-route: too many arguments: %ld (max %ld)", argc, MAX_NUM); + // ExitCallback(); + return 0; + } + + //x = newobject(OSCroute_class); // get memory for a new object & initialize + + x->x_complainmode = 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); + } 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); + } else { + /* Maybe this is an option we support */ + +/* if (argv[i].a_w.w_sym == ps_complain) { */ +/* x->x_complainmode = 1; */ +/* } else { */ +/* post("* OSC-route: Unrecognized argument %s", argv[i].a_w.w_sym->s_name); */ +/* } */ + + } + + // no LONG + +/* } else if (argv[i].a_type == A_FLOAD) { */ +/* // Convert to a numeral. Max ints are -2147483648 to 2147483647 */ +/* char *string = getbytes(12); */ +/* // I can't be bothered to plug this 12 byte memory leak */ +/* if (string == 0) { */ +/* post("* OSC-route: out of memory!"); */ +/* // ExitCallback(); */ +/* return 0; */ +/* } */ +/* sprintf(string, "%d", argv[i].a_w.w_long); */ +/* x->x_prefixes[i] = string; */ +/* ++(x->x_num); */ + + } else if (argv[i].a_type == A_FLOAT) { + post("* OSC-route: float arguments are not OK."); + // ExitCallback(); + return 0; + } else { + post("* OSC-route: unrecognized argument type!"); + // ExitCallback(); + return 0; + } + } + + + /* Have to create the outlets in reverse order */ + /* well, not in pd ? */ + // for (i = x->x_num-1; i >= 0; --i) { + for (i = 0; i <= x->x_num-1; i++) { + // x->x_outlets[i] = listout(x); + x->x_outlets[i] = outlet_new(&x->x_obj, &s_list); + } + + // ExitCallback(); + return (x); +} + + +void OSCroute_version (t_OSCroute *x) { + // EnterCallback(); + post("OSCroute Version " OSC_ROUTE_VERSION + ", by Matt Wright. pd-fication cxc@web.fm\nOSCroute Compiled " __TIME__ " " __DATE__); + // ExitCallback(); +} + +/* I don't know why these aren't defined in some Max #include file. */ +#define ASSIST_INLET 1 +#define ASSIST_OUTLET 2 + +void OSCroute_assist (t_OSCroute *x, void *box, long msg, long arg, + char *dstString) { + // EnterCallback(); + + if (msg==ASSIST_INLET) { + sprintf(dstString, "Incoming OSC messages"); + } else if (msg==ASSIST_OUTLET) { + if (arg < 0 || arg >= x->x_num) { + post("* OSCroute_assist: No outlet corresponds to arg %ld!", arg); + } else { + sprintf(dstString, "subaddress + args for prefix %s", x->x_prefixes[arg]); + } + } else { + post("* OSCroute_assist: unrecognized message %ld", msg); + } + + // ExitCallback(); +} + +void OSCroute_list(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) { + // EnterCallback(); + if (argc > 0 && argv[0].a_type == A_SYMBOL) { + /* Ignore the fact that this is a "list" */ + OSCroute_doanything(x, argv[0].a_w.w_symbol, argc-1, argv+1); + } else { + post("* OSC-route: invalid list beginning with a number"); + } + // ExitCallback(); +} + + +void OSCroute_anything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) { + // EnterCallback(); + OSCroute_doanything(x, s, argc, argv); + // ExitCallback(); +} + + + + +void OSCroute_doanything(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) { + char *pattern, *nextSlash; + int i; + int matchedAnything; + // post("*** OSCroute_anything(s %s, argc %ld)", s->s_name, (long) argc); + + pattern = s->s_name; + if (pattern[0] != '/') { + post("* OSC-route: invalid message pattern %s does not begin with /", s->s_name); + return; + } + + matchedAnything = 0; + + nextSlash = NextSlashOrNull(pattern+1); + if (*nextSlash == '\0') { + /* last level of the address, so we'll output the argument list */ + + +#ifdef NULL_IS_DIFFERENT_FROM_BANG + if (argc==0) { + post("* OSC-route: why are you matching one level pattern %s with no args?", + pattern); + return; + } +#endif + + for (i = 0; i < x->x_num; ++i) { + if (PatternMatch(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_LONG) { */ + +/* outlet_int(x->x_outlets[i], argv[0].a_w.w_long); */ + // } else + if (argv[0].a_type == A_FLOAT) { + + outlet_float(x->x_outlets[i], argv[0].a_w.w_float); + } else { + post("* OSC-route: 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 (PatternMatch(patternBegin, x->x_prefixes[i]+1)) { + ++matchedAnything; + if (restOfPattern == 0) { + restOfPattern = gensym(nextSlash); + } + outlet_anything(x->x_outlets[i], restOfPattern, argc, argv); + } + } + } + + if (x->x_complainmode) { + if (!matchedAnything) { + post("* OSC-route: pattern %s did not match any prefixes", pattern); + } + } +} + +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; +} + +static int MyStrCopy(char *target, const char *source) { + int i = 0; + while (*source != '\0') { + *target = *source; + ++target; + ++source; + ++i; + } + *target = 0; + return i; +} + + + +void OSCroute_allmessages(t_OSCroute *x, t_symbol *s, int argc, t_atom *argv) { + int i; + t_symbol *prefixSymbol = 0; + char prefixBuf[1000]; + char *endOfPrefix; + t_atom a[1]; + + if (argc >= 1 && argv[0].a_type == A_SYMBOL) { + prefixSymbol = argv[0].a_w.w_symbol; + endOfPrefix = prefixBuf + MyStrCopy(prefixBuf, + prefixSymbol->s_name); + } else { + prefixSymbol = ps_emptySymbol; + prefixBuf[0] = '\0'; + endOfPrefix = prefixBuf; + } + + + for (i = 0; i < x->x_num; ++i) { + post("OSC: %s%s", prefixSymbol->s_name, x->x_prefixes[i]); + MyStrCopy(endOfPrefix, x->x_prefixes[i]); + SETSYMBOL(a, gensym(prefixBuf)); + outlet_anything(x->x_outlets[i], s, 1, a); + } +} -- cgit v1.2.1