OSC-address-space.h

Go to the documentation of this file.
00001 /*
00002 Copyright  1998. The Regents of the University of California (Regents). 
00003 All Rights Reserved.
00004 
00005 Written by Matt Wright, The Center for New Music and Audio Technologies,
00006 University of California, Berkeley.
00007 
00008 Permission to use, copy, modify, distribute, and distribute modified versions
00009 of this software and its documentation without fee and without a signed
00010 licensing agreement, is hereby granted, provided that the above copyright
00011 notice, this paragraph and the following two paragraphs appear in all copies,
00012 modifications, and distributions.
00013 
00014 IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
00015 SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
00016 OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
00017 BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00018 
00019 REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
00020 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00021 PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
00022 HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
00023 MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
00024 
00025 The OpenSound Control WWW page is 
00026     http://www.cnmat.berkeley.edu/OpenSoundControl
00027 */
00028 
00029 
00030 /*
00031   OSC-address-space.h
00032   Matt Wright, 11/20/97
00033   Version 2.0 5/28/98
00034 
00035   C interface for registering the nodes in the OSC address space for an
00036   application.
00037 
00038   include OSC-timetag.h before this file
00039 
00040 ****************************** Introduction ******************************
00041 
00042 
00043   The model is based on our original C++ design and consists of two kinds of
00044   objects:
00045 
00046     methods are the leaf nodes of the address space hierarchy.  A complete OSC
00047     address corresponds to a particular method, which has a corresponding
00048     callback procedure that will be invoked to implement commands sent by an
00049     OSC client.
00050 
00051     containers are branch nodes of the address space hierarchy, and contain
00052     methods and other containers.  Each container has a single namespace;
00053     it cannot contain a method and a subcontainer with the same name.
00054 
00055   For example, let's examine the OSC message "/resonators/foo/decay 2.5".  The
00056   address of this message is "/resonators/foo/decay" and the message has a
00057   single argument, 2.5.  We'd say that the object corresponding to the prefix
00058   "/resonators" is a container, and that it contains another container whose
00059   address is "/resonators/foo".  The "/resonators/foo" container has a method
00060   "decay".
00061 
00062   The memory model used by this module is pre-allocation of fixed-size objects
00063   for containers, methods, and other internal objects.  This preallocated
00064   memory is dynamically managed internally by a custom high-performance memory
00065   allocator.  When the preallocated memory runs out, this module calls an
00066   optional realtime memory allocator that you provide.  If your memory allocator
00067   gives this module more memory, it will add it to the pool of objects and
00068   never free the memory.  If your system does not have a realtime memory 
00069   allocator, provide a procedure that always returns 0.
00070 */
00071 
00072 /*************************** Type Definitions  ******************************/
00073 
00074 /* Users of this module don't get to see what's inside these objects */
00075 typedef struct OSCContainerStruct *OSCcontainer;
00076 typedef struct OSCMethodStruct *OSCMethod;
00077 
00078 /* This makes it easy to change the way we represent symbolic names: */
00079 typedef const char *Name;
00080 
00081 
00082 /************************ Initialization and Memory  ************************/
00083 
00084 /* You will fill an OSCAddressSpaceMemoryTuner struct with the parameters that
00085    determine how memory will be allocated.
00086 
00087    initNumContainers is the number of containers that will be allocated at
00088    initialization time.  This should be the maximum number of containers you
00089    ever expect to have in your address space.
00090 
00091    initNumMethods is the number of methods that will be allocated at
00092    initialization time.  If you register the same method callback procedure
00093    multiple times at different places in the address space, each of these
00094    locations counts as a separate method as far as memory allocation is
00095    concerned.
00096 
00097    The MemoryAllocator fields are procedures you will provide that allocate
00098    memory.  Like malloc(), they take the number of bytes as arguments and return
00099    either a pointer to the new memory or 0 for failure.  This memory will never
00100    be freed.
00101 
00102    The InitTimeMemoryAllocator will be called only at initialization time,
00103    i.e., before OSCInitAddressSpace() returns.  If it ever returns 0, that's
00104    a fatal error.
00105 
00106    The RealTimeMemoryAllocator will be called if, while the application is
00107    running, the address space grows larger than can fit in what was allocated
00108    at initialization time.  If the RealTimeMemoryAllocator() returns 0, the
00109    operation attempting to grow the address space will fail.  If your system
00110    does not have real-time memory allocation, RealTimeMemoryAllocator should
00111    be a procedure that always returns 0.
00112 */
00113 
00114 struct OSCAddressSpaceMemoryTuner {
00115     int initNumContainers;
00116     int initNumMethods;
00117     void *(*InitTimeMemoryAllocator)(int numBytes);
00118     void *(*RealTimeMemoryAllocator)(int numBytes);
00119 };
00120 
00121 /* Given an OSCAddressSpaceMemoryTuner, return the number of bytes of
00122    memory that would be allocated if OSCInitAddressSpace() were called
00123    on it. */
00124 int OSCAddressSpaceMemoryThatWouldBeAllocated(struct OSCAddressSpaceMemoryTuner *t);
00125 
00126 
00127 /* Call this before you call anything else.  It returns the container that
00128    corresponds to the address "/" and is the root of the address space tree. 
00129 */
00130 OSCcontainer OSCInitAddressSpace(struct OSCAddressSpaceMemoryTuner *t);
00131 
00132 
00133 /**************************** Containers  ****************************/
00134 
00135 /* Here's how this system deals with the standard OSC queries addressed to
00136    containers.  This module handles the details of listening for these queries
00137    and returning a correctly-formatted answer; all it needs from you is the
00138    actual data that constitute the answers to these queries.
00139 
00140    You pass this data in an OSCContainerQueryResponseInfo structure.  Future versions
00141    of this module may have new kinds of queries that they can deal with, so
00142    the list of fields in this structure may grow.  That's why your code should
00143    call OSCInitContainerQueryResponseInfo() on your struct before putting new values
00144    into it; this procedure will initialize all of the fields to 0, meaning
00145    "don't have that information", which will cause the associated queries to
00146    fail.
00147 
00148    The "null" message, i.e., a message with a trailing slash, requesting the
00149    list of addresses under a given container, is handled automatically.
00150 */
00151 
00152 struct OSCContainerQueryResponseInfoStruct {
00153     char *comment;
00154     /* Other fields may go here */
00155 };
00156 
00157 void OSCInitContainerQueryResponseInfo(struct OSCContainerQueryResponseInfoStruct *i);
00158 
00159 
00160 /* Allocate a new container and initialize it.  Returns 0 if it cannot
00161    allocate a new container, e.g., if you've exceeded the initNumContainers
00162    limit of the OSCAddressSpaceMemoryTuner() and the RealTimeMemoryAllocator()
00163    didn't return any new memory.
00164 
00165    This procedure doesn't make a copy of the name string or any of the
00166    contents of the OSCContainerQueryResponseInfoStruct.  It does copy the fields
00167    of the OSCContainerQueryResponseInfoStruct.
00168 */
00169 OSCcontainer OSCNewContainer(Name name, OSCcontainer parent,
00170                  struct OSCContainerQueryResponseInfoStruct *queryInfo);
00171 
00172 
00173 /* Remove a container from the address space.  This also removes all the
00174    container's methods and recursively removes all sub-containers.  Memory
00175    freed by removing a container is kept in this module's internal pool. 
00176 */
00177 void OSCRemoveContainer(OSCcontainer container);
00178 
00179 
00180 /* Given a pointer to a container, and another name for that container, add or
00181    remove that name as an alias for the container.  Return FALSE for failure. */
00182 Boolean OSCAddContainerAlias(OSCcontainer container, Name otherName);
00183 Boolean OSCRemoveContainerAlias(OSCcontainer container, Name otherName);
00184 
00185 
00186 /* Write the OSC address of the given container into the given string.
00187    Return FALSE if the address won't fit in the string. */
00188 Boolean OSCGetAddressString(char *target, int maxLength, OSCcontainer c);
00189 
00190 
00191 /* Given an address (not a pattern!), return the single OSCcontainer it names,
00192    or 0 if there is no container at that address */
00193 OSCcontainer OSCLookUpContainer(Name address);
00194 
00195 
00196 /**************************** Methods  ****************************/
00197 
00198 /* A methodCallback is a procedure that you write that will be called at the
00199    time that an OSC message is to take effect.  It will be called with 5
00200    arguments:
00201      - A context pointer that was registered with the methodNode
00202        this is a method of.  (Something like the C++ "this" pointer.)
00203      - The number of bytes of argument data
00204      - A pointer to the argument portion of the OSC message
00205      - The time tag at which this message is supposed to take effect.
00206      - A "return address" object you can use to send a message back to the
00207        client that sent this message.  This return channel is guaranteed
00208        to be usable only during the invocation of your method, so your method
00209        must use the return address immediately or ignore it, not store it away
00210        for later use.
00211 */
00212 typedef const struct NetworkReturnAddressStruct *const NetworkReturnAddressPtr;
00213 typedef void (*methodCallback)(void *context, int arglen, const void *args, 
00214                    OSCTimeTag when, NetworkReturnAddressPtr returnAddr);
00215 
00216 
00217 /* A ParamValQuerier is a procedure that the OSC system will call when the
00218    user wants to know the current value of a parameter.  It will be passed the
00219    same context pointer as the associated method.  It should write its return
00220    value in the given buffer in the same format as the associated
00221    methodCallback would expect its "args" argument, and should return the
00222    length of data just like the method would expect in its "arglen" argument.
00223    It doesn't have to worry about the address portion of the OSC message.
00224 */
00225 typedef char OSCData;   /* For pointers to OSC-formatted data */
00226 typedef int (*ParamValQuerier)(OSCData *result, void *context);
00227 
00228 
00229 /* This system deals with other standard per-method queries, such as
00230    documentation, valid parameter types and ranges, units, default values,
00231    etc., pretty much just like per-container queries.
00232 */
00233 
00234 struct OSCMethodQueryResponseInfoStruct {
00235     char *description;
00236     ParamValQuerier pvq;
00237     /* For each argument of the method:
00238     min, max, default, units */
00239 };
00240 
00241 void OSCInitMethodQueryResponseInfo(struct OSCMethodQueryResponseInfoStruct *i);
00242 
00243 
00244 /* Allocate a new method, initialize it, and add it to a container. Returns 0
00245    for failure, e.g., if you've exceeded the initNumMethods limit of the
00246    OSCAddressSpaceMemoryTuner() and the RealTimeMemoryAllocator() didn't return any
00247    new memory.
00248 
00249    This procedure doesn't make a copy of the name string or any of the
00250    contents of the OSCMethodQueryResponseInfoStruct.
00251 */
00252 
00253 OSCMethod OSCNewMethod(Name name, OSCcontainer container, methodCallback meth, 
00254                void *context, struct OSCMethodQueryResponseInfoStruct *queryInfo);
00255 
00256 
00257 
00258 /******************************* Debug  ********************************/
00259 
00260 //#define DEBUG
00261 
00262 #ifdef DEBUG
00263 void OSCPrintWholeAddressSpace(void);
00264 #endif
00265 
00266 
00267 /**************************** Sample Code  *****************************/
00268 
00269 /* Here's a gross approximation of how your application will invoke the
00270    procedures in this module.  It registers an address space with
00271    containers with addresses "/foo", "/foo/foochild", and "/bar",
00272    and gives each of them "play" and "shuddup" messages.
00273 
00274 
00275 #include "OSC-common.h"
00276 #include "OSC-timetag.h"
00277 #include "OSC-address-space.h"
00278 
00279 
00280 typedef struct {
00281     int playing;
00282     int param;
00283     float otherParam;
00284 } Player;
00285 
00286 void PlayCallback(void *context, int arglen, const void *vargs, 
00287           OSCTimeTag when, NetworkReturnAddressPtr ra) {
00288     Player *p = context;
00289     const int *args = vargs;
00290     
00291 
00292     p->playing = 1;
00293     if (arglen >= 4) {
00294     p->param = args[0];
00295     }
00296 }
00297 
00298 void ShuddupCallback(void *context, int arglen, const void *vargs,
00299              OSCTimeTag when, NetworkReturnAddressPtr ra) {
00300     Player *p = context;
00301     const float *args = vargs;
00302     
00303 
00304     p->playing = 0;
00305     if (arglen >= 4) {
00306     p->otherParam = args[0];
00307     }
00308 }
00309 
00310 void *InitTimeMalloc(int numBytes) {
00311     return malloc(numBytes);
00312 }
00313 
00314 void *NoRealTimeMalloc(int numBytes) {
00315     return 0;
00316 }
00317 
00318 main() {
00319     struct OSCAddressSpaceMemoryTuner oasmt;
00320     OSCcontainer topLevelContainer, foo, foochild, bar;
00321     struct OSCContainerQueryResponseInfoStruct ocqris;
00322     struct OSCMethodQueryResponseInfoStruct omqris;
00323 
00324     Player *players;
00325 
00326     players = (Player *) malloc(3 * sizeof(*players));
00327     if (!players) exit(1);
00328 
00329     oasmt.initNumContainers = 10;
00330     oasmt.initNumMethods = 10;
00331     oasmt.InitTimeMemoryAllocator = InitTimeMalloc;
00332     oasmt.RealTimeMemoryAllocator = NoRealTimeMalloc;
00333 
00334     topLevelContainer = OSCInitAddressSpace(&oasmt);
00335 
00336     OSCInitContainerQueryResponseInfo(&ocqris);
00337     ocqris.comment = "Foo for you";
00338     foo = OSCNewContainer("foo", topLevelContainer, &ocqris);
00339 
00340     OSCInitContainerQueryResponseInfo(&ocqris);
00341     ocqris.comment = "Beware the son of foo!";
00342     foochild = OSCNewContainer("foochild", foo, &ocqris);
00343 
00344     OSCInitContainerQueryResponseInfo(&ocqris);
00345     ocqris.comment = "Belly up to the bar";
00346     bar = OSCNewContainer("bar", topLevelContainer, &ocqris);
00347 
00348     if (foo == 0 || foochild == 0 || bar == 0) {
00349     fprintf(stderr, "Problem!\n");
00350     exit(1);
00351     }
00352 
00353     OSCInitMethodQueryResponseInfo(&omqris);
00354     OSCNewMethod("play", foo, PlayCallback, &(players[0]), &omqris);
00355     OSCNewMethod("shuddup", foo, ShuddupCallback, &(players[0]), &omqris);
00356 
00357     OSCNewMethod("play", foochild, PlayCallback, &(players[1]), &omqris);
00358     OSCNewMethod("shuddup", foochild, ShuddupCallback, &(players[1]), &omqris);
00359 
00360     OSCNewMethod("play", bar, PlayCallback, &(players[2]), &omqris);
00361     OSCNewMethod("shuddup", bar, ShuddupCallback, &(players[2]), &omqris);
00362 }
00363 
00364 */
00365          

Generated on Thu Sep 17 23:14:15 2009 for CSL by  doxygen 1.5.8